Introduction
CanalAPI is a unified gateway over 600+ LLM, image, and audio models. Use any OpenAI-compatible client — point base_url at https://api.canalapi.com/v1, pass your key, and ship.
Quickstart
You need two things: an API key (from the console) and a model slug. Here's the simplest possible request:
# Any OpenAI-compatible client works — just swap the base URL
curl https://api.canalapi.com/v1/chat/completions \
-H "Authorization: Bearer $CANAL_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-4-sonnet",
"messages": [{"role":"user","content":"Hello"}]
}'Response
{
"id": "chatcmpl_8K2m3",
"object": "chat.completion",
"created": 1745078400,
"model": "claude-4-sonnet",
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Hi there!" },
"finish_reason": "stop"
}],
"usage": { "prompt_tokens": 8, "completion_tokens": 3, "total_tokens": 11 }
}Authentication
Pass your key via the Authorization: Bearer ... header. Keys are scoped — create separate keys per environment (dev / staging / prod) from the console.
Chat completionsPOST/v1/chat/completions
Create a chat completion. Compatible with OpenAI's chat/completions — same parameters, same response shape.
Request body
| Field | Type | Description |
|---|---|---|
| modelrequired | string | Model slug, e.g. claude-4-sonnet, gpt-4o. See full model list. |
| messagesrequired | array | Conversation as an array of { role, content } objects. Roles: system, user, assistant. |
| streamoptional | boolean | If true, returns tokens as SSE. Default false. |
| temperatureoptional | number | 0–2. Higher = more random. Default 1. |
| max_tokensoptional | integer | Cap on completion tokens. Model-dependent default. |
| toolsoptional | array | Tool definitions for function calling. |
Streaming example
stream = client.chat.completions.create(
model="claude-4-sonnet",
messages=[{"role": "user", "content": "Write a haiku."}],
stream=True,
)
for chunk in stream:
print(chunk.choices[0].delta.content or "", end="")Errors & retries
CanalAPI uses conventional HTTP status codes. On 5xx upstream failures we auto-retry across healthy channels — you only see an error after the routing pool is exhausted.
| Code | Meaning | What to do |
|---|---|---|
| 400 | bad_request | Check request body — likely a bad model or malformed messages. |
| 401 | unauthenticated | Missing / revoked key. Create a new one in the console. |
| 402 | insufficient_balance | Top up your balance, then retry. |
| 429 | rate_limited | Back off per Retry-After header. |
| 502/503 | upstream_error | Already retried — raise a support ticket if persistent. |
SDKs
Official SDKs wrap retries, streaming, and error normalization. Under the hood they're thin wrappers over the HTTP API.
pip install canalapinpm i @canalapi/sdkgo get canalapi/canal-go