API documentation

OpenAI-compatible chat completions. Technical description of how the service behaves; it is not a service-level commitment.

Quick start

Base address https://api.privatedeskai.com/v1. Get a key on the account page and send it as a bearer token.

curl https://api.privatedeskai.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"model":"deepseek-ai/DeepSeek-V4-Flash-0731","messages":[{"role":"user","content":"Hello"}]}'

Streaming (server-sent events) - add "stream": true and read lines starting with data: until data: [DONE]:

curl -N https://api.privatedeskai.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"model":"deepseek-ai/DeepSeek-V4-Flash-0731","stream":true,"stream_options":{"include_usage":true},"messages":[{"role":"user","content":"Hello"}]}'

With the OpenAI SDKs set base_url to the address above and use your key.

Models

GET /v1/models lists them: deepseek-ai/DeepSeek-V4-Flash-0731 and the fast-mode alias deepseek-v4-flash-fast. Context window 400,000 tokens, output up to 16,000 tokens (see /models).

Each object in the GET /v1/models list carries context_length (400000), max_tokens (16000) and pricing with two fields, prompt and completion: the price in US dollars per token, written as a string (for example "0.000000028"). The price depends on the tariff of the key sent in the Authorization header: a Super Deal key sees "0.000000028" for both fields; a Standard key, a wrong key or no key sees the Standard prices, prompt "0.00000003971" and completion "0.00000007941". Both model names are the same model, so both show the price of the key's tariff.

{"object":"list","data":[{"id":"deepseek-ai/DeepSeek-V4-Flash-0731","object":"model","owned_by":"sagg","context_length":400000,"max_tokens":16000,"pricing":{"prompt":"0.000000028","completion":"0.000000028"}}]}

Response format

The answer is passed on in the OpenAI format. A non-streaming response (shortened; the values are an example, and reasoning_content is present when the model thought before answering):

{"id":"devshard-156104-7671","object":"chat.completion","created":1793983354,"model":"deepseek-ai/DeepSeek-V4-Flash-0731",
 "choices":[{"index":0,"finish_reason":"length","message":{"role":"assistant","content":"...","reasoning_content":"..."}}],
 "usage":{"prompt_tokens":89,"completion_tokens":64,"total_tokens":153,"completion_tokens_details":{"reasoning_tokens":41}}}

A streaming response is a sequence of data: lines, each a chat.completion.chunk with a delta (first the role, then pieces of reasoning_content when the model thinks, then pieces of content); the last content chunk has an empty delta and a finish_reason; with "stream_options":{"include_usage":true} one more chunk follows with "choices":[] and usage; the stream ends with data: [DONE]:

data: {"id":"...","object":"chat.completion.chunk","model":"deepseek-ai/DeepSeek-V4-Flash-0731","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

data: {"id":"...","object":"chat.completion.chunk","model":"...","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"...","object":"chat.completion.chunk","model":"...","choices":[],"usage":{"prompt_tokens":7,"completion_tokens":64,"total_tokens":71}}

data: [DONE]

Other fields that the provider adds (for example system_fingerprint) are passed on as they are.

Reasoning

The model can think before it answers; the thinking comes back in reasoning_content. The request field reasoning_effort works like this: none turns thinking off; low, high and max turn it on. They differ in one gateway rule: a stream that creeps (after 90 seconds of streaming, both the average pace and the pace of the last 30 seconds are below 5 tokens per second) is handed to the next provider, if one is left; this rule is not applied to requests with high, xhigh or max, or with thinking enabled, because they ask for long thinking on purpose. It is applied with low, with none and when the field is absent. The field thinking is accepted but has no effect.

With thinking on, use "stream": true. The model can think for a long time before the first token of the answer, and a non-streaming request can end with 503 before the answer is ready: in our check of 2026-10-30, 8 of 15 non-streaming requests with low, high or max on Standard ended this way. With none, non-streaming requests work normally.

Time to the first word

By default the model may think before it answers, and this adds to the time before the first word. A client can turn thinking off with an explicit reasoning_effort: "none". The gateway does not change this on its own: a request without the field behaves as described above, and the choice stays with the client.

Our measurement of 2026-11-08: 124 requests per line per mode, short answers, ordinary requests without tool calls, made with reasoning_effort: "none" against requests without the field (not with the alias deepseek-v4-flash-fast from the Models section). Median time to the first word: Standard 1.24 s by default and 0.61 s with none; Super Deal 3.60 s by default and 0.79 s with none. The slowest 5% of first words changed little: Standard 8.3 s and 7.7 s, Super Deal 23.4 s and 21.5 s. The time to the complete answer in the slowest 5% was not lower: Standard 8.9 s and 10.7 s, Super Deal 23.4 s and 31.2 s.

This is a technical measurement, not a guarantee. The quality of the answers was not compared in it, and requests with tool calls were not measured.

Limits

Technical limits, not promises: a limit on request rate, a limit on concurrent streams, a limit on request body size. Exceeding the rate or stream limit returns 429 with a Retry-After header; a body that is too large returns 413.

LimitValue
Context window (context_length)400000 tokens
Output (max_tokens)16000 tokens
Request body2 MiB (2097152 bytes); larger returns 413 request_too_large
Request rate of a key from the account pagea token bucket: 20 requests at once, refilled at 5 per second; when it is empty the answer is 429 rate_limit_exceeded and Retry-After is the time to the next free token (one second at 5 per second)
Concurrent streams of a key from the account page4 by default; a request over the limit returns 429

The rate and the stream count are counted per account: all keys of one account share them. The values above are the defaults of keys issued on the account page; the operator can set other values for a particular key.

Errors

Errors use the OpenAI format {"error":{"message","type","code","param"}}; every response carries X-Request-ID.

StatusWhenError code (examples)
400the request cannot be answered: invalid JSON, wrong type, a value out of range (temperature, top_p, max_tokens), a missing field, n above 1invalid_json, invalid_type, invalid_value, missing_required_parameter
401the key is wrong; the response carries WWW-Authenticateinvalid_api_key
402no key and the request asks for payment by the x402 protocol (agents that pay per request)x402 payment requirements
404unknown modelmodel_not_found
413request body too largerequest_too_large
429rate or concurrent-stream limit; wait for Retry-Afterrate_limit_exceeded
502, 503no provider could answer (all failed or the answer was unusable); X-Request-ID identifies the request, Retry-After may be presentupstream_error, all_providers_unavailable

What a stream does when something goes wrong

Billing, in plain words

Tariffs

Standard: requests go to decentralized network providers in priority order; behind them stands an insurance provider outside the decentralized network. Super Deal - economical tariff, depends on the decentralized network, no insurance outside that network: decentralized-network providers only.

Prices are on the pricing page.

Parameter support is described on the compatibility page; measured results are on benchmarks.