stream: true on POST /v1/chat/completions to get a Server-Sent Events response. Add stream_options.include_usage when your client needs the usage frame. /v1/messages uses a different, event-named stream grammar described in Anthropic Messages.
What arrives, and when
Frame shapes
The response carriesContent-Type: text/event-stream, Cache-Control: no-cache and Connection: keep-alive. Content arrives in OpenAI-compatible data: frames, and partial output is on choices[].delta.
choices array. On a hosted model it also carries the request’s cost and the count of input tokens billed at the cached rate, both described in Chat completions:
data: [DONE].
[DONE]. A transport interruption can close it without an error frame. Treat a missing [DONE] as an incomplete response even when the HTTP status was 200. Retrying with the same Idempotency-Key returns the original request’s receipt, or 409 while it is still running; it never replays the text. To get an answer, send a new request with a new key, which is new paid inference. See Retrying a stream.
code is upstream_error when the model stream ended, hosted_inference_response_timeout when the response deadline did, and upstream_stream_error otherwise. See Errors.
Is usage always included?
No. The gateway always asks the model for usage so it can settle the request, but it forwards the usage frame to you only when your request carriedstream_options.include_usage: true. Omit it and content frames still stream while usage-only frames stay hidden. A usage frame is never synthesized: if the model reports no usage for a request, none is sent.
After an interrupted request, recovery uses the usage evidence that was persisted. A failed checkpoint write can leave that evidence missing or stale, so neither the delivered token count nor the final charge can be inferred from the last content chunk. Keep the request id for support. A new key starts new paid inference and cannot recover the old response.
There is one exception, so you can account for generated tokens even when no answer was delivered. When every choice finishes without final answer content, the gateway forwards one annotated usage frame whether or not you opted in.
When a stream ends without an answer
A choice that reaches its generation limit before producing answer content carries a machine-readable status on its terminal frame:finish_reason produced no answer, the code is no_answer_content instead. Inspect the preserved finish_reason before deciding whether to retry.
The annotated usage frame then reports how much of the generated output was not an answer:
cost: 0 and cached_tokens: 0 whatever the model reported: nothing was priced, at either rate.
The usual cause is an output budget too small for a model that reasons first. See give reasoning models room.
The same
Idempotency-Key reads the original request’s receipt; it does not replay delivered tokens. Getting a new answer requires a new request and a new key, which starts new paid inference. Read Retrying a stream before retrying a stream.Related
Chat completions
The request contract every stream starts from.
Idempotent retries
Retry a dropped stream without paying twice.
Errors
Every status, code, and caller action.