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 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.

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.

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.