Chat Completions¶
POST /chat/completions is the core of the Blaick API. You send a list of messages and a model, and you get back a model response — either all at once (JSON) or streamed token by token (Server-Sent Events).
Request body¶
{
"model_id": "claude-sonnet-4-20250514",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
"stream": false,
"temperature": 0.7,
"max_tokens": 4096,
"conversation_id": null,
"auto_route": false
}
| Field | Type | Required | Description |
|---|---|---|---|
model_id |
string | Yes | The model to use. Accepts a model UUID or a provider model id from GET /models. |
messages |
array | Yes | The conversation so far. Each item has a role (system, user, or assistant) and content. |
stream |
boolean | No | Stream the response as SSE. Defaults to false. See Streaming. |
temperature |
number | No | Sampling temperature. Higher is more random. Defaults to 0.7. |
max_tokens |
integer | No | Maximum tokens to generate in the response. Defaults to 4096. |
conversation_id |
string | null | No | Attach this exchange to an existing conversation. If omitted or null, a new conversation is created and its id is returned. |
auto_route |
boolean | No | Let Blaick pick the cheapest capable model instead of model_id. See Auto-routing. |
Messages¶
messages is an ordered list. Use roles to structure the exchange:
system— instructions that shape behavior. Optional; put it first if you use it.user— input from the user.assistant— a previous model reply, when you're managing history yourself.
"messages": [
{"role": "system", "content": "You translate English to French. Reply only with the translation."},
{"role": "user", "content": "Good morning"}
]
Two ways to keep context
You can send the full messages history on every request, or let Blaick store it for you with a conversation. With a conversation_id, you only need to send the newest user message.
Non-streaming response¶
With stream omitted or false, you get a single JSON object:
{
"id": "c0ffee00-0000-4000-8000-000000000000",
"conversation_id": "11111111-2222-4333-8444-555555555555",
"model_id": "claude-sonnet-4-20250514",
"content": "The capital of France is Paris.",
"usage": {
"input_tokens": 18,
"output_tokens": 8,
"total_tokens": 26,
"cost_tokens": 52
},
"created_at": "2026-08-04T10:00:00Z",
"auto_routed": false,
"provider_metadata": {
"provider": "anthropic",
"failback_used": false,
"latency_ms": 640
}
}
| Field | Description |
|---|---|
id |
Unique id for this response message. |
conversation_id |
The conversation this exchange belongs to (created for you if you didn't pass one). |
model_id |
The model that actually served the request — may differ from your request if auto-routing or failback kicked in. |
content |
The generated text. |
usage |
Token counts. cost_tokens is what was billed. See Usage & Tokens. |
created_at |
ISO 8601 timestamp. |
auto_routed |
Whether the auto-router chose the model. |
provider_metadata |
Which upstream provider served it, whether a failback occurred, and latency. |
Full example¶
curl https://api.blaick.ai/api/v1/chat/completions \
-H "Authorization: Bearer $BLAICK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model_id": "claude-sonnet-4-20250514",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
"max_tokens": 100
}'
import os, requests
BASE = "https://api.blaick.ai/api/v1"
headers = {"Authorization": f"Bearer {os.environ['BLAICK_API_KEY']}"}
resp = requests.post(
f"{BASE}/chat/completions",
headers=headers,
json={
"model_id": "claude-sonnet-4-20250514",
"messages": [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "What is the capital of France?"},
],
"max_tokens": 100,
},
)
resp.raise_for_status()
data = resp.json()
print(data["content"])
const BASE = "https://api.blaick.ai/api/v1";
const resp = await fetch(`${BASE}/chat/completions`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BLAICK_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model_id: "claude-sonnet-4-20250514",
messages: [
{ role: "system", content: "You are a concise assistant." },
{ role: "user", content: "What is the capital of France?" },
],
max_tokens: 100,
}),
});
const data = await resp.json();
console.log(data.content);
Auto-routing¶
Set auto_route: true and Blaick analyzes your prompt and picks the cheapest model that can handle it — a small model for a simple question, a larger one for hard reasoning. You still pass a model_id as the ceiling/fallback.
{
"model_id": "claude-sonnet-4-20250514",
"messages": [{"role": "user", "content": "What's 2 + 2?"}],
"auto_route": true
}
When the router changes the model, the response reflects it:
{
"content": "4",
"model_id": "a-cheaper-model",
"auto_routed": true,
"routing_reason": "Simple arithmetic — handled by a lower-tier model.",
"task_type": "simple_qa"
}
To preview what the router would do without spending tokens on a full completion, use POST /chat/triage or POST /chat/auto-route.
Errors to handle¶
Chat completions can return:
402— out of tokens or subscription past due403— the model isn't available on your plan (common on trial)429— rate limited503— the model is temporarily unavailable
See Errors & Rate Limits for the full list and retry guidance.