Streaming events
SSE event formats for the three protocols with stream: true, the keepalive comments HopBase inserts, and how errors are delivered mid-stream.
With "stream": true in the request body, Create chat completion, Create response and Create message return text/event-stream (SSE) instead. Event formats follow each protocol's official definition, so the streaming interfaces of the official SDKs work directly; HopBase only inserts keepalive comments and does not change event content.
/v1/chat/completionsPOST/v1/responsesPOST/v1/messagesKeepalive comments
While streaming, HopBase writes an SSE comment line between events about every 10 seconds, so intermediate proxies do not treat the connection as idle and drop it during long reasoning:
: hopbase-keepaliveLines starting with a colon are comments in the SSE spec, and the official SDKs and standard SSE parsers ignore them. If you parse lines yourself, skip lines starting with : instead of parsing them as JSON. If the model produces no output for a long time (about 90–150 seconds, depending on the model), the gateway treats it as stalled and retries or returns an error; see Concurrency, timeouts, and billing.
Chat Completions
Each event is a single data: line containing a chat.completion.chunk object, with text in choices[0].delta.content; the stream ends with data: [DONE].
data: {"id":"chatcmpl-EXAMPLE","object":"chat.completion.chunk","model":"gpt-5.6-sol","choices":[{"index":0,"delta":{"role":"assistant","content":"I am"},"finish_reason":null}]}
data: {"id":"chatcmpl-EXAMPLE","object":"chat.completion.chunk","model":"gpt-5.6-sol","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"id":"chatcmpl-EXAMPLE","object":"chat.completion.chunk","model":"gpt-5.6-sol","choices":[],"usage":{"prompt_tokens":14,"completion_tokens":52,"total_tokens":66}}
data: [DONE]| Field | Description |
|---|---|
choices[].delta.content | Text in this chunk |
choices[].delta.tool_calls | Tool call arguments arrive in pieces; concatenate function.arguments by index |
choices[].finish_reason | Non-null in the last chunk: stop / length / tool_calls |
usage | Sent only if the request set stream_options.include_usage: true, in a final event with empty choices; omitting it does not affect billing |
Responses
Each event consists of an event: line and a data: line; the type in data matches the event name.
event: response.created
data: {"type":"response.created","response":{"id":"resp_EXAMPLE","status":"in_progress"}}
event: response.output_text.delta
data: {"type":"response.output_text.delta","item_id":"msg_EXAMPLE","output_index":0,"content_index":0,"delta":"I am"}
event: response.completed
data: {"type":"response.completed","response":{"id":"resp_EXAMPLE","status":"completed","usage":{"input_tokens":14,"output_tokens":58,"total_tokens":72}}}| Event | Description |
|---|---|
response.created | The response has started |
response.output_text.delta | A piece of output text, in delta |
response.output_text.done | A content part has finished; text holds the full text |
response.completed | Finished successfully; response.usage holds usage |
response.failed | Failed midway; the reason is in response.error.code: rate_limit_exceeded / server_error / invalid_prompt |
Anthropic Messages
Event order: message_start → for each content block content_block_start / content_block_delta / content_block_stop → message_delta (with stop_reason and output usage) → message_stop.
event: message_start
data: {"type":"message_start","message":{"id":"msg_EXAMPLE","role":"assistant","model":"claude-sonnet-5","content":[],"usage":{"input_tokens":9,"output_tokens":1}}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello!"}}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":14}}
event: message_stop
data: {"type":"message_stop"}Errors mid-stream
Once a stream starts producing output, the HTTP status is already 200. Later errors are delivered as events, and the status code never changes:
Chat Completions data: {"error": {…}} (no event: line)
Responses event: response.failed
Anthropic event: errorIf a Claude stream breaks midway, HopBase sends one Anthropic error event and then ends the stream:
event: error
data: {"type":"error","error":{"type":"api_error","message":"Response stream interrupted, please retry"}}Handle error events inside your read loop. Partial output cannot be resumed; reissue the whole request. Output produced before the interruption is billed by usage. For retry policy, see Error codes and retries.