API reference
The public HTTP surface for AnonRouter integrations.
The production API base URL is:
https://api.anonrouter.ai/v1Requests authenticate one of three ways, depending on the endpoint:
- Inference key (
ar_) inAuthorization: Bearerto issue tickets and, in compatibility mode, to call inference directly. - Management key (
arm_) inAuthorization: Bearerto read balance and usage. - Inference ticket in the
x-anonrouter-ticketheader to run a single ticketed request.
Some account and billing operations require an authenticated session and are performed from the dashboard rather than with an API key.
Inference
| Method | Endpoint | Credential | Description |
|---|---|---|---|
GET | /models | Inference or management key | List enabled models and capabilities |
GET | /catalog/models | None | Public, cacheable catalog with privacy metadata |
GET | /models/uptime | None | Passive success-rate and latency series |
POST | /inference/tickets | Inference key | Issue a single-use inference ticket |
POST | /chat/completions | Ticket | Create a streaming or non-streaming chat completion |
POST | /embeddings | Ticket | Create vector embeddings |
POST | /images/generations | Ticket | Generate an image (when enabled) |
POST | /audio/speech | Inference key | Synthesize speech (when enabled) |
GET | /capabilities | None | Report enabled feature flags |
In compatibility mode, /chat/completions and
/embeddings accept an inference key directly instead of a ticket.
Routing
| Method | Endpoint | Credential | Description |
|---|---|---|---|
GET | /routing/effective | Inference key | List models the saved preferences allow |
GET | /routing/preferences | Session | Read saved routing preferences |
PUT | /routing/preferences | Session | Replace saved routing preferences |
POST | /routing/preview | Session | Preview a routing decision |
POST | /routing/eligible-models | None | List models eligible for draft preferences |
Account
| Method | Endpoint | Credential | Description |
|---|---|---|---|
GET | /balance | Management key | Read available and reserved balance |
GET | /usage | Management key | Read recent usage metadata |
Workspaces
| Method | Endpoint | Credential | Description |
|---|---|---|---|
GET | /workspaces | Session | List workspaces |
POST | /workspaces | Session | Create a workspace |
PATCH | /workspaces/:id | Session | Edit a workspace |
DELETE | /workspaces/:id | Session | Delete a workspace |
Billing
| Method | Endpoint | Credential | Description |
|---|---|---|---|
GET | /billing/catalog | Session | Packages, limits, fee, and terms |
GET | /billing/orders | Session | List purchase orders |
GET | /billing/orders/:orderId | Session | Poll one order |
GET | /billing/receipts | Session | List receipts |
GET | /billing/receipts/:receiptNumber | Session | Fetch one receipt |
Response headers
Successful inference responses include:
x-anonrouter-selected-model: the chosenprovider/model.x-anonrouter-routing:autoorexact.x-ratelimit-limit-requests,x-ratelimit-remaining-requests,x-ratelimit-reset-requests, and the matching-tokensvariants.
Errors
Errors use an OpenAI-style envelope with a machine-readable type and a
request_id:
{
"error": {
"message": "Inference ticket is invalid or expired",
"type": "invalid_ticket",
"request_id": "req_..."
}
}Common cases:
| Status | type | Meaning |
|---|---|---|
401 | ticket_required | A ticket is required and none was sent |
401 | invalid_ticket | The ticket is invalid, expired, or already used |
403 | insufficient_scope | The credential lacks the required scope |
402 | insufficient_balance | Not enough prepaid balance |
404 | model_not_found | The model is unknown or not enabled |
409 | ticket_model_mismatch | The request model differs from the ticket |
409 | ticket_reasoning_mismatch | The reasoning selection differs from the ticket |
429 | rate_limited | Rate limit exceeded; see retry-after |
503 | media_disabled | Image or speech is not enabled on this deployment |
A 429 response also sets a retry-after header. During streaming, a mid-stream
provider failure is delivered as an inline SSE error frame rather than an HTTP
status, because the response headers have already been sent.