Streaming
stream true on both metered endpoints, how settlement works on the terminal chunk, and what to do when a stream breaks.
Both metered endpoints stream. Set stream: true and you get server-sent events in the
OpenAI chunk shape, so a stock OpenAI client iterates them unchanged.
stream = client.chat.completions.create(
model="auto",
messages=[{"role": "user", "content": "Write a haiku about prepaid inference."}],
max_tokens=100,
stream=True,
)
for chunk in stream:
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)Billing on a stream
The prepaid flow is the same as a non-streamed call, and the difference is only when the books close:
- The worst-case hold is reserved before the first byte is sent.
- Chunks stream to you.
- The terminal chunk carries the final
usage, and settlement happens there.
So a 402 for insufficient balance arrives before the stream starts, never halfway
through one. If a stream begins, the hold cleared.
Read usage off the terminal chunk
Intermediate chunks do not carry a settled usage. Take token counts and
usage.cost from the last chunk of the stream. Reading them earlier gets you a
partial figure or nothing at all.
When a stream breaks
If the connection drops mid-stream, you have a partial completion and ModelBeat has an unsettled hold. The hold is reconciled on our side rather than being stranded against your balance — you are charged for what was actually generated, not for the reservation.
There is no resume. Reissue the request.
Errors during a stream
An error raised before the stream starts uses the ordinary envelopes and status codes in Errors — a normal JSON body, not an SSE frame. That covers authentication, rate limits, balance, and routing refusals, all of which are decided up front.
Every response carries X-Request-Id, streamed or not. Log it. See
Errors.
What is not supported
- Streaming on the unsupported shapes.
/v1/messagesand/v1/responsesreturn501in their streaming form exactly as they do otherwise. See Limits.