EN ▾
Get API key

Uncensored API integration guide: register, verify, first call

This guide does one thing: get your first request running in ten minutes. No SDKs, just standard libraries sending HTTP requests, because there is essentially only one POST endpoint. Seeing what the request looks like means you won't panic when switching frameworks. Examples cover Python requests, Java java.net.http, Go net/http, and PHP curl; copy and run them directly.

Updated on

Key points

  • Registration requires only an email and password. New accounts receive $0.50 in trial credit, valid for 7 days, with no payment information required.
  • Base URL is https://api.wushenchaapi.com/v1,模型名固定写 uncensored. Auth header is Authorization: Bearer.
  • Verify key with GET /v1/models, then POST /v1/chat/completions. Troubleshoot these two steps separately for speed.
  • Set timeouts in all four languages, and read error.code, not just the HTTP status code.

Pre-flight checklist

Review this first to avoid going back later.

  • An email address capable of receiving mail, used for registration.
  • Any of the following runtimes on your machine: Python 3, JDK 15 and above (examples use text blocks), Go, or PHP with the curl extension.
  • Confirm you are 18+; the service is for adults only.
  • Know you want plain text chat: there is only one model, no embeddings, images, voice, or fine-tuning.
  • Store your API key in environment variables, not in source code or commits.

Few interface conventions: endpoint https://api.wushenchaapi.com/v1, compatible with OpenAI chat completions. Your existing request bodies should work as-is.

Estimated time: registration takes one minute, environment setup depends on your machine, and the first request itself takes no more than thirty seconds. If you haven't received a result after this time, it is likely a network or key issue; go straight to the troubleshooting list at the end. Follow this order: models, then chat; synchronous first, then streaming; confirm each step before proceeding.

Register and get your key

Open /get-api-key/ and register with your email and password. The key is displayed immediately after registration; copy it down. A few details:

  1. Each account has only one API key.
  2. You can regenerate it, but the old key expires immediately. Deploy the new value before switching in production.
  3. New accounts receive $0.50 in trial credit, valid for 7 days, with no payment information required.
  4. When free trial credit expires or is used up, requests return 402 with error code no_credit. Top up prepaid credit to continue. It is not a subscription; balance never expires.

Set the API key in environment variables: macOS/Linux run export API_KEY=your_key, Windows PowerShell uses $env:API_KEY="your_key". All examples read from API_KEY.

Step 1: Verify connectivity with /v1/models

Don't send chat requests yet. Make a zero-cost GET request to confirm address, network, and API key are correct:

curl https://api.wushenchaapi.com/v1/models \
  -H "Authorization: Bearer $API_KEY"

A 200 response with the model list (only one uncensored) means it works. 401 means invalid or missing API key; timeout means check network/proxy. Separating connectivity from request body issues saves time during integration.

Python: requests

No SDK needed; one requests.post is enough. Note three things: set timeout; check r.ok before accessing choices; on failure, the error body is {"error":{"code":...,"message":...}}.

import os
import requests

url = "https://api.wushenchaapi.com/v1/chat/completions"
headers = {
    "Authorization": "Bearer " + os.environ["API_KEY"],
    "Content-Type": "application/json",
}
payload = {
    "model": "uncensored",
    "messages": [{"role": "user", "content": "用两句话描述一场雨夜里的追逐戏。"}],
    "max_tokens": 300,
}
r = requests.post(url, headers=headers, json=payload, timeout=120)
print(r.status_code)
data = r.json()
if r.ok:
    print(data["choices"][0]["message"]["content"])
    print(data["usage"])
else:
    print(data["error"]["code"], data["error"]["message"])

On success, usage contains prompt_tokens and completion_tokens. Print them during development to track costs.

Request body breakdown

All four languages send the same JSON. Understand it first; writing in any language is just translation.

FieldRequiredDescription
modelYesFixed to uncensored.
messagesYesArray of objects with role and content. Roles are system, user, assistant.
max_tokensNoDefault 2048, max 16,000 per request. Increase it for long texts.
temperature / top_p / stopNoStandard sampling parameters, passed through as-is.
streamNoSet to true for SSE streaming.

You will most often read three fields in the response: choices[0].message.content is the body, choices[0].finish_reason tells you if it ended normally or was truncated by length, and usage is the token usage for this request. Reading all three fields ensures a complete integration.

Also note two hard limits: the request body must not exceed 8 MB, and each API key is limited to 300 requests per minute. For batch tasks, do not send all parallel requests at once; set a simple concurrency cap first.

Java: java.net.http

JDK 11+ includes HttpClient out of the box, so no dependencies are needed. The example below uses JDK 15 text blocks for JSON; for lower versions, you can use string concatenation or a JSON library of your choice to serialize.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Demo {
    public static void main(String[] args) throws Exception {
        String key = System.getenv("API_KEY");
        String body = """
            {"model":"uncensored",
             "messages":[{"role":"user","content":"写一段两百字以内的悬疑小说开头。"}],
             "max_tokens":400}
            """;
        HttpRequest req = HttpRequest.newBuilder(
                URI.create("https://api.wushenchaapi.com/v1/chat/completions"))
            .timeout(Duration.ofSeconds(120))
            .header("Authorization", "Bearer " + key)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(body))
            .build();
        HttpResponse<String> resp = HttpClient.newHttpClient()
            .send(req, HttpResponse.BodyHandlers.ofString());
        System.out.println(resp.statusCode());
        System.out.println(resp.body());
    }
}

Tip: When the body contains Chinese, BodyPublishers.ofString defaults to UTF-8 encoding, so no extra handling is needed. In production, make HttpClient a singleton to reuse it, instead of creating a new instance for every request.

Go: net/http

Go's standard library is equally sufficient. The key point is not to use the default http.DefaultClient without setting a timeout; otherwise, goroutines will hang indefinitely if the server stalls.

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"os"
	"time"
)

func main() {
	body := []byte(`{"model":"uncensored","messages":[{"role":"user","content":"给一个反派角色写三句独白。"}],"max_tokens":300}`)
	req, err := http.NewRequest("POST", "https://api.wushenchaapi.com/v1/chat/completions", bytes.NewReader(body))
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 120 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	out, _ := io.ReadAll(resp.Body)
	fmt.Println(resp.StatusCode, string(out))
}

Read the response body completely using io.ReadAll before parsing. For structured processing, define a corresponding struct and deserialize it using encoding/json. The fields are choices, message, content, and usage.

PHP: curl

Use the curl extension in PHP. Remember to add JSON_UNESCAPED_UNICODE to json_encode; otherwise, Chinese characters will be escaped as \uXXXX. It works, but it is hard to read during debugging.

<?php
$payload = [
    "model" => "uncensored",
    "messages" => [["role" => "user", "content" => "写一首八行的现代诗,主题是末班地铁。"]],
    "max_tokens" => 300,
];
$ch = curl_init("https://api.wushenchaapi.com/v1/chat/completions");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 120,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("API_KEY"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$res = curl_exec($ch);
if ($res === false) {
    die("curl 错误: " . curl_error($ch) . "\n");
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $status, "\n";
$data = json_decode($res, true);
echo $data["choices"][0]["message"]["content"] ?? $res, "\n";

Distinguish between two types of failures: curl_exec returning false indicates a network-layer issue; returning content with a non-200 status code indicates an API-layer issue, so read error.code.

Common pitfalls on the first call

  • 401: The header was written as Authorization: <key>, missing the Bearer prefix; or the environment variable did not take effect in the new terminal.
  • 404: The path is missing /v1, or chat/completions is misspelled.
  • 400: Invalid JSON, or the prompt plus max_tokens exceeds the 100,000 token limit.
  • 402: Balance depleted or free trial credit expired.
  • Output truncated: max_tokens defaults to 2048, with a maximum of 16,000 per request. Increase it explicitly for long texts.
  • Want streaming: Add "stream": true to the request body. The response will be SSE, and a data block with usage will be appended at the end.

Once it works, look at Prompt writing to improve output quality. For errors, consult the Error Code Troubleshooting Guide. Full parameter documentation is in the documentation, and pricing is on the pricing page.

Once it works, add three things before going live

The examples in the tutorial are the minimum viable versions. To put them into production, you must add at least these three items.

  1. Timeout. The example sets a uniform 120-second timeout because long text generation is indeed slow. If your business requires synchronous waiting, shorten the timeout according to your page's tolerance and use streaming output so users can see characters first.
  2. Error routing. 401, 402, and 403 are errors that retrying won't fix; alert or notify the user. Only 429 and 503 are worth backing off and retrying. Specific implementations are in the troubleshooting guide and are not detailed here.
  3. Usage logging. Log the usage field from every response. Log only the numbers; do not log user content. This is essential for end-of-month reconciliation and investigating abnormal consumption.

A note on key management: there is only one key. If leaked, it can only be regenerated, and regenerating it will cause all active services to go offline. So do not scatter it across multiple scripts and machine configurations; centralize it in one key configuration location so you don't miss any services when switching.

Finally, content boundaries: legal adult content, fictional novels, and controversial topics are not rejected. However, sexual content involving minors is always blocked with a 403 response, including in fiction and roleplay. If your application targets adult users, we recommend adding age verification in your own registration flow.

Here is a final self-check sequence you can even paste next to your monitor: Is the key in the environment variables? Do models respond? Is the request body valid JSON? Is the model uncensored? Is max_tokens sufficient? Is finish_reason in the response 'stop' or 'length'? Is usage logged? If all seven items are green, your integration is complete.

Frequently asked questions

Do you have to use the official SDK to make calls?

No. It is just a standard HTTPS POST with JSON. Any language that can send HTTP requests will work; the SDK just wraps it for convenience.

What should I put in the model field?

Set to uncensored. There is currently only this one model; you can confirm with GET /v1/models.

What happens when the free trial credit runs out?

The request returns 402 with error code no_credit. Top up your prepaid credit to continue using the service. The balance does not expire and there is no subscription.

Will regenerating the key affect the old key?

Yes. The old key becomes invalid immediately, so change to the new key in your services before clicking regenerate, or accept a brief interruption.

Just fill out the form to get your API key

Create an account, copy the key, and modify the Base URL. That's all there is to the configuration.