UncutGPT API reference
OpenAI-compatible access to 100+ models, from Claude, GPT, Gemini and Grok to UncutGPT's own uncensored models. Keep your OpenAI code; change the base URL and the key.
Introduction
The UncutGPT API gives your code 100+ models: UncutGPT's uncensored models and mainstream ones such as Claude, GPT, Gemini, Grok, DeepSeek and Qwen. It follows OpenAI's Chat Completions API, so the official OpenAI libraries and most tools built for them work unchanged: set the base URL and use an UncutGPT key.
- Base URL
https://uncutgpt.com/api/v1- Format
- JSON over HTTPS; streaming as server-sent events
- Billing
- Prepaid credit, charged per token
Authentication
Every request needs a secret key in the Authorization header. Create keys in the API platform; each key is shown once, when you create it.
Authorization: Bearer $UNCUTGPT_API_KEYTreat keys like passwords. Anyone with one can spend your credit, so keep keys on your server and out of web pages, mobile apps and public repositories. Revoke a leaked key at once on the platform; you can also give each key a monthly spending limit. Call the API from your server, not from browser JavaScript: browsers on other sites are refused (CORS).
Quickstart
- Create an API key and save it as
UNCUTGPT_API_KEY. - Add credit on the platform's Billing page (from $5). Its Playground, for trying models, uses the same credit.
- Send your first request:
curl https://uncutgpt.com/api/v1/chat/completions \
-H "Authorization: Bearer $UNCUTGPT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "venice-uncensored-1.2",
"messages": [
{"role": "system", "content": "You are a blunt, honest assistant."},
{"role": "user", "content": "Write a haiku about the ocean."}
]
}'Models
GET /v1/models lists every model the API offers, with its context size and price per million tokens. GET /v1/models/{model} returns one. Use the id as the model of a request. The list changes as providers add and retire models, so read it rather than hard-coding prices.
{
"object": "list",
"data": [{
"id": "venice-uncensored-1.2",
"object": "model",
"created": 1735689600,
"owned_by": "system",
"name": "Uncut Uncensored AI",
"context_length": 128000,
"max_output_tokens": 32768,
"uncensored": true,
"vision": true,
"tools": true,
"pricing": { "input_per_million_usd": 0.26, "output_per_million_usd": 1.17 }
}]
}Models marked "uncensored": true answer without the refusals and lectures of mainstream assistants. They still won't help with anything in the acceptable use rules.
Chat completions
POST /v1/chat/completions sends a conversation and returns the model's reply.
Request body
| Field | Description |
|---|---|
modelstring · required | A model ID from GET /v1/models, such as venice-uncensored-1.2. |
messagesarray · required | The conversation so far, oldest first: 1 to 2,000 messages. See the message object below. |
streamboolean | Send the reply as server-sent events while it's written. Default false. |
stream_optionsobject | {"include_usage": true} adds a final chunk with token usage and cost. |
max_completion_tokensinteger | The most tokens the reply may use. Alias: max_tokens. Capped at the model's own limit; without it, up to 8,192. |
temperaturenumber | 0 to 2. Higher is more random. |
top_pnumber | 0 to 1. Nucleus sampling. |
frequency_penaltynumber | -2 to 2. Discourages repeating the same tokens. |
presence_penaltynumber | -2 to 2. Encourages new topics. |
stopstring | array | Up to 4 sequences (each up to 1,000 characters) where the reply stops. |
seedinteger | Best-effort repeatable sampling, where the model supports it. |
response_formatobject | {"type": "json_object"} or a json_schema, for models that support it. |
toolsarray | Up to 128 functions the model may call. See Tool calling. |
tool_choicestring | object | none, auto, required, or a specific function. |
parallel_tool_callsboolean | Whether the model may call several tools at once. |
reasoning_effortstring | minimal, low, medium or high, for reasoning models. |
ninteger | Only 1 is supported. |
userstring | Accepted for compatibility and ignored: it is never stored or passed on. |
Message object
| Field | Description |
|---|---|
rolestring · required | system, developer, user, assistant or tool. |
contentstring | array · required | Text, or (user messages only) an array of {type: "text"} and {type: "image_url"} parts. Images may be https URLs or base64 data URLs, for models that accept images. |
tool_callsarray | On assistant messages: the calls the model made (content may then be null). |
tool_call_idstring | On tool messages: the call this result answers. |
namestring | An optional participant name (letters, digits, _ and -, up to 64), sent to the model with the message. |
Response
finish_reason is stop when the reply ended naturally, length when it reached max_completion_tokens, tool_calls when the model called a tool, and content_filter when the provider withheld it.
{
"id": "chatcmpl-3f1c9a6b2e4d4c8f9a1b7e2d5c6f8a90",
"object": "chat.completion",
"created": 1792561200,
"model": "venice-uncensored-1.2",
"system_fingerprint": null,
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Salt wind folds the waves…", "refusal": null },
"logprobs": null,
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 31,
"completion_tokens": 18,
"total_tokens": 49,
"prompt_tokens_details": { "cached_tokens": 0 },
"cost": 0.00003
}
}Streaming
With "stream": true the reply arrives as server-sent events, one chat.completion.chunk per piece, ending with data: [DONE]. Set stream_options.include_usage to get a last chunk with empty choices and the request's usage. While a model is thinking, the stream sends comment lines (: ping) to keep the connection open; SDKs skip them.
stream = client.chat.completions.create(
model="venice-uncensored-1.2",
messages=[{"role": "user", "content": "Tell me a short story."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)data: {"id":"chatcmpl-3f1c…","object":"chat.completion.chunk","created":1792561200,"model":"venice-uncensored-1.2","system_fingerprint":null,"choices":[{"index":0,"delta":{"role":"assistant","content":"Salt"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-3f1c…","object":"chat.completion.chunk","created":1792561200,"model":"venice-uncensored-1.2","system_fingerprint":null,"choices":[{"index":0,"delta":{"content":" wind"},"logprobs":null,"finish_reason":"stop"}]}
data: [DONE]If something fails after the stream started, the last event is an error object (see Errors) instead of [DONE]; OpenAI SDKs raise it as an exception.
Tool calling
Describe functions in tools; when the model wants one, the reply has finish_reason: "tool_calls" and the calls in message.tool_calls. Run the function yourself, then send its result back as a tool message with the matching tool_call_id. Check a model's tools flag in the model list first.
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
response = client.chat.completions.create(
model="venice-uncensored-1.2",
messages=[{"role": "user", "content": "What's the weather in Lisbon?"}],
tools=tools,
)
call = response.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments) # get_weather {"city": "Lisbon"}Pricing and billing
The API runs on prepaid credit, bought on the API platform from $5. Each request costs the input and output tokens the model actually used, at the model's price per million tokens as listed by /v1/models; cached input tokens cost less where the model offers caching.
- A request that fails without streaming costs nothing, since you received nothing.
- A stream that fails part-way costs only the output already sent to you.
- A stream you stop (by closing the connection) costs what the model produced until then. A request without streaming may keep running after you disconnect, and costs its whole reply.
Before a request starts, an estimate of its largest cost (the prompt, counted generously, plus max_completion_tokens, at least 32) is set aside from your balance, and whatever it didn't use goes back when it ends. Without max_completion_tokens, a low balance shortens the longest reply allowed; with it, a request the balance can't cover is refused with insufficient_quota (key_limit_reached when the key's monthly limit is what falls short). Some models add their own system prompt to a conversation without one, and some write a few tokens past a very small max_completion_tokens; you pay for what they really used. If that is more than was set aside, the rest comes from your balance as far as it goes (it never goes below zero), so a key can end slightly over its monthly limit. API credit is separate from Plus and Super plans.
Rate limits
- 60 requests per minute for each key.
- 4 requests running at the same time for each account.
- 600 requests per minute from one IP address, whatever the key.
- Up to 5 active keys per account.
- Requests up to 4 MB, and replies up to 10 minutes long.
Over a rate limit, the API answers 429 rate_limit_exceeded with a Retry-After header in seconds, and OpenAI SDKs retry automatically. Running out of credit or reaching a key's monthly limit is also a 429, but waiting won't fix it: those send x-should-retry: false, so SDKs raise the error at once. Need more? Contact support.
Errors
Errors use OpenAI's format, so SDKs raise their usual exceptions (AuthenticationError, RateLimitError and so on). Messages never include provider details. A request without streaming keeps its real status for 90 seconds; one that fails after that (while the connection is kept open) answers 200 with the error object as its body, so check for error when a request runs that long.
{
"error": {
"message": "You exceeded your current quota. Add credits on the UncutGPT API platform to keep using the API.",
"type": "insufficient_quota",
"param": null,
"code": "insufficient_quota"
}
}| Code | Meaning |
|---|---|
null400 · invalid_request_error | A parameter is missing or invalid; param names the field. With param null, the model refused the request, for example because it is longer than the model's context. |
unsupported_parameter400 · invalid_request_error | The model doesn't support tools (or tool_choice), response_format or reasoning_effort; param names which. |
unsupported_content400 · invalid_request_error | The model doesn't accept images. |
missing_api_key401 · invalid_request_error | No key in the Authorization header. |
invalid_api_key401 · invalid_request_error | The key is wrong, malformed or revoked. |
account_unavailable403 · permission_error | The account behind the key is blocked or deleted. |
model_not_found404 · invalid_request_error | The model ID isn't offered. List models with GET /v1/models. |
unknown_url404 · invalid_request_error | The path isn't an API endpoint. |
not_found404 · invalid_request_error | The API is switched off for now. |
method_not_allowed405 · invalid_request_error | The endpoint doesn't take this HTTP method. |
request_too_large413 · invalid_request_error | The request body is over 4 MB. |
rate_limit_exceeded429 · rate_limit_error | Too many requests per minute or at once, or over 600 a minute from one IP address. Wait for Retry-After. |
upstream_rate_limited429 · rate_limit_error | The model provider is busy. Wait for Retry-After. |
insufficient_quota429 · insufficient_quota | The balance can't cover the request. Add credits; waiting won't help. |
key_limit_reached429 · insufficient_quota | The key reached its monthly spending limit. Raise it or use another key. |
upstream_error502 · server_error | The model provider failed. Safe to retry: without streaming it cost nothing, and a stream that broke off cost only the output already sent. |
model_unavailable503 · server_error | The model is temporarily unavailable. Retry after a moment or pick another model. |
overloaded503 · server_error | The API is busy or can't be reached. Retry after Retry-After. |
unavailable503 · server_error | The API or its model list is temporarily unavailable. Retry after Retry-After. |
timeout504 · server_error | The reply took longer than 10 minutes. Charged like upstream_error. |
OpenAI compatibility
- Supported endpoints: GET /v1/models, GET /v1/models/{model} and POST /v1/chat/completions.
- Unknown request fields are ignored rather than rejected, so newer SDKs keep working.
- Sampling options a model doesn't support (such as seed) are dropped; tools, response_format and reasoning_effort on a model without them return a 400 error instead.
- The developer role is sent to models as system.
- Reasoning models return their thinking in reasoning_content, next to content.
- usage includes cost: what the request was charged, in US dollars.
- Quota errors (insufficient_quota, key_limit_reached) send x-should-retry: false, so OpenAI SDKs don't retry them.
- logprobs and n greater than 1 aren't supported.
Data and acceptable use
We don't store your prompts or the model's replies. For each request we keep only metadata: the key, model, token counts, cost, status and time, to bill you and show your usage. Prompts go to the model provider that serves the request and nowhere else; the user field and any IDs you send are never passed on.
The API is for adults (18+). Uncensored doesn't mean anything goes: content sexualising minors, non-consensual intimate imagery of real people, and help with serious crimes are banned, and keys used for them are revoked. If you serve the API to your own users, you're responsible for them following these rules. Read the full terms of service and privacy policy.
