Introduction
CanRouter is an API gateway that puts many AI models behind one OpenAI-compatible endpoint. You keep a single prepaid balance (in US dollars), and every request you make is metered at the exact published rate of the model you call. Your dashboard shows token usage, cost, latency, and status for every request — nothing more is stored.
Quick Start
- Create an account. Registration takes under a minute and needs only an email, username, and password.
- Add funds. Top up your balance from the dashboard. Funds are applied only after payment is verified.
- Create an API key. Keys are shown once at creation and stored hashed — keep the secret safe and rotate it any time.
- Make requests. Point any OpenAI-compatible client at our gateway endpoint.
Authentication
Gateway requests authenticate with an API key sent as a bearer token:
Authorization: Bearer canr_sk_...
The dashboard itself uses secure session cookies with CSRF protection — the same key never serves both.
SDK Examples
Because the gateway is OpenAI-compatible, popular SDKs work by changing only the base URL and key. Full examples:
cURL
curl https://api.canrouter.ai/v1/chat/completions \
-H "Authorization: Bearer $CANROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "canrouter-core",
"messages": [{"role": "user", "content": "Hello"}]
}'JavaScript / TypeScript
// Install the official OpenAI SDK, then point it at CanRouter:
// npm install openai
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.CANROUTER_API_KEY,
baseURL: "https://api.canrouter.ai/v1",
});
const completion = await client.chat.completions.create({
model: "canrouter-core",
messages: [{ role: "user", content: "Hello" }],
});
console.log(completion.choices[0].message.content);Python
# pip install openai
from openai import OpenAI
client = OpenAI(
api_key="your-canrouter-api-key",
base_url="https://api.canrouter.ai/v1",
)
completion = client.chat.completions.create(
model="canrouter-core",
messages=[{"role": "user", "content": "Hello"}],
)
print(completion.choices[0].message.content)PHP
// composer require openai-php/client
use OpenAI\Client;
$client = OpenAI::factory()
->withApiKey('your-canrouter-api-key')
->withBaseUri('api.canrouter.ai/v1')
->make();
$result = $client->chat()->create([
'model' => 'canrouter-core',
'messages' => [
['role' => 'user', 'content' => 'Hello'],
],
]);
echo $result->choices[0]->message->content;Streaming
Chat completions stream server-sent events (SSE) when stream: true is set. Chunks use the standard chat.completion.chunk shape and finish with a [DONE] sentinel. Token usage is metered from the stream exactly like a non-streaming call.
const stream = await client.chat.completions.create({
model: "canrouter-core",
messages: [{ role: "user", content: "Tell me a story" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}Embeddings
Embedding models in the catalog are available through POST /v1/embeddings with the standard OpenAI request shape. Embeddings are billed per input token at the published model rate.
const response = await client.embeddings.create({
model: "canrouter-embed",
input: ["The gateway routes many models behind one API."],
});
console.log(response.data[0].embedding.length, "dimensions");Idempotency
Send an Idempotency-Key header (up to 64 characters) to guarantee a request is processed only once. If a key is reused, the gateway returns idempotency_conflict instead of executing (and charging) the upstream call a second time — safe retries never double-bill.
Error reference
Every error response uses one consistent envelope, so your integration can handle failures in a single code path:
{
"error": {
"message": "Insufficient account balance.",
"type": "billing_error",
"code": "insufficient_balance",
"request_id": "req_9f2c..."
}
}| Code | Meaning |
|---|---|
authentication_error | 401 — missing or invalid API key |
invalid_request | 400 — malformed payload or unsupported parameters |
model_unavailable | 404 — model is not in the catalog or has no active provider |
rate_limited | 429 — account, key, or endpoint limit exceeded |
insufficient_balance | 402 — not enough prepaid balance for the call |
provider_error | 502 — the upstream provider failed after retries/failover |
timeout | 504 — the upstream provider did not respond in time |
idempotency_conflict | 409 — the Idempotency-Key was already used |
internal_error | 500 — unexpected platform error; retry with a new key |
The request ID is your reference when contacting support.
Rate limits
Requests are rate-limited per account and per API key to keep the platform fair and stable. When a limit is hit, the API responds with a rate_limited error and a 429 status. Limits can be configured per key from the dashboard.
Gateway endpoints
| Endpoint | Description |
|---|---|
POST /v1/chat/completions | Chat completions (stream + non-stream) |
POST /v1/completions | Legacy text completions (prompt in, text out) |
POST /v1/embeddings | Embedding vectors for catalog embedding models |
POST /v1/images/generations | Text-to-image generation (per-image billing) |
POST /v1/images/edits | Image editing / inpainting (multipart) |
POST /v1/audio/speech | Text-to-speech (returns audio bytes) |
POST /v1/audio/transcriptions | Speech-to-text (multipart audio) |
POST /v1/audio/translations | Audio translation (multipart audio) |
POST /v1/responses | OpenAI Responses API |
POST /v1/rerank | Search-result reranking (Jina/Cohere-style) |
POST /v1/moderations | Content safety moderation |
POST /v1/videos/generations | Text-to-video (async task) |
GET /v1/videos/generations/{id} | Poll a video task's status |
POST /v1/messages | Anthropic Messages API compatibility |
POST /v1beta/models/{m}:generateContent | Native Gemini format |
POST /v1beta/models/{m}:streamGenerateContent | Native Gemini streaming |
POST /v1beta/models/{m}:countTokens | Native Gemini token counting (free) |
GET /v1/models | List public models available on the gateway |
GET /v1/usage | Your recent usage records |
GET /v1/logs | Your request log with filters |
GET /v1/account/credits | Current prepaid balance |
POST/GET/DELETE /v1/account/api-keys | Manage gateway API keys |
POST /v1/account/topup | Create a top-up checkout session |
GET/POST /v1/support/tickets | Open and list support tickets |
POST /replicate/v1/models/{o}/{m}/predictions | Replicate prediction (async task) |
GET /replicate/v1/predictions/{id} | Poll Replicate task status |
POST/GET/DELETE /v1/files | File storage for Assistants/Batches |
GET /v1/files/{id}/content | Download file content |
POST /v1/batches | Create batch job (async) |
GET /v1/batches/{id} | Get batch status |
POST /v1/batches/{id}/cancel | Cancel a batch |
WS /v1/realtime | Realtime WebSocket (voice) |
POST /suno/* | Suno music generation (passthrough) |
All gateway endpoints authenticate with Authorization: Bearer canr_sk_.... The Anthropic compatibility layer additionally accepts x-api-key, and the Gemini layer accepts x-goog-api-key, matching the native SDKs. Models can be prefixed with new- to resolve a model redirect for client compatibility.
Native SDK formats
In addition to the OpenAI-compatible protocol, the gateway speaks the Anthropic Messages format (/v1/messages) and the native Gemini format (/v1beta/models/:model:generateContent), so you can point the official Anthropic and Gemini SDKs at CanRouter without writing translation code.
Replicate API
The gateway proxies the Replicate API for image and video models (FLUX, Stable Diffusion, Kling, etc.). Use your CanRouter API key with the Replicate-compatible endpoint:
curl -X POST "https://api.canrouter.ai/replicate/v1/models/black-forest-labs/flux-schnell/predictions" \
-H "Authorization: Bearer $CANROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input": {"prompt": "A cat riding a skateboard"}}'Prediction results are relayed verbatim. GET requests for status polling are free of charge; POST requests are billed per-request.
Suno Music
Suno music generation is available via the vendor passthrough at /suno/. Send a Suno-compatible request with your CanRouter API key:
curl -X POST "https://api.canrouter.ai/suno/v1/chat/completions" \
-H "Authorization: Bearer $CANROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "chirp-v4", "messages": [{"role": "user", "content": "An upbeat pop song"}]}'File storage
The /v1/files endpoint stores files for use with the Assistants API and Batches. Upload a file with a purpose tag, then reference it by ID in your assistant or batch requests. Files are scoped to your account and accessible only with your API key.
Batches
The Batches API lets you run many requests asynchronously. Upload a JSONL input file via /v1/files, then create a batch pointing at an endpoint (e.g. /v1/chat/completions). Results are written to output and error files you can download.