Requesting an output ceiling
Sunra forwards the ceiling you send to the upstream provider. When a response stops because it hit that ceiling, it reports
finish_reason: "length" (Chat Completions and Responses) or stop_reason: "max_tokens" (Messages) — the same signal you would get calling the provider directly.
On Chat Completions, some providers accept only
max_tokens and ignore max_completion_tokens — an unbounded completion when you believed you had set a ceiling. For the deepseek/ models the gateway translates max_completion_tokens into max_tokens on your behalf. If you send both, the smaller of the two wins, since either one is an upper bound.Providers that honor max_completion_tokens natively are left alone, so a ceiling you set is enforced exactly once, wherever it is enforced.Model output ceilings
Each model has its own maximum output length, independent of what you request. Asking for more than a model allows is rejected, not silently reduced — the upstream provider returns400 with the valid range in the message. For example, deepseek/deepseek-v4-flash and deepseek/deepseek-v4-pro accept up to 393,216 output tokens and reject anything above it:
400 is the intended behavior here. A ceiling that is quietly lowered would be indistinguishable from a completion that legitimately ran to its limit: both report finish_reason: "length", and nothing in usage would tell you which happened.
Output ceilings are per model and change as providers ship new versions. Treat the 400 as the authoritative answer rather than hard-coding a limit in your client.
Stream lifetime
A streamed request (stream: true) is governed by two limits on the gateway side:
Neither limit applies to a stream that is actively delivering tokens within the idle window — a long generation is not interrupted just for being long. Non-streaming requests are not subject to these limits; they have their own fixed ceiling of 6 minutes for the whole request.
The abort frame
When either limit fires — or the upstream connection fails mid-stream — the gateway does not drop the connection. It flushes whatever it still holds, sends an error frame in your endpoint’s SSE dialect, and closes the stream cleanly. Everything delivered before the frame is valid output and can be used. On/v1/chat/completions and /v1/responses:
[DONE] sentinel is part of the Chat Completions dialect only; Responses streams end after the error frame without one.
On /v1/messages, the frame follows the Anthropic dialect — a typed error event, and no [DONE]:
type is always gateway_stream_aborted. On the OpenAI-shaped dialects, code names which limit fired:
A stream that ends without an abort frame ended normally. Because the frame is deterministic, treat its absence together with a truncated stream as a client-side or network problem rather than a gateway abort.
Billing for an aborted stream
An aborted stream is billed for what was delivered to you, never for the full generation the provider may have continued internally.- If the provider had already reported final usage before the abort, that report is billed.
- Otherwise the delivered output is settled on a conservative estimate — roughly four characters per token, capped at the output ceiling you requested. The completion records
usage_source: "conservative_estimate"for the record. - If nothing was delivered, or the provider reported an explicit error, the request is marked failed and the reserved credits are released. Failed requests are not charged.