We use cookies. Cookies and browser storage keep you signed in and remember your preferences. With your permission we also measure how the site is used. You can any time. See our cookie policy.

Streaming

Endpoints

Streaming

Stream model output token by token with server-sent events by setting stream to true, and read the chunks in your app as they arrive.

Try it in the playground

Set stream: true on Chat completions, Responses or Completions to receive tokens as they are generated. The response uses server-sent events (Content-Type: text/event-stream). api14 passes the upstream bytes through to you as they arrive and does not buffer them.

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api14.com/api/v1",
  apiKey: process.env.API14_API_KEY,
});

const stream = await client.chat.completions.create({
  "model": "openai/gpt-5-mini",
  "messages": [
    {
      "role": "user",
      "content": "Explain vector databases in two sentences."
    }
  ],
  "stream": true
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

Event format

Each event is a data: line holding a JSON chunk. The stream ends with data: [DONE].

data: {"id":"gen-1760000000-abc","object":"chat.completion.chunk","model":"openai/gpt-5-mini","choices":[{"index":0,"delta":{"role":"assistant","content":"Hel"}}]}

data: {"id":"gen-1760000000-abc","object":"chat.completion.chunk","model":"openai/gpt-5-mini","choices":[{"index":0,"delta":{"content":"lo!"}}]}

data: {"id":"gen-1760000000-abc","object":"chat.completion.chunk","model":"openai/gpt-5-mini","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":10,"completion_tokens":3,"total_tokens":13,"cost":0.0000085}}

data: [DONE]
  • The last chunk before [DONE] carries usage, including cost in USD. You don't need stream_options.include_usage. Usage reporting is always on.
  • The id is the same in every chunk. It is the generation id you can pass to Generation lookup.
  • Some providers send SSE comment lines (lines starting with :) to keep the connection alive. SSE clients and the OpenAI SDKs ignore them. If you parse the stream yourself, skip lines that start with :.

Billing for streams

The gateway reads the final usage chunk while forwarding the stream and debits your balance once the stream closes.

Disconnecting does not cancel the bill. If you close the connection before the stream finishes, the upstream provider may keep generating and still charge for it. In that case api14 reads the cost from the generation record. To limit the cost, set max_tokens.

Errors during a stream

Errors before the first byte, such as an invalid key, a low balance or an unknown model, return a normal JSON error with a 4xx or 5xx status. See Errors. If a provider fails mid-stream, the stream may end with a chunk that contains an error object and finish_reason: "error":

{ "error": { "code": 502, "message": "Provider disconnected" }, "choices": [{ "delta": { "content": "" }, "finish_reason": "error" }] }

Always check finish_reason on the last chunk.

Tips

  • Proxies and serverless platforms sometimes buffer responses. Disable response buffering (e.g. X-Accel-Buffering: no on nginx) if you relay the stream to browsers.
  • Tool calls stream as delta.tool_calls fragments. Join the arguments strings by index before parsing them. See Tool calling.
  • Reasoning models stream their reasoning in delta.reasoning before the answer. See Reasoning.