Documentation

Everything you need to integrate with CanRouter.

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

  1. Create an account. Registration takes under a minute and needs only an email, username, and password.
  2. Add funds. Top up your balance from the dashboard. Funds are applied only after payment is verified.
  3. Create an API key. Keys are shown once at creation and stored hashed — keep the secret safe and rotate it any time.
  4. 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 Anthropic and Gemini compatibility layers additionally accept their native SDK headers, so the official SDKs work without code changes:

ProtocolHeadersApplies to
OpenAI-compatibleAuthorization: Bearer canr_sk_...All /v1/* gateway endpoints
Anthropic Messagesx-api-key: canr_sk_...anthropic-version: 2023-06-01POST /v1/messages (Authorization: Bearer is also accepted)
Gemini nativex-goog-api-key: canr_sk_...POST /v1beta/models/{model}:generateContent and other /v1beta actions (Authorization: Bearer is also accepted)

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..."
  }
}
CodeMeaning
authentication_error401 — missing or invalid API key
invalid_request400 — malformed payload or unsupported parameters
model_unavailable404 — model is not in the catalog or has no active provider
rate_limited429 — account, key, or endpoint limit exceeded
insufficient_balance402 — not enough prepaid balance for the call
provider_error502 — the upstream provider failed after retries/failover
timeout504 — the upstream provider did not respond in time
idempotency_conflict409 — the Idempotency-Key was already used
internal_error500 — unexpected platform error; retry with a new key

The request ID is your reference when contacting support.

Troubleshooting

When a request fails or a client cannot connect, work through the matching checklist below — it covers the questions our support team sees most.

401 — authentication_error — missing or invalid API key

  • Send the key as "Authorization: Bearer canr_sk_..." (OpenAI-style), "x-api-key" (Anthropic /v1/messages), or "x-goog-api-key" (Gemini /v1beta) — exactly one of the documented schemes.
  • Use a key created on the dashboard Keys page; keys are shown once and can be rotated there.
  • Copy the key without leading/trailing whitespace or quotes, and confirm it starts with "canr_sk_".
  • A 401 from every request usually means the key was revoked or never activated — create a fresh key and retry.

404 — model_unavailable — model is not in the catalog or has no active provider

  • Check the model ID against the live catalog at https://www.canrouter.ai/models — the ID must match exactly.
  • Do not prepend vendor prefixes the catalog does not use; copy the ID verbatim.
  • If the model is listed as "not available at the moment", pick an active model in the same category.
  • Verify the endpoint path: /v1/chat/completions, /v1/messages, or /v1beta/models/{model}:generateContent — a wrong path also returns 404.

400 — invalid_request — malformed payload or unsupported parameters

  • Validate the JSON body: correct model field, required fields present, no trailing commas.
  • For Anthropic /v1/messages, "max_tokens" is required and the first message must not have role "assistant".
  • Remove parameters the target endpoint does not support.
  • Send "Content-Type: application/json".

429 — rate_limited — account, key, or endpoint limit exceeded

  • Slow down or add client-side retries with exponential backoff and jitter.
  • Check the per-key rate limits configured on the dashboard Keys page.
  • Batch or queue bursts instead of sending parallel floods.

5xx — 502 provider_error / 504 timeout / 500 internal_error — upstream or platform failure

  • Retry with exponential backoff; failover and retries are built in, but sustained upstream outages need a retry on the client.
  • For 500 internal_error, retry with a new Idempotency-Key (if used).
  • Check https://www.canrouter.ai/status for known incidents and announcements.
  • If it persists, open a support ticket from the dashboard and include the request_id from the error envelope.

Endpoint connectivity checklist

  • OpenAI-compatible clients: base URL is exactly https://api.canrouter.ai/v1 — do not double the /v1 suffix (SDK baseURL already includes /v1).
  • Anthropic SDK: base URL is https://api.canrouter.ai with no /v1 suffix — the SDK appends /v1/messages itself.
  • Gemini SDK: base URL is https://api.canrouter.ai — the SDK appends /v1beta/models/... itself.
  • Confirm outbound HTTPS (TCP 443) to api.canrouter.ai is not blocked by a firewall or proxy.
  • Confirm the account has a positive prepaid balance (GET /v1/account/credits).
  • Check https://www.canrouter.ai/status for known incidents before debugging further.
  • Full, always-current reference: https://www.canrouter.ai/documentation

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

EndpointDescription
POST /v1/chat/completionsChat completions (stream + non-stream)
POST /v1/completionsLegacy text completions (prompt in, text out)
POST /v1/embeddingsEmbedding vectors for catalog embedding models
POST /v1/images/generationsText-to-image generation (per-image billing)
POST /v1/images/editsImage editing / inpainting (multipart)
POST /v1/audio/speechText-to-speech (returns audio bytes)
POST /v1/audio/transcriptionsSpeech-to-text (multipart audio)
POST /v1/audio/translationsAudio translation (multipart audio)
POST /v1/responsesOpenAI Responses API
POST /v1/rerankSearch-result reranking (Jina/Cohere-style)
POST /v1/moderationsContent safety moderation
POST /v1/videos/generationsText-to-video (async task)
GET /v1/videos/generations/{id}Poll a video task's status
POST /v1/messagesAnthropic Messages API compatibility
POST /v1beta/models/{m}:generateContentNative Gemini format
POST /v1beta/models/{m}:streamGenerateContentNative Gemini streaming
POST /v1beta/models/{m}:countTokensNative Gemini token counting (free)
GET /v1/modelsList public models available on the gateway
GET /v1/usageYour recent usage records
GET /v1/logsYour request log with filters
GET /v1/account/creditsCurrent prepaid balance
POST/GET/DELETE /v1/account/api-keysManage gateway API keys
POST /v1/account/topupCreate a top-up checkout session
GET/POST /v1/support/ticketsOpen and list support tickets
POST /replicate/v1/models/{o}/{m}/predictionsReplicate prediction (async task)
GET /replicate/v1/predictions/{id}Poll Replicate task status
POST/GET/DELETE /v1/filesFile storage for Assistants/Batches
GET /v1/files/{id}/contentDownload file content
POST /v1/batchesCreate batch job (async)
GET /v1/batches/{id}Get batch status
POST /v1/batches/{id}/cancelCancel a batch
WS /v1/realtimeRealtime 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.

Anthropic Messages (cURL)

curl https://api.canrouter.ai/v1/messages \
  -H "x-api-key: $CANROUTER_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<model-id-from-catalog>",
    "max_tokens": 256,
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Gemini generateContent (cURL)

curl "https://api.canrouter.ai/v1beta/models/<model-id-from-catalog>:generateContent" \
  -H "x-goog-api-key: $CANROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contents": [{"parts": [{"text": "Hello"}]}]}'
  • Official Anthropic SDK: point it at CanRouter with base_url="https://api.canrouter.ai" and your CanRouter API key — the SDK sends x-api-key and anthropic-version automatically.
  • Official Gemini SDK: set the api_key to your CanRouter API key and base_url to "https://api.canrouter.ai" — the SDK sends x-goog-api-key automatically.

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.