API reference
The Nicrron API
OpenAI-compatible, so the official OpenAI SDKs work with only the base URL and key changed. This page lists what the gateway accepts and returns.
Also as an OpenAPI 3.1 file, and the whole docs index for language models at /llms.txt.
Base URL and keys
Send every request to https://api.nicrron.ai/v1 with your key in the Authorization header. Each path also answers under /api/v1. Keys are made in the dashboard; see Authentication for provider keys.
Authorization: Bearer sk-af-…Endpoints
- POST/v1/chat/completionsChat, with routing, fallback, caching and streaming.
- GET/v1/modelsEvery model with context length and prices. No key needed.
- POST/v1/embeddingsEmbeddings, with the same fallback list as chat.
- POST/v1/audio/speechText to speech.
- POST/v1/audio/transcriptionsSpeech to text (Whisper), files up to 26 MB.
- POST/v1/videos/generationsStart a video job. Answers 202 with a job id.
- POST/v1/images/generationsStart an image job. Answers 202 with a job id.
- GET/v1/videos/generations/{id}A job's status; …/content downloads the result.
- GET/v1/generation?id=Cost, tokens and timing of one finished request.
- GET/v1/keyThe calling key: spend, limit, rate limit and balance.
Chat completions
POST /v1/chat/completions takes the OpenAI request body plus models and provider. Fields not listed here are accepted without checks.
- modelstring
- A model id such as anthropic/claude-sonnet-5-5, or a routing slug: nicrron/auto, nicrron/reasoning, nicrron/coding, nicrron/fastest, nicrron/cheapest. At most 256 characters.
- modelsstring[]
- Fallback models, tried in order after model. At most 10.
- messagesobject[]
- Required, at least one. role is system, user, assistant or tool; content is a string, an array of content parts (text, image_url) or null; name, tool_call_id and tool_calls as in the OpenAI API.
- streamboolean
- Send the answer as server-sent events. See Streaming.
- max_tokensinteger
- Upper bound on generated tokens. Greater than 0.
- temperaturenumber
- 0 to 2. A temperature of 0 also turns the response cache on.
- top_pnumber
- 0 to 1.
- stopstring | string[]
- Stop sequences.
- frequency_penaltynumber
- Passed to the provider.
- presence_penaltynumber
- Passed to the provider.
- seedinteger
- Passed to providers that support it.
- tools, tool_choicearray, any
- Function calling, in the OpenAI format.
- response_formatobject
- For example { "type": "json_object" }.
- providerobject
- Which providers may serve the request, and in what order. See Provider routing.
- userstring
- Your own end-user id.
| Field | Type | What it does |
|---|---|---|
| model | string | A model id such as anthropic/claude-sonnet-5-5, or a routing slug: nicrron/auto, nicrron/reasoning, nicrron/coding, nicrron/fastest, nicrron/cheapest. At most 256 characters. |
| models | string[] | Fallback models, tried in order after model. At most 10. |
| messages | object[] | Required, at least one. role is system, user, assistant or tool; content is a string, an array of content parts (text, image_url) or null; name, tool_call_id and tool_calls as in the OpenAI API. |
| stream | boolean | Send the answer as server-sent events. See Streaming. |
| max_tokens | integer | Upper bound on generated tokens. Greater than 0. |
| temperature | number | 0 to 2. A temperature of 0 also turns the response cache on. |
| top_p | number | 0 to 1. |
| stop | string | string[] | Stop sequences. |
| frequency_penalty | number | Passed to the provider. |
| presence_penalty | number | Passed to the provider. |
| seed | integer | Passed to providers that support it. |
| tools, tool_choice | array, any | Function calling, in the OpenAI format. |
| response_format | object | For example { "type": "json_object" }. |
| provider | object | Which providers may serve the request, and in what order. See Provider routing. |
| user | string | Your own end-user id. |
curl https://api.nicrron.ai/v1/chat/completions \
-H "Authorization: Bearer $NICRRON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nicrron/coding",
"models": ["openai/gpt-6-sol"],
"messages": [
{ "role": "system", "content": "Answer in one sentence." },
{ "role": "user", "content": "What does a 502 mean?" }
],
"max_tokens": 200,
"provider": { "sort": "latency" }
}'The answer is an OpenAI chat.completion. model is the model that actually answered and provider who served it. The id is also sent as the x-request-id header, and is the id for /v1/generation. When the provider reports prompt caching, usage also carries cache_read_tokens and cache_write_tokens.
{
"id": "gen-6f1c2a9e-…",
"object": "chat.completion",
"created": 1792345678,
"model": "anthropic/claude-opus-5-5",
"provider": "anthropic",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "A 502 means …" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 31,
"total_tokens": 55
}
}Provider routing and fallback
A request is tried model by model (model, then models, with routing slugs expanded) and, within a model, endpoint by endpoint. It moves on when a provider rate-limits or fails before answering. Limits per request: 8 models after expansion, 6 endpoint attempts, and 90 seconds for something to answer. Without a provider object, traffic is spread over healthy endpoints and unhealthy ones are tried last.
- orderstring[]
- Try these providers first, in this order; the rest follow.
- onlystring[]
- Use only these providers.
- ignorestring[]
- Never use these providers.
- sort"price" | "latency" | "throughput"
- Order the endpoints by blended price, measured latency or tokens per second. Healthy endpoints always come before unhealthy ones.
- allow_fallbacksboolean
- false tries one endpoint per model instead of moving on to the next provider.
| Field | Type | What it does |
|---|---|---|
| order | string[] | Try these providers first, in this order; the rest follow. |
| only | string[] | Use only these providers. |
| ignore | string[] | Never use these providers. |
| sort | "price" | "latency" | "throughput" | Order the endpoints by blended price, measured latency or tokens per second. Healthy endpoints always come before unhealthy ones. |
| allow_fallbacks | boolean | false tries one endpoint per model instead of moving on to the next provider. |
Response caching
A request with temperature: 0, or with the header x-nicrron-cache: true, is answered from cache when the identical request was answered before for your account. x-nicrron-cache: false turns it off. Every chat response carries x-nicrron-cache: HIT or MISS; a hit costs nothing and shows in your logs as cached. Answers that call tools, and streams that broke, are never cached.
Streaming
With stream: true the answer arrives as server-sent events of chat.completion.chunk. The last chunk has empty choices and the final usage, then data: [DONE]. If the provider stops partway, a chunk with an error (code 502) and finish_reason: "error" comes first; the part already generated is billed. Closing the connection stops generation upstream.
data: {"id":"gen-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"A 502"}}]}
data: {"id":"gen-…","object":"chat.completion.chunk","model":"anthropic/claude-opus-5-5","provider":"anthropic","choices":[],"usage":{"prompt_tokens":24,"completion_tokens":31,"total_tokens":55}}
data: [DONE]Rate limits and credits
Each key has a per-minute request limit: 60 unless the key was given its own. The window is the calendar minute. Every authenticated response carries x-ratelimit-limit and x-ratelimit-remaining; a 429 also carries retry-after in seconds. A key can also have a lifetime spend limit, after which it answers 403.
Prices are each provider's list price. Requests paid from credits add a 5% platform fee; requests that use your own provider key (BYOK) are charged 5% of the list price. Requests need a positive balance. A prompt is refused with 402 if the prompt alone would cost more than your balance plus $1, so one large request can't run an account far below zero. Accounts with auto top-up are charged afterwards instead.
Errors
Errors come back with an HTTP status and a JSON body. Chat and key errors carry error.code; embeddings, audio and media errors carry error.type (for example invalid_request_error, insufficient_quota).
{
"error": {
"message": "Rate limit exceeded (60 requests/min)",
"code": 429
}
}| 400 | The body is invalid; no model was given; more than 10 fallback models; a model id over 256 characters; or the prompt is longer than the model's context window. |
|---|---|
| 401 | The Authorization header is missing, or the key is invalid or disabled. |
| 402 | The balance is used up, or this prompt alone would cost more than the balance allows. Add credits. |
| 403 | The account is suspended, or the key has reached its spend limit. |
| 404 | No such model (or media job). |
| 429 | The key's per-minute rate limit is used up (see retry-after), or a provider rate-limited a request with no fallback left. |
| 502 | Every provider in the fallback chain failed, or a provider rejected the request. The message says which. |
| 503 | Media or audio generation is not available right now. You were not charged. |
List models
GET /v1/models needs no key. Prices are US dollars per token, as strings. Media and audio models are listed too; the catalog page shows the same list per million tokens. Prices are each provider's list price. Requests paid from credits add a 5% platform fee.
{
"data": [
{
"id": "anthropic/claude-sonnet-5-5",
"name": "Anthropic: Claude Sonnet 5.5",
"modality": "chat",
"context_length": 1000000,
"pricing": { "prompt": "0.000003", "completion": "0.000015" },
"providers": ["anthropic"]
}
]
}Look up a generation
GET /v1/generation?id=gen-… returns what one request cost (including the platform fee) and how long it took, for your own requests only. Right after a request it can answer 404 for a moment while billing settles.
{
"data": {
"id": "gen-6f1c2a9e-…",
"model": "anthropic/claude-opus-5-5",
"provider_name": "anthropic",
"tokens_prompt": 24,
"tokens_completion": 31,
"total_cost": 0.00089,
"latency": 1840,
"time_to_first_token": 420,
"streamed": false,
"created_at": "2026-10-18T21:04:05.000Z"
}
}The current key
GET /v1/key describes the key that called it: its label, lifetime spend in dollars, its spend limit (or null), its rate limit, and the account balance.
{
"data": {
"label": "production",
"usage": 12.4815,
"limit": 100,
"rate_limit": { "requests": 60, "interval": "1m" },
"balance": 87.52
}
}