Chat Completions
Authorization: Bearer lattice_sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxRequires an application API key. Subject to that application's model allowlist, monthly quota, and rate limit.
Request body
The body is validated as a strict object — any field not listed below causes 400 invalid_request, it is never silently dropped.
modelstring, requiredmessagesChatMessage[], required{ role: 'system' | 'user' | 'assistant', content: string }, content up to 32,000 characters. streamboolean, default falsetemperaturenumber, optional0 to 2.max_tokensinteger, optional>= 1. Also used as the upper bound for quota reservation before dispatch. top_pnumber, optionalstopstring | string[], optionaltype ProviderAdapter = {
id: ProviderId;
createChatCompletion(
request: ChatCompletionRequest,
ctx: ProviderRequestContext,
): Promise<ChatCompletionResponse>;
streamChatCompletion(
request: ChatCompletionRequest,
ctx: ProviderRequestContext,
): AsyncGenerator<ChatCompletionChunk, void, void>;
};
type ProviderRequestContext = {
apiKey?: string;
providerModel: string;
signal: AbortSignal;
};tools/tool_calls, n (multiple completions), logprobs, response_format, image/multimodal content. Sending any of these fails validation rather than being ignored, so a client finds out immediately rather than silently getting different behavior than expected. Non-streaming response
200 OK, content-type: application/json:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1755878400,
"model": "gpt-4o",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 42,
"completion_tokens": 118,
"total_tokens": 160
}
}finish_reason is one of 'stop' | 'length' | 'content_filter', normalized the same way across every provider — see Providers for how each upstream's native stop reason maps into these three.
Streaming
Set "stream": true. The response is text/event-stream; each event's data: payload is a JSON-encoded chunk, and the stream ends with a literal data: [DONE]:
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755878400,"model":"gpt-4o","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755878400,"model":"gpt-4o","choices":[{"index":0,"delta":{"content":"Sure"},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1755878400,"model":"gpt-4o","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":42,"completion_tokens":118,"total_tokens":160}}
data: [DONE]Chunk shape:
type ChatCompletionChunk = {
id: string;
object: 'chat.completion.chunk';
created: number;
model: string;
choices: [
{
index: number;
delta: { role?: 'assistant'; content?: string };
finish_reason: 'stop' | 'length' | 'content_filter' | null;
},
];
usage?: { prompt_tokens: number; completion_tokens: number; total_tokens: number } | null;
};usage is only present on the terminal chunk, and only when the upstream provider reports it there.
Errors
See the full table in Errors. The two most common on this endpoint beyond auth failures:
| Status | error.code | Cause |
|---|---|---|
403 | model_not_permitted | The application has an allowedModels list and this model isn't on it. |
429 | quota_exceeded | The application's monthly token quota is exhausted. |
429 | rate_limit_exceeded | The application's per-minute request limit is exceeded. |
404 | model_not_found | model doesn't match any registry id or alias. |
502 | all_providers_failed / provider_error | Every candidate provider failed. |