Streaming
Set stream: true and Claud returns the completion incrementally as server-sent events, so your users see the first words within a few hundred milliseconds instead of waiting for the whole answer.
Making a streaming request#
curl https://api.claudkey.com/v1/chat/completions \
-H "Authorization: Bearer $CLAUD_API_KEY" \
-H "Content-Type: application/json" \
-N \
-d '{
"model": "claud-5.1",
"stream": true,
"messages": [{ "role": "user", "content": "Count to five, one number per line." }]
}'The response has Content-Type: text/event-stream. Each event is a line starting with data: followed by a JSON object, separated by blank lines. The stream ends with the literal data: [DONE].
Anatomy of a stream#
data: {"id":"chatcmpl-01J9...","object":"chat.completion.chunk","created":1789467600,"model":"claud-5.1","system_fingerprint":"fp_claud","choices":[{"index":0,"delta":{"role":"assistant","content":"1"},"logprobs":null,"finish_reason":null}]}
data: {"id":"chatcmpl-01J9...","object":"chat.completion.chunk","created":1789467600,"model":"claud-5.1","system_fingerprint":"fp_claud","choices":[{"index":0,"delta":{"content":"\n2"},"logprobs":null,"finish_reason":null}]}
...
data: {"id":"chatcmpl-01J9...","object":"chat.completion.chunk","created":1789467600,"model":"claud-5.1","system_fingerprint":"fp_claud","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]}
data: {"id":"chatcmpl-01J9...","object":"chat.completion.chunk","created":1789467600,"model":"claud-5.1","choices":[],"usage":{"prompt_tokens":18,"completion_tokens":9,"total_tokens":27,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":0},"prompt_cache_hit_tokens":0,"prompt_cache_miss_tokens":18}}
data: {"id":"chatcmpl-01J9...","object":"chat.completion.chunk","created":1789467600,"model":"claud-5.1","choices":[],"fable":{"tokens_debited":"21","cost_usd":"0.000041","balance_tokens":"25998179","fallback_used":false}}
data: [DONE]In order, you will receive:
- Content chunks.
choices[0].deltacarriescontent, and for reasoning modelsreasoning_content, as they are generated. The first chunk also setsdelta.role: "assistant". Tool calls arrive asdelta.tool_callsfragments; see Tool calling. - A finish chunk with an empty
deltaandfinish_reasonset (stop,length,tool_callsorcontent_filter). - A usage chunk with
choices: []and the final token counts. Sent by default; setstream_options: {"include_usage": false}to omit it. - A billing chunk with
choices: []and afableobject. This is Claud-specific and tells you exactly what the request cost. data: [DONE].
The fable billing event#
- tokens_debitedstring
- Claud tokens charged for this request, as a decimal string.
- cost_usdstring
- The same amount in US dollars, six decimal places.
- balance_tokensstring
- Your available balance after this request.
- fallback_usedboolean
trueif the request was served by the model's fallback route. You are still billed at the requested model's price.
The OpenAI SDKs pass unknown fields through: in JavaScript read chunk.fable, in Python read chunk.model_extra["fable"].
Errors mid-stream#
If the request fails before any output, you get a normal HTTP error status and JSON body. Once streaming has begun the status is already 200, so failures are delivered as an event and the stream is closed:
data: {"error":{"message":"The model provider timed out.","type":"provider_error","code":"provider_timeout","request_id":"req_01J9..."}}
data: [DONE]Tokens generated before the failure are billed; the remainder of the reservation is released. Always check for an error key on each event.
Cancelling#
Close the connection to stop generation. Claud aborts the upstream request within a few hundred milliseconds and bills only the tokens produced so far.
const controller = new AbortController();
setTimeout(() => controller.abort(), 5_000); // give up after five seconds
const stream = await client.chat.completions.create(
{ model: 'claud-5.1', stream: true, messages },
{ signal: controller.signal },
);Response headers#
Streaming responses carry x-request-id, x-claud-model and the x-ratelimit-* headers. x-claud-tokens-debited and x-claud-balance are only available on non-streaming responses because the cost is not known when headers are sent; use the fable event instead.
Tips#
- Send
Accept: text/event-streamif your HTTP client supports it, and disable response buffering (-Nin curl). Claud already setsX-Accel-Buffering: nofor proxies. - Deltas are not word-aligned. Buffer until you have a whitespace boundary if you render markdown incrementally.
- Keep an idle timeout of at least 60 seconds; reasoning models may pause visible output while thinking, although
reasoning_contentdeltas usually keep the connection busy. - If you need the whole answer anyway (for example to parse JSON), use a non-streaming request; it is simpler and the cost is identical.