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#

Text
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:

  1. Content chunks. choices[0].delta carries content, and for reasoning models reasoning_content, as they are generated. The first chunk also sets delta.role: "assistant". Tool calls arrive as delta.tool_calls fragments; see Tool calling.
  2. A finish chunk with an empty delta and finish_reason set (stop, length, tool_calls or content_filter).
  3. A usage chunk with choices: [] and the final token counts. Sent by default; set stream_options: {"include_usage": false} to omit it.
  4. A billing chunk with choices: [] and a fable object. This is Claud-specific and tells you exactly what the request cost.
  5. 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
true if 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:

Text
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-stream if your HTTP client supports it, and disable response buffering (-N in curl). Claud already sets X-Accel-Buffering: no for 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_content deltas 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.