Using the API
Streaming
Streamed responses use server-sent events with the same chunk shape as OpenAI, so existing stream handling works unchanged.
Requesting a stream
Set stream to true. The response is text/event-stream, and each event carries one JSON chunk.
curl -N https://api.openbase.ai/v1/chat/completions \
-H "Authorization: Bearer $OPENBASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "xai/grok-4.6",
"messages": [{"role": "user", "content": "Count to three"}],
"stream": true
}'Chunk shape
Content arrives in the delta of the first choice. The stream ends with a chunk carrying a finish_reason, then a literal data: [DONE].
data: {"id":"chatcmpl-abc","object":"chat.completion.chunk","model":"xai/grok-4.6","provider":"xai","choices":[{"index":0,"delta":{"content":"One"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":8,"total_tokens":20}}
data: [DONE]Usage on close
Token counts are not known until the upstream finishes, so they appear on the final chunk rather than the first. Read usage from the chunk that also carries the finish reason.
Billing follows the stream
A request is settled when its stream closes. If the client disconnects mid-stream, the tokens already produced are still billed, because the provider has already charged for them.
Reading the stream yourself
Without an SDK, split on blank lines and parse each data payload.
const response = await fetch("https://api.openbase.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.OPENBASE_API_KEY}`,
},
body: JSON.stringify({ model, messages, stream: true }),
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const events = buffer.split("\n\n");
buffer = events.pop() ?? "";
for (const event of events) {
const data = event.replace(/^data: /, "").trim();
if (data === "[DONE]") return;
const chunk = JSON.parse(data);
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
}Errors mid-stream
- A failure before any bytes are sent returns a normal JSON error with the right status code.
- A failure after headers are flushed cannot change the status code, so an error envelope is written as a final event and the stream is closed.