DocumentationBrowse
Streaming
Set "stream": true for text/event-stream. The framing is OpenAI-style: data: lines separated by blank lines, terminated by data: [DONE]. Three things differ from a plain OpenAI stream, and all three matter when you write a client.
"stream": trueWhere the metadata lives
| Frame | Carries |
|---|---|
| First | An empty role delta with docketrouter holding everything except the verification report: sources, injection, degraded, jurisdiction, session_id, request_id. Read your grounding metadata here, before any text arrives. |
| Middle | Ordinary content deltas. |
| Last | finish_reason, usage including cost, and docketrouter.verification. |
| Terminator | data: [DONE] |
data: {"id":"chatcmpl-fae913ea-4bd","object":"chat.completion.chunk","created":1787855024,
"model":"deepseek/deepseek-v4-flash",
"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}],
"docketrouter":{"sources":{"rules":[…],"cases":[…],"citations":[],"ms":1902},
"injection":null,"degraded":null,"upstream":"openrouter","juiced":true,
"data_policy":"shared","jurisdiction":"tx","session_id":null,
"request_id":"req_7a77ac20c65741338811"}}
data: {"id":"chatcmpl-fae913ea-4bd",…,"choices":[{"index":0,"delta":{"content":"Rule 11 "},"finish_reason":null}]}
…
data: {"id":"chatcmpl-fae913ea-4bd",…,"choices":[{"index":0,"delta":{},"finish_reason":"stop"}],
"usage":{"prompt_tokens":2451,"completion_tokens":79,"total_tokens":2530,"cost":0.00022462},
"docketrouter":{"verification":{"checked":[],"fabricated":[],"unverified":[],"revised":false}}}
data: [DONE]The response also carries x-docketrouter-request-id in the HTTP headers, which arrive before the first frame. Log it there and you have the handle even if the stream dies mid-flight.
The three differences
1. The revise pass never runs
Citations in the answer are still checked, but the text has already left the building, so there is nothing to rewrite. verification.revised is always false on a streamed response. If you want automatic repair of a fabricated citation, do not stream.
Staying silent about a fabrication would ship the exact failure this product exists to prevent, so instead the warning is appended to the stream itself as a final content delta, where a human will actually see it:
[DocketRouter: citation check failed. These citations could not be found in the reporters and appear fabricated: 999 U.S. 1234. Do not rely on them. Streamed answers cannot be auto-corrected; re-run this request without stream to get a repaired answer.]
That text is part of content, so a client that renders raw deltas gets it for free. A client that renders structured output should detect it from verification.fabricated in the final frame instead and present it properly.
2. An upstream failure does not change the status
The HTTP status is already 200 by the time the model is called. A mid-stream failure arrives as a content delta reading [upstream error; request_id req_…] with finish_reason: "error". There is no usage frame and no verification report in that case. Check for the finish reason explicitly.
3. The timeout is longer
A streaming request is given 120 seconds, against 90 for a non-streaming one. Grounding runs before the first frame, so time to first token includes retrieval, typically one to three seconds.
Clients
curl -N https://docketrouter.ai/api/v1/chat/completions \
-H "Authorization: Bearer dr-…" \
-H "content-type: application/json" \
-d '{
"model": "deepseek/deepseek-v4-flash",
"stream": true,
"max_tokens": 600,
"messages": [{ "role": "user", "content": "One sentence: what is Rule 11 about?" }]
}'A single frame can span several reads, and a single read can contain several frames. The buffer-and-split pattern above is the whole trick. Splitting on \n will corrupt long JSON frames, and the first frame is the longest one in the stream because it carries every retrieved excerpt.
When not to stream
- When a fabricated citation must be repaired rather than reported. Only non-streaming requests run the revise pass.
- When you are writing to a store rather than to a screen. Batch work gains nothing from streaming and loses the automatic repair.
- When your transport buffers. Some proxies and serverless edges buffer
text/event-streamuntil the response completes, which gives you all the downside and none of the latency benefit.
A worked example that streams to the user and still enforces the verification gate is in Recipes.
Something here wrong or missing? Mail hello@docketrouter.ai with the request_id and we will fix the docs or the API, whichever is broken.