POST /v1/chat/completions
The OpenAI Chat Completions API. Any OpenAI SDK or tool works when you point its base URL at https://api.abliteratedllm.dev/v1.
Placeholders:
$API_BASEishttps://api.abliteratedllm.dev/v1,$API_ORIGINishttps://api.abliteratedllm.dev, and$YOUR_KEYis your API key.
Request
curl $API_BASE/chat/completions \
-H "Authorization: Bearer $YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-5.3-flash-abliterated",
"messages": [
{"role": "system", "content": "You are a noir novelist."},
{"role": "user", "content": "Open chapter one in three sentences."}
],
"reasoning_effort": "low",
"max_tokens": 2048,
"temperature": 0.8
}'
Abridged response:
{
"id": "…",
"object": "chat.completion",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "Rain hit the window like it owed me money…" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 31,
"completion_tokens": 212,
"total_tokens": 243,
"prompt_tokens_details": { "cached_tokens": 0 }
}
}
Parameters
Fields not listed here are passed to the model unchanged, so standard OpenAI parameters work. Sampling parameters are range-checked first: a value outside its range fails with 400 invalid_request before anything is charged.
| Field | Notes |
|---|---|
model | Required. Any id from GET /v1/models, currently glm-5.3-flash-abliterated, deepseek-v4.1-flash or deepseek-v4-pro. |
messages | Required. Text only (see below). |
max_tokens or max_completion_tokens | Output budget. Default 16384. Lowered to the model's max output (max_output_tokens in GET /v1/models), and to 4096 on trial accounts. A value above the limit is lowered, not rejected. |
reasoning_effort | Passed through. "low", "medium" or "high" sets how much the model reasons before answering. |
stream | true for server-sent events. Without it, the answer is generated as a stream on our side and returned as one chat.completion when it ends, so a request cut by the time limit or a disconnect is billed for the output generated so far. |
stream_options | include_usage is always switched on, so streams always end with a usage chunk. |
temperature | 0 to 2. |
top_p | 0 to 1. |
top_k | 0 to 100. |
frequency_penalty, presence_penalty | -2 to 2. |
stop | A string or up to 4 strings. |
tools, tool_choice, parallel_tool_calls | Function tools, as in the OpenAI API. A tool whose type isn't "function" fails with 400 invalid_request. |
n | Only 1 (the default). Any other value fails with 400 invalid_request; send separate requests for more samples. |
response_format | json_object or json_schema for structured output. |
prompt_cache_key | Passed through. Requests that share a key are routed together, which raises prompt cache hits. |
user | Passed through. |
Streaming
With "stream": true the response is a stream of data: lines. Headers are sent as soon as the model accepts the request. Until the first token arrives, the stream carries an SSE comment line, : ping, every 15 seconds, so proxies don't close an idle connection. SSE clients and the OpenAI SDKs ignore comment lines.
: ping
data: {"id":"…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"Rain"}}]}
data: {"id":"…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"…","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":31,"completion_tokens":212,"total_tokens":243,"prompt_tokens_details":{"cached_tokens":0}}}
data: [DONE]
Usage always arrives in its own final chunk, and that chunk has an empty choices array. Check that choices isn't empty before reading choices[0]:
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="")
if chunk.usage:
print("\n", chunk.usage)
Reasoning
Models that reason before they answer, such as glm-5.3-flash-abliterated, use reasoning_effort to set how much. The model's page under Models says whether it reasons. When the model returns its reasoning, it arrives in reasoning_content: on choices[0].message in a normal response, and on choices[0].delta while streaming. Reasoning tokens are output tokens: they count toward the output budget and are billed at the output price.
Text only
The models accept text. A message with an image, video, audio or file content part fails with 400 unsupported_content before anything is charged. The rejected part types are image_url, input_image, image, video, input_audio and file. Plain string content and text parts are fine. Content nested many levels deep (parts inside parts) fails with 400 invalid_request.
Context length
A prompt longer than the model's context window fails with an error. It is never silently truncated.
Prompt caching
Caching is automatic: when a request starts with the same tokens as a recent one, those tokens are read from cache and billed at the lower cached-input price. usage.prompt_tokens_details.cached_tokens reports how many. To raise hit rates for a long conversation or agent session, send the same prompt_cache_key on every request of that session. We recommend it for any client that sends many requests with a shared prefix.
Billing
cost = (prompt_tokens - cached_tokens) × input price
+ cached_tokens × cached-input price
+ completion_tokens × output price
Prices are per 1M tokens and each term is rounded up to the next $0.000001. Current prices are on GET /v1/models, which also explains holds, aborted streams and failed requests.
Headers
Claude Code's session header, X-Claude-Code-Session-Id, is honored for cache affinity; every other client header is dropped. Every response carries x-request-id.
Errors
Errors use the OpenAI shape, {"error": {"type", "code", "message"}}. The codes are on the Errors page.