OpenAI-compatible streaming with SSE
Configure streaming without mixing endpoint formats. The examples keep verified routing separate from model-specific capability claims.
What streaming changes
With a non-streaming request, the client waits for the complete response. Streaming delivers incremental events as the model produces output. OpenAI documents server-sent events (SSE) for streamed HTTP responses; the Responses API and Chat Completions expose different event shapes.
| Endpoint | Read text from | End condition |
|---|---|---|
| Responses | Typed events such as response.output_text.delta | response.completed, or an error event |
| Chat Completions | chunk.choices[0].delta.content | SSE terminator data: [DONE] |
Verify the key and model before streaming
Start with GET /v1/models. Copy an exact model ID visible to your key, then run one short non-streaming request. This separates authentication and model routing errors from stream parsing problems.
curl -sS https://monkeytheme.com/v1/models \ -H "Authorization: Bearer $OPENAI_API_KEY"
On August 3, 2026, unauthenticated POST probes with stream: true reached both /v1/responses and /v1/chat/completions and returned structured 401 API_KEY_REQUIRED. That verifies authentication-layer routing only. It does not prove authenticated streaming for every model.
Stream with the Python SDK
The official Python SDK supports stream=True. The Responses example below prints text delta events and keeps other event types explicit.
from openai import OpenAI
client = OpenAI(
api_key="YOUR_KEY",
base_url="https://monkeytheme.com/v1",
)
stream = client.responses.create(
model="MODEL_ID_FROM_LIST",
input="Write one short sentence.",
stream=True,
)
for event in stream:
if event.type == "response.output_text.delta":
print(event.delta, end="", flush=True)
elif event.type == "error":
print("\nstream error:", event)For Chat Completions, iterate over chunks and read chunk.choices[0].delta.content. Do not use the Responses event parser on Chat Completions output.
Stream with the Node.js SDK
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: "https://monkeytheme.com/v1",
});
const stream = client.responses.stream({
model: "MODEL_ID_FROM_LIST",
input: "Write one short sentence.",
});
stream.on("response.output_text.delta", (event) => {
process.stdout.write(event.delta);
});
await stream.finalResponse();The official Node SDK also has a Chat Completions stream runner. Treat it as a separate response format rather than renaming fields until the code compiles.
Use curl to inspect the raw SSE boundary
curl -N https://monkeytheme.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"model": "MODEL_ID_FROM_LIST",
"input": "Reply with OK",
"stream": true
}'-N disables curl output buffering. If curl shows incremental events but an application does not, inspect the application's parser and any proxy between it and the gateway.
Proxy checks for stalled streams
Nginx documents proxy_buffering off as passing the upstream response to the client synchronously as it arrives. Its proxy_read_timeout applies between successive reads, not to the total response time.
location /v1/ {
proxy_pass http://your_upstream;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 300s;
}Diagnose the symptom, not just the status
| Symptom | Likely layer to inspect |
|---|---|
| 401 before any event | Key, Authorization header and gateway authentication |
| 404 before any event | Base URL, duplicated /v1 or unsupported endpoint |
| Events arrive in one batch | Client output buffering or reverse-proxy buffering |
| Stream stops after a quiet interval | Read timeout between upstream reads; collect timestamps and request IDs |
| Text duplicates after reconnect | Application retry/reconnect logic; do not assume a stream can resume from an arbitrary byte |
Sources and related guides
FAQ
Does streaming use WebSocket?
This guide covers HTTP streaming with server-sent events. WebSocket is not required for the Responses or Chat Completions examples shown here.
Why does the output arrive all at once?
First run curl with -N. If curl streams but the application does not, inspect client-side buffering. If neither streams, inspect reverse-proxy buffering and the upstream response.
Can I parse Responses and Chat Completions the same way?
No. Responses emits typed events such as response.output_text.delta. Chat Completions places incremental text in choices[0].delta.content.
Does a 401 prove that streaming is unsupported?
No. A structured 401 is an authentication failure before model output begins. Fix the key or header, then test streaming with a model returned to that key.
Does this page confirm every MonkeyAI model can stream?
No. The public probe verifies that both endpoint paths reach the authentication layer. Authenticated stream support must be tested with the exact model and endpoint you plan to use.