{"openapi":"3.1.0","info":{"title":"Rapid Router API","version":"1.0.0","description":"One API for many AI models. Inference endpoints (chat, messages, responses, embeddings, rerank, media, batches) authenticate with an API key (sk-rr-...); account endpoints (keys, audit) authenticate with a dashboard session JWT, and credits, usage and generation take either. Both go in the Authorization: Bearer header; wherever an API key is accepted it may instead go in an x-api-key header. The provisioning API (/v1/provisioning/keys) takes a management key (sk-rr-mgmt-...) as a bearer token instead. Errors always use the { ok:false, error:{ code, message } } envelope. Key-authenticated inference responses carry X-RateLimit-Limit / -Remaining / -Reset headers, plus Retry-After on 429."},"servers":[{"url":"https://rapidrouter.ai/api"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"A Rapid Router API key (sk-rr-...) for inference routes, or a dashboard session JWT for account routes."},"apiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"A Rapid Router API key (sk-rr-...) sent as x-api-key, the header Anthropic SDKs use. Accepted wherever an API key is; not by provisioning or the session-only account routes."},"managementKey":{"type":"http","scheme":"bearer","description":"A management key (sk-rr-mgmt-...), for the provisioning API only. It can never call inference, and runtime keys cannot call provisioning."}},"schemas":{"Error":{"type":"object","required":["ok","error"],"properties":{"ok":{"type":"boolean","const":false},"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable code, e.g. bad_request, unauthorized, rate_limited, budget_exceeded"},"message":{"type":"string","description":"Human-readable explanation"}}}}},"ChatMessage":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["system","user","assistant","tool"]},"content":{"description":"A string, or an array of content parts ({type:\"text\",text} / {type:\"image_url\",image_url:{url}})","oneOf":[{"type":"string"},{"type":"array","items":{"type":"object"}},{"type":"null"}]},"tool_calls":{"type":"array","items":{"type":"object"}},"tool_call_id":{"type":"string"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"note":{"type":"string"},"prefix":{"type":"string","description":"First 12 characters of the secret, for display"},"monthly_cap_usd":{"type":["string","null"],"description":"Decimal string, or null for no cap"},"spend_usd":{"type":"string","description":"Lifetime spend through this key (decimal string)"},"limit_usd":{"type":["number","null"]},"limit_reset":{"type":["string","null"],"enum":["daily","weekly","monthly",null]},"limit_spent_usd":{"type":"number"},"limit_remaining_usd":{"type":["number","null"]},"limit_resets_at":{"type":["string","null"],"format":"date-time"},"allowed_models":{"type":["array","null"],"items":{"type":"string"},"description":"null = every model; otherwise exact ids and 'provider/*' patterns"},"blocked_models":{"type":["array","null"],"items":{"type":"string"},"description":"Exact ids and 'author/*' patterns this key may never call; null = none"},"disabled":{"type":"boolean"},"rpm":{"type":["integer","null"],"description":"Per-key requests-per-minute override; null = platform default"},"capture":{"type":"boolean","description":"Request/response capture on this key"},"capture_days":{"type":"integer","enum":[1,7,30]},"guard_pii":{"type":"boolean"},"expires_at":{"type":["string","null"],"format":"date-time"},"rotated_from":{"type":["string","null"],"description":"Id of the key this one replaced via rotate"},"created_at":{"type":"string","format":"date-time"},"last_used_at":{"type":["string","null"],"format":"date-time"}}},"Batch":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"batch"},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled","expired"]},"discount_pct":{"type":"number"},"request_counts":{"type":"object","properties":{"total":{"type":"integer"},"completed":{"type":"integer"},"failed":{"type":"integer"}}},"created_at":{"type":["integer","null"],"description":"Unix seconds"},"expires_at":{"type":["integer","null"],"description":"Unix seconds"},"completed_at":{"type":["integer","null"],"description":"Unix seconds"}}},"AuditEvent":{"type":"object","properties":{"id":{"type":"string"},"user_id":{"type":"string"},"org_id":{"type":["string","null"]},"actor_email":{"type":["string","null"]},"action":{"type":"string","description":"e.g. key.create, key.update, key.delete, budget.update, org.invite.create, org.member.add, org.member.remove, byok.add, byok.remove"},"subject":{"type":["string","null"],"description":"The id the action acted on (key id, provider slug, user id, ...)"},"detail":{"type":["object","null"]},"created_at":{"type":"string","format":"date-time"}}},"ModelUptime":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"providers":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"buckets":{"type":"array","minItems":72,"maxItems":72,"items":{"type":"object","properties":{"hour":{"type":"string","format":"date-time"},"availability":{"type":["number","null"],"minimum":0,"maximum":1}}}}}}}}}}},"ModelEndpoints":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"endpoints":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"pricing":{"type":"object","properties":{"input_per_m":{"type":"number"},"output_per_m":{"type":"number"}}},"healthy":{"type":"boolean","description":"The provider is configured and able to serve"},"stats":{"type":"object","description":"Last 24 hours of successful traffic on this route","properties":{"requests_24h":{"type":"integer"},"p50_latency_ms":{"type":["integer","null"]},"throughput_tps":{"type":["number","null"],"description":"Output tokens per second of wall time"}}}}}}}}}}}},"paths":{"/v1/chat/completions":{"post":{"summary":"Chat completion (OpenAI-compatible)","description":"Runs the prompt on the requested model with automatic provider routing and fallbacks. Set stream:true for server-sent events (text/event-stream) of chat.completion.chunk objects, terminated by data: [DONE]. A model id may carry the :free variant suffix where advertised. Instead of model, a preset name may be sent.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"model":{"type":"string","description":"Required unless preset is set"},"preset":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"stream":{"type":"boolean","default":false},"max_tokens":{"type":"integer"},"temperature":{"type":"number"},"top_p":{"type":"number"},"stop":{"type":["string","array"]},"tools":{"type":"array","items":{"type":"object"}},"tool_choice":{},"response_format":{"type":"object"},"reasoning":{"type":"object","description":"Unified reasoning controls, e.g. { max_tokens } or { effort }"},"provider":{"type":"object","description":"Routing preferences"},"user":{"type":"string"}}}}}},"responses":{"200":{"description":"An OpenAI-shape chat.completion object (choices, usage), or an SSE stream when stream:true. When the output limit was lowered so the worst case fits the credit balance, the body (or the final usage chunk of a stream) carries max_tokens_capped: { requested: integer|null, applied: integer, reason: 'balance' }.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current minute window","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets","schema":{"type":"integer"}},"X-RR-Max-Tokens-Capped":{"description":"Present only when the output limit was capped to fit the balance: the max_tokens actually applied","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Out of credits, or the key hit its spend limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Model not allowed for this key, or account budget exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/chat/fanout":{"post":{"summary":"Run one prompt on up to 4 models at once","description":"Same body as /v1/chat/completions but with models (an array of up to 4 ids) instead of model. Each model runs as a full, individually billed chat completion. Streaming is not supported. The key is checked per inner request, so an invalid key shows up as a 401 in each result.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["models","messages"],"properties":{"models":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":4},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"results":{"type":"array","items":{"type":"object","properties":{"model":{"type":"string"},"status":{"type":"integer","description":"HTTP status of the inner completion"},"body":{"type":"object","description":"The inner response body (chat.completion or error envelope)"}}}}}}}}}}},"400":{"description":"models missing, more than 4 models, or stream:true","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Neither an Authorization nor an x-api-key header was sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/messages":{"post":{"summary":"Anthropic Messages API (compatible)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"description":"Anthropic-shape request in, Anthropic-shape response out (streaming included), served through the same routing and billing pipeline as /v1/chat/completions. max_tokens is required.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","messages","max_tokens"],"properties":{"model":{"type":"string"},"messages":{"type":"array","items":{"type":"object"}},"max_tokens":{"type":"integer"},"system":{},"stream":{"type":"boolean"},"temperature":{"type":"number"},"top_p":{"type":"number"},"stop_sequences":{"type":"array","items":{"type":"string"}},"tools":{"type":"array","items":{"type":"object"}},"tool_choice":{"type":"object"},"thinking":{"type":"object"},"metadata":{"type":"object"}}}}}},"responses":{"200":{"description":"An Anthropic-shape message object, or an SSE stream when stream:true. When the output limit was lowered to fit the credit balance, the message object carries max_tokens_capped: { requested: integer|null, applied: integer, reason: 'balance' }; in a stream it rides on the message_delta event only when the serving upstream is Anthropic itself, so read the header there.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current minute window","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets","schema":{"type":"integer"}},"X-RR-Max-Tokens-Capped":{"description":"Present only when the output limit was capped to fit the balance: the max_tokens actually applied","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request (Anthropic error envelope for validation errors on this endpoint)"},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/responses":{"post":{"summary":"OpenAI Responses API (compatible, stateless)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"description":"Responses-shape request in, Responses-shape response out. STATELESS: nothing is stored, so store:true and previous_response_id are rejected; resend prior output items in input to continue a conversation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","input"],"properties":{"model":{"type":"string"},"input":{"description":"A string, or an array of input items (message / function_call / function_call_output)","oneOf":[{"type":"string"},{"type":"array","items":{"type":"object"}}]},"instructions":{"type":"string"},"max_output_tokens":{"type":"integer"},"stream":{"type":"boolean"},"temperature":{"type":"number"},"top_p":{"type":"number"},"tools":{"type":"array","items":{"type":"object"}},"tool_choice":{},"text":{"type":"object","description":"{ format: { type: json_schema | json_object, ... } }"},"reasoning":{"type":"object"},"user":{"type":"string"}}}}}},"responses":{"200":{"description":"A Responses-shape response object, or an SSE stream when stream:true. When the output limit was lowered to fit the credit balance, the response object carries max_tokens_capped: { requested: integer|null, applied: integer, reason: 'balance' }; the streamed response.completed event does not, so read the header there.","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current minute window","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets","schema":{"type":"integer"}},"X-RR-Max-Tokens-Capped":{"description":"Present only when the output limit was capped to fit the balance: the max_tokens actually applied","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid request, or a stateful parameter (store, previous_response_id)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/responses/{id}":{"get":{"summary":"Retrieve a response (always 404: this Responses API is stateless)","description":"Present for SDK compatibility. Nothing is stored, so every id answers 404 not_found, with or without auth.","security":[],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"404":{"description":"Responses are never stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/embeddings":{"post":{"summary":"Embeddings (OpenAI-compatible)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","input"],"properties":{"model":{"type":"string"},"input":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"encoding_format":{"type":"string","enum":["float","base64"]},"dimensions":{"type":"integer"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"object":{"type":"string","const":"embedding"},"index":{"type":"integer"},"embedding":{"type":"array","items":{"type":"number"}}}}},"model":{"type":"string"},"provider":{"type":"string"},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"total_tokens":{"type":"integer"},"cost":{"type":"number"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown embedding model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/rerank":{"post":{"summary":"Rerank documents against a query","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","query","documents"],"properties":{"model":{"type":"string"},"query":{"type":"string"},"documents":{"type":"array","items":{"type":"string"},"maxItems":1000},"top_n":{"type":"integer"},"return_documents":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"model":{"type":"string"},"provider":{"type":"string"},"results":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"relevance_score":{"type":"number"},"document":{"type":"string"}}}},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"total_tokens":{"type":"integer"},"cost":{"type":"number"}}}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown rerank model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/tokenize":{"post":{"summary":"Count tokens for a model","description":"Free and unauthenticated (rate limited per IP, 30/min). Exact counts via tiktoken for OpenAI-family models; other families get a character-based estimate with exact:false.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model"],"properties":{"model":{"type":"string"},"text":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"},"description":"Alternative to text; counted with chat message overhead"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"tokens":{"type":"integer"},"exact":{"type":"boolean"},"encoding":{"type":["string","null"],"description":"cl100k_base / o200k_base, or null for an estimate"}}}}}}}},"400":{"description":"Missing model, or neither text nor messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/models":{"get":{"summary":"List chat models (OpenAI-compatible)","security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"model"},"owned_by":{"type":"string"},"provider":{"type":"string"},"available":{"type":"boolean"},"pricing":{"type":"object","properties":{"input_per_m":{"type":"number"},"output_per_m":{"type":"number"}}},"requests_30d":{"type":"integer"},"tokens_30d":{"type":"number"},"variants":{"type":"array","items":{"type":"string"}},"context_length":{"type":["integer","null"]},"max_output_tokens":{"type":["integer","null"]},"input_modalities":{"type":"array","items":{"type":"string"}},"output_modalities":{"type":"array","items":{"type":"string"}},"capabilities":{"type":"object"}}}}}}}}}}}},"/v1/catalog":{"get":{"summary":"Full model catalog (chat, embeddings, rerank, media) with pricing and live stats","security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"counts":{"type":"object","properties":{"live":{"type":"integer"},"pending":{"type":"integer"},"authors":{"type":"integer"},"media":{"type":"integer"}}},"usd_inr":{"type":["object","null"]},"models":{"type":"array","items":{"type":"object"}}}}}}}}}}}},"/v1/images/edits":{"post":{"summary":"Edit an image with a prompt","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"description":"One source image in, one edited image out. \"image\" is a data:image/...;base64 URL or an https URL (PNG, JPEG or WEBP, under 8 MB). Prompted edits: qwen/qwen-image-edit, qwen/qwen-image-edit-max, black-forest-labs/flux.1-kontext-dev, wan-ai/wan2.7-image-edit, wan-ai/wan2.6-image-edit, bria/fibo_edit, prunaai/p-image-edit. Tools that need no prompt: bria/enhance, bria/remove_background, bria/erase, bria/erase_foreground, bria/expand, bria/gen_fill, bria/blur_background, bria/replace_background, clarityai/crystal, clarityai/flux, clarityai/creative (upscalers), black-forest-labs/flux-1-redux-dev (variations). \"mask\" (data URL) is optional for erase and gen_fill. Billed per image returned.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","image"],"properties":{"model":{"type":"string"},"prompt":{"type":"string"},"image":{"type":"string"},"mask":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"created":{"type":"integer"},"model":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"b64_json":{"type":"string"},"url":{"type":"string"}}}},"cost":{"type":"number"}}}}}}}},"400":{"description":"Missing image or prompt, or not an edit model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown image model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/images/generations":{"post":{"summary":"Generate images","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","prompt"],"properties":{"model":{"type":"string"},"prompt":{"type":"string"},"n":{"type":"integer"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"created":{"type":"integer"},"model":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"b64_json":{"type":"string"},"url":{"type":"string"}}}},"cost":{"type":"number"}}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown image model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audio/speech":{"post":{"summary":"Text to speech","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","input"],"properties":{"model":{"type":"string"},"input":{"type":"string"},"voice":{"type":"string"},"language":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"model":{"type":"string"},"audio":{"type":"string","description":"Base64 audio bytes"},"format":{"type":"string","enum":["mp3","wav"]},"cost":{"type":"number"}}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown speech model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audio/transcriptions":{"post":{"summary":"Speech to text","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","audio_b64"],"properties":{"model":{"type":"string"},"audio_b64":{"type":"string","description":"Base64-encoded audio"},"language":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"model":{"type":"string"},"text":{"type":"string"},"language_code":{"type":"string"},"billed_minutes":{"type":"number"},"cost":{"type":"number"}}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown transcription model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/translate":{"post":{"summary":"Translate text (always served and billed as sarvam/mayura)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["input","target_language_code"],"properties":{"input":{"type":"string"},"source_language_code":{"type":"string","default":"auto"},"target_language_code":{"type":"string","description":"e.g. hi-IN"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"model":{"type":"string","const":"sarvam/mayura"},"translated_text":{"type":"string"},"source_language_code":{"type":"string","description":"As detected when the source was auto"},"cost":{"type":"number"}}}}}}}},"400":{"description":"Missing input or target_language_code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Out of credits, or the key hit its spend limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"sarvam/mayura not allowed or blocked for this key, or account budget exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Translate provider failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Translate provider not configured on this deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/media/models":{"get":{"summary":"List media models (image, video, speech, transcription, translate)","security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["image","video","tts","stt","translate"]},"provider":{"type":"string"}}}}}}}}}}}}}},"/v1/videos/generations":{"post":{"summary":"Start a video generation","description":"Billed flat, upfront, once the render starts. Most models are asynchronous: poll POST /v1/videos/generations/status with the returned id. Models that only run synchronously come back already done, with a 'vsync_' id and the video URL in the same response; that id stays pollable for an hour.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","prompt"],"properties":{"model":{"type":"string"},"prompt":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"model":{"type":"string"},"id":{"type":"string","description":"Operation id to poll (may contain slashes)"},"status":{"type":"string","enum":["processing","done"]},"poll":{"type":"string","const":"/v1/videos/generations/status"},"video":{"type":"string","description":"Video URL; present only when status is 'done'"},"cost":{"type":"number"}}}}}}}},"400":{"description":"Missing prompt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Out of credits, or the key hit its spend limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Model not allowed or blocked for this key, or account budget exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown video model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Video provider failed to start","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Video provider not configured on this deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/videos/generations/status":{"post":{"summary":"Poll a video generation","description":"The id goes in the body, not the path, because some provider operation ids contain slashes. Polling is not billed.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The id from POST /v1/videos/generations"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["processing","done","failed","expired"],"description":"expired: a 'vsync_' id no longer held (older than an hour, or not yours); the video was in the create response"},"video":{"description":"When done: a URL string, a provider video object, or null","type":["string","object","null"]},"video_b64":{"type":"string","description":"When done, for OpenAI (Sora) jobs instead of video"},"format":{"type":"string","const":"mp4","description":"Accompanies video_b64"},"progress":{"type":["number","null"],"description":"While processing, where the provider reports it"},"message":{"type":"string","description":"Accompanies expired"}}}}}}}},"400":{"description":"Missing id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Could not read the video job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Video provider not configured on this deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/voice/chat":{"post":{"summary":"Voice chat: audio in, transcript + reply text + spoken reply out","description":"One call runs speech-to-text, a chat completion and text-to-speech, each billed as its own ledger line. Non-stream only (stream:true is a 400). Audio is at most 15 MB, sent as base64 audio_b64 in JSON or as a \"file\" part in multipart/form-data (other fields as form fields). model defaults to google/gemini-flash-latest; omitted stt_model / tts_model pick the cheapest configured model, and an unnamed STT falls back to the next one if it fails. A failed stage answers with error.billed_stages ([], [\"stt\"] or [\"stt\",\"chat\"]) naming the stages already charged.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["audio_b64"],"properties":{"audio_b64":{"type":"string","description":"Base64 audio, at most 15 MB decoded"},"mime_type":{"type":"string","default":"audio/wav"},"model":{"type":"string","description":"Chat model"},"stt_model":{"type":"string"},"tts_model":{"type":"string"},"voice":{"type":"string"},"system":{"type":"string","description":"System prompt for the chat stage"},"max_tokens":{"type":"integer","minimum":1},"response_format":{"type":"string","enum":["mp3","wav","opus","aac","flac","pcm"],"description":"Honoured by OpenAI, Together and DeepInfra speech models; others return their native format"},"language":{"type":"string"}}}},"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"The audio; its part Content-Type is used as the mime type"},"model":{"type":"string"},"stt_model":{"type":"string"},"tts_model":{"type":"string"},"voice":{"type":"string"},"system":{"type":"string"},"max_tokens":{"type":"integer","minimum":1},"response_format":{"type":"string","enum":["mp3","wav","opus","aac","flac","pcm"]},"language":{"type":"string"}}}}}},"responses":{"200":{"description":"Success","headers":{"X-RateLimit-Limit":{"description":"Requests allowed per minute for this key","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current minute window","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix time (seconds) when the window resets","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"transcript":{"type":"string"},"reply_text":{"type":"string"},"audio_b64":{"type":["string","null"]},"audio_mime":{"type":"string","description":"e.g. audio/mpeg, audio/wav"},"models":{"type":"object","properties":{"stt":{"type":"string"},"chat":{"type":"string"},"tts":{"type":"string"}}},"usage":{"type":"object","properties":{"stt_cost_usd":{"type":"number"},"chat_cost_usd":{"type":"number"},"tts_cost_usd":{"type":"number"},"cost_usd_total":{"type":"number"}}}}}}}}}},"400":{"description":"Missing audio, empty audio, or stream:true","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Out of credits, or the key hit its spend limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"STT/TTS model not allowed for this key, or account budget exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown stt_model or tts_model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Audio over 15 MB (audio_too_large)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"No speech detected (voice_empty_transcript); only STT was billed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited, or too many requests in flight","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"A stage failed (voice_stt_failed / voice_chat_failed / voice_tts_failed). A failed chat stage passes through its own 4xx status instead.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"No STT or TTS provider configured on this deployment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/batches":{"post":{"summary":"Create a batch of up to 500 chat completions (standard per-token pricing, 24h window)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requests"],"properties":{"requests":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["body"],"properties":{"custom_id":{"type":"string"},"body":{"type":"object","description":"A /v1/chat/completions body (stream not allowed)"}}}}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"400":{"description":"Invalid batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"List your batches (newest first, up to 100)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/batches/{id}":{"get":{"summary":"Fetch one batch","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"404":{"description":"No such batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/batches/{id}/results":{"get":{"summary":"Batch results as JSONL (one line per item, submission order)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"application/x-ndjson: { custom_id, response } or { custom_id, error } per line"},"404":{"description":"No such batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Batch is still queued or running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/batches/{id}/cancel":{"post":{"summary":"Cancel a queued or running batch","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Batch"}}}},"404":{"description":"No such batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Batch already finished","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/analytics/meta":{"get":{"summary":"What the analytics query accepts (management key)","description":"Lists the metrics, dimensions and rollups POST /v1/analytics/query understands. Needs a management key (sk-rr-mgmt-...) as the bearer token.","security":[{"managementKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"metrics":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"additive":{"type":"boolean"}}}},"dimensions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}}}},"rollups":{"type":"array","items":{"type":"string","enum":["none","day","week","month"]}}}}}}}}},"401":{"description":"Missing, revoked or non-management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/analytics/query":{"post":{"summary":"Usage grouped by a dimension, optionally over time (management key)","description":"The query behind the dashboard's Explore tab. One metric, grouped by one dimension and an optional second, rolled up by day, week or month or not at all. Groups past the top `limit` fold into \"Other\". Window: `days` (rolling, up to 366) or `from`/`to` inclusive IST dates.","security":[{"managementKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"metric":{"type":"string","enum":["spend","requests","tokens","tokens_in","tokens_out","tokens_reasoning","tokens_cached","errors","cache_hits","latency_p50"],"default":"spend"},"group":{"type":"string","enum":["model","provider","key","app","user","kind","status","preset","day","week","month"],"default":"model"},"subgroup":{"type":["string","null"],"description":"A second dimension, from the same list"},"rollup":{"type":"string","enum":["none","day","week","month"],"default":"none"},"days":{"type":"integer","description":"Rolling window in days (default 30)"},"from":{"type":"string","format":"date"},"to":{"type":"string","format":"date"},"limit":{"type":"integer","minimum":1,"maximum":50,"default":10}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"metric":{"type":"string"},"group":{"type":"string"},"subgroup":{"type":["string","null"]},"rollup":{"type":"string"},"label":{"type":"string"},"additive":{"type":"boolean"},"total":{"type":["number","null"]},"groups":{"type":"array","items":{"type":"string"},"description":"Group names in rank order, \"Other\" last when folded"},"rows":{"type":"array","items":{"type":"object","properties":{"t":{"type":["string","null"],"description":"The time bucket as an IST wall-clock string, null without a rollup"},"group":{"type":"string"},"subgroup":{"type":["string","null"]},"value":{"type":"number"},"requests":{"type":"integer"}}}}}}}}}}},"400":{"description":"Bad window","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, revoked or non-management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys":{"get":{"summary":"List your live API keys (dashboard session auth)","description":"Revoked keys are not listed; their spend stays in the usage logs.","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"last_model":{"type":["string","null"],"description":"Model of the most recent request through this key"}}}]}}}}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create an API key","description":"The secret is returned exactly once and never stored. rotated_from cannot be set here; only rotate sets it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"note":{"type":"string","maxLength":200,"description":"Trimmed; over 200 characters is a 400"},"limit_usd":{"type":["number","null"],"minimum":0},"limit_reset":{"type":["string","null"],"enum":["daily","weekly","monthly",null]},"monthly_cap_usd":{"type":["number","null"],"minimum":0},"allowed_models":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"blocked_models":{"type":["array","null"],"items":{"type":"string","maxLength":200},"maxItems":200},"expires_at":{"type":["string","null"],"format":"date-time","description":"At least a minute in the future; null = never"},"rpm":{"type":["integer","null"],"minimum":1,"maximum":60,"description":"null = platform default"},"capture":{"type":"boolean"},"capture_days":{"type":"integer","enum":[1,7,30],"default":7,"description":"Any other value is a 400"},"guard_pii":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"secret":{"type":"string"}}}]}}}}}},"400":{"description":"Invalid key settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys/{id}":{"patch":{"summary":"Edit a key (name, note, limits, allowlist, capture, PII guard)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"note":{"type":"string","maxLength":200,"description":"Trimmed; over 200 characters is a 400"},"limit_usd":{"type":["number","null"],"minimum":0},"limit_reset":{"type":["string","null"],"enum":["daily","weekly","monthly",null]},"monthly_cap_usd":{"type":["number","null"],"minimum":0},"allowed_models":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"blocked_models":{"type":["array","null"],"items":{"type":"string","maxLength":200},"maxItems":200},"expires_at":{"type":["string","null"],"format":"date-time","description":"At least a minute in the future; null = never"},"rpm":{"type":["integer","null"],"minimum":1,"maximum":60,"description":"null = platform default"},"capture":{"type":"boolean"},"capture_days":{"type":"integer","enum":[1,7,30],"default":7,"description":"Any other value is a 400"},"guard_pii":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ApiKey"}}}}}},"400":{"description":"Invalid key settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Revoke a key","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ApiKey"}}}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/keys/{id}/rotate":{"post":{"summary":"Rotate a key (dashboard session auth)","description":"Mints a successor with the same settings (its rotated_from names the old key) and returns its secret exactly once. Nothing is revoked: the old key keeps working for 24 hours, then expires on its own. No request body.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"secret":{"type":"string"},"retiring":{"type":"object","properties":{"id":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}}}}}]}}}}}},"400":{"description":"The old key's settings no longer validate","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Read-only (impersonated) session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/provisioning/keys":{"get":{"summary":"List runtime API keys (management key auth)","security":[{"managementKey":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}},"401":{"description":"Missing management key, a runtime key was sent, or unknown/revoked management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a runtime API key (management key auth)","description":"The secret is returned exactly once and never stored.","security":[{"managementKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"note":{"type":"string","maxLength":200,"description":"Trimmed; over 200 characters is a 400"},"limit_usd":{"type":["number","null"],"minimum":0},"limit_reset":{"type":["string","null"],"enum":["daily","weekly","monthly",null]},"monthly_cap_usd":{"type":["number","null"],"minimum":0},"allowed_models":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"blocked_models":{"type":["array","null"],"items":{"type":"string","maxLength":200},"maxItems":200},"expires_at":{"type":["string","null"],"format":"date-time","description":"At least a minute in the future; null = never"},"rpm":{"type":["integer","null"],"minimum":1,"maximum":60,"description":"null = platform default"},"capture":{"type":"boolean"},"capture_days":{"type":"integer","enum":[1,7,30],"default":7,"description":"Any other value is a 400"},"guard_pii":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"secret":{"type":"string"}}}]}}}}}},"400":{"description":"Invalid key settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing management key, a runtime key was sent, or unknown/revoked management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/provisioning/keys/{id}":{"get":{"summary":"Fetch one runtime API key (management key auth)","security":[{"managementKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ApiKey"}}}}}},"401":{"description":"Missing management key, a runtime key was sent, or unknown/revoked management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found (or revoked)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Edit a runtime API key, including disabling it (management key auth)","description":"Same fields as PATCH /v1/keys/{id}, plus disabled. A disabled key answers 401 key_disabled until re-enabled here.","security":[{"managementKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"note":{"type":"string","maxLength":200,"description":"Trimmed; over 200 characters is a 400"},"limit_usd":{"type":["number","null"],"minimum":0},"limit_reset":{"type":["string","null"],"enum":["daily","weekly","monthly",null]},"monthly_cap_usd":{"type":["number","null"],"minimum":0},"allowed_models":{"type":["array","null"],"items":{"type":"string"},"maxItems":200},"blocked_models":{"type":["array","null"],"items":{"type":"string","maxLength":200},"maxItems":200},"expires_at":{"type":["string","null"],"format":"date-time","description":"At least a minute in the future; null = never"},"rpm":{"type":["integer","null"],"minimum":1,"maximum":60,"description":"null = platform default"},"capture":{"type":"boolean"},"capture_days":{"type":"integer","enum":[1,7,30],"default":7,"description":"Any other value is a 400"},"guard_pii":{"type":"boolean"},"disabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/ApiKey"}}}}}},"400":{"description":"Invalid key settings, or nothing to update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing management key, a runtime key was sent, or unknown/revoked management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found (or revoked)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Revoke a runtime API key (management key auth)","security":[{"managementKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"id":{"type":"string"}}}}}}}},"401":{"description":"Missing management key, a runtime key was sent, or unknown/revoked management key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Key not found (or already revoked)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/credits":{"get":{"summary":"Credit balance and recent transactions (session JWT or API key)","description":"An API key here resolves to its owner by a plain lookup, not the gateway check: it is not rate limited and is not refused for being disabled or expired, only for being unknown or revoked. x-api-key is read when no Authorization header is sent.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"balance_usd":{"type":["string","number"],"description":"Decimal string; the number 0 when the account has no balance row yet. For a shared org balance, the owner's wallet"},"balance_shared":{"type":"boolean","description":"True when the balance shown is an org owner's shared wallet"},"transactions":{"type":"array","description":"The caller's own last 50 ledger rows, newest first","items":{"type":"object","properties":{"delta_usd":{"type":"string","description":"Decimal string"},"kind":{"type":"string"},"ref":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}}},"inr_rate":{"type":["number","null"]}}}}}}}},"401":{"description":"Missing or invalid session, or unknown/revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage/summary":{"get":{"summary":"Usage totals with the previous-window comparison, daily series and breakdowns (session JWT or API key)","description":"The window is ?days=7|30 (default 30), or ?from=&to= as inclusive IST days (at most 366), which wins when both are valid and from <= to; otherwise the range is ignored and days applies. The prev_* totals cover the same span immediately before.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30],"default":30},"description":"Anything other than 7 means 30"},{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"name":"key_id","in":"query","schema":{"type":"string"},"description":"Narrow every aggregate to one of your keys"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"totals":{"type":"object","properties":{"spend_usd":{"type":"string","description":"Decimal string"},"requests":{"type":"string","description":"Decimal string"},"tokens":{"type":"string","description":"Decimal string"},"errors":{"type":"string","description":"Decimal string"},"p50_ms":{"type":["number","null"],"description":"Median latency of successful requests"},"prev_spend_usd":{"type":"string","description":"Decimal string"},"prev_requests":{"type":"string","description":"Decimal string"},"prev_tokens":{"type":"string","description":"Decimal string"},"prev_errors":{"type":"string","description":"Decimal string"},"prev_p50_ms":{"type":["number","null"]}}},"daily":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date","description":"IST day"},"spend_usd":{"type":"string","description":"Decimal string"},"requests":{"type":"string","description":"Decimal string"},"errors":{"type":"string","description":"Decimal string"},"tokens":{"type":"string","description":"Decimal string"}}}},"by_model":{"type":"array","maxItems":20,"description":"Top 20 by cost","items":{"type":"object","properties":{"model":{"type":"string"},"requests":{"type":"string","description":"Decimal string"},"errors":{"type":"string","description":"Decimal string"},"tokens":{"type":"string","description":"Decimal string"},"cost_usd":{"type":"string","description":"Decimal string"}}}},"by_key":{"type":"array","maxItems":20,"description":"Top 20 keys by cost","items":{"type":"object","properties":{"key_id":{"type":"string"},"key_name":{"type":["string","null"]},"requests":{"type":"string","description":"Decimal string"},"errors":{"type":"string","description":"Decimal string"},"tokens":{"type":"string","description":"Decimal string"},"cost_usd":{"type":"string","description":"Decimal string"},"last_at":{"type":"string","format":"date-time"}}}},"days":{"type":"integer","description":"Length of the window in days"},"from":{"type":["string","null"],"description":"The from query value as sent (echoed even when it was not applied)"},"to":{"type":["string","null"],"description":"The to query value as sent (echoed even when it was not applied)"},"month":{"type":"object","description":"IST calendar month to date, independent of the window","properties":{"spend_usd":{"type":"number"},"requests":{"type":"number"},"day":{"type":"integer"},"days_in_month":{"type":"integer"},"projected_usd":{"type":"number","description":"Straight-line projection to month end"}}},"sdk":{"type":["string","null"],"description":"Client of the most recent request"}}}}}}}},"400":{"description":"from/to span more than a year","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing bearer token, invalid session, or unknown, disabled or expired API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"key_id is not a key on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"API key rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage/logs":{"get":{"summary":"Request log explorer with SQL-side filters (session JWT or API key)","description":"Newest first. Every filter given applies (they AND together), including hours with from/to.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"hours","in":"query","schema":{"type":"integer","minimum":1,"maximum":720},"description":"Last N hours; out of range is ignored"},{"name":"from","in":"query","schema":{"type":"string","format":"date"},"description":"Inclusive IST day"},{"name":"to","in":"query","schema":{"type":"string","format":"date"},"description":"Inclusive IST day"},{"name":"status","in":"query","schema":{"type":"string","enum":["ok","err","4xx","5xx"]},"description":"ok = 2xx, err = everything else; other values are ignored"},{"name":"model","in":"query","schema":{"type":"string"},"description":"Exact model id"},{"name":"key_id","in":"query","schema":{"type":"string"},"description":"Exact key id"},{"name":"app","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring of the app title or app URL"},{"name":"preset","in":"query","schema":{"type":"string"},"description":"Exact preset name"},{"name":"q","in":"query","schema":{"type":"string"},"description":"Case-insensitive substring of model, provider, app title or request id"},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100},"description":"Out-of-range values are clamped"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"key_id":{"type":"string"},"model":{"type":"string"},"provider":{"type":"string"},"status":{"type":"integer"},"latency_ms":{"type":"integer"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"},"tokens_reasoning":{"type":"integer"},"tokens_cached":{"type":"integer"},"cost_usd":{"type":"string","description":"Decimal string"},"app_url":{"type":["string","null"]},"app_title":{"type":["string","null"]},"user_tag":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"error_message":{"type":["string","null"]},"preset":{"type":["string","null"]},"sdk":{"type":["string","null"]},"cache_hit":{"type":"boolean"}}}},"total":{"type":"integer","description":"Count for the current filter, not the page"}}}}}}}},"401":{"description":"Missing bearer token, invalid session, or unknown, disabled or expired API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"API key rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage/logs/{id}":{"get":{"summary":"One request log row in full (session JWT or API key)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The request log id (gen_...)"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","description":"Every stored request_logs column (the list row fields and more) plus key_name","properties":{"id":{"type":"string"},"key_id":{"type":"string"},"key_name":{"type":["string","null"]},"model":{"type":"string"},"provider":{"type":"string"},"status":{"type":"integer"},"latency_ms":{"type":"integer"},"tokens_in":{"type":"integer"},"tokens_out":{"type":"integer"},"cost_usd":{"type":"string","description":"Decimal string"},"error_message":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Missing bearer token, invalid session, or unknown, disabled or expired API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No request with that id on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"API key rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/usage/export":{"get":{"summary":"Usage CSV for accounting (session JWT or API key)","description":"One row per IST day + key + model + provider + status, columns date,key_id,model,provider,status,requests,tokens_in,tokens_out,tokens_cached,cost_usd. from and to are inclusive IST days, at most 92 days apart.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date"}},{"name":"key_id","in":"query","schema":{"type":"string"},"description":"Narrow to one of your keys"},{"name":"model","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["ok","err"]}},{"name":"q","in":"query","schema":{"type":"string"},"description":"Substring match on model or provider"}],"responses":{"200":{"description":"CSV attachment (rapidrouter-usage-<from>-<to>.csv)","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Bad or missing dates, from after to, or a range over 92 days","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing bearer token, invalid session, or unknown, disabled or expired API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"key_id is not a key on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"API key rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/generation":{"get":{"summary":"Cost and tokens of one request, after the fact (session JWT or API key)","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string"},"description":"The request log id, the x-request-id response header, or the id in the response body"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"id":{"type":"string"},"model":{"type":"string"},"provider_name":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"total_cost":{"type":"number"},"usage":{"type":"number","description":"Same as total_cost"},"tokens_prompt":{"type":"integer"},"tokens_completion":{"type":"integer"},"native_tokens_prompt":{"type":"integer"},"native_tokens_completion":{"type":"integer"},"native_tokens_reasoning":{"type":"integer"},"native_tokens_cached":{"type":"integer"},"latency":{"type":"integer","description":"ms"},"generation_time":{"type":"integer","description":"ms; same as latency"},"cache_hit":{"type":"boolean"},"status":{"type":"integer"},"app_id":{"type":["string","null"]}}}}}}}},"400":{"description":"Missing id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing bearer token, invalid session, or unknown, disabled or expired API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No generation with that id on this account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"API key rate limited (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/key":{"get":{"summary":"What the calling API key is allowed to do: label, limit, usage, rate limit","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object"}}}}}},"401":{"description":"Unknown or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/auth/keys":{"post":{"summary":"OAuth PKCE: exchange an authorization code for an API key","description":"Step 4 of \"Sign in with Rapid Router\". After the user approves at /oauth/authorize?callback_url=...&code_challenge=...&code_challenge_method=S256, the browser lands on callback_url?code=...; the app posts that code with its code_verifier here and receives a new API key on the user's account, billed to the user's credits. No auth: the code plus the matching verifier is the proof. Codes live 10 minutes and are single-use. Rate limited to 10 attempts a minute per IP.","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","code_verifier"],"properties":{"code":{"type":"string"},"code_verifier":{"type":"string","description":"The PKCE verifier whose base64url(SHA-256) is the code_challenge"}}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"allOf":[{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","required":["key"],"properties":{"key":{"type":"string","description":"The API key secret (sk-rr-...), returned exactly once"}}}}},{"type":"object","required":["key"],"properties":{"key":{"type":"string","description":"The same secret as data.key"}}}]}}}},"400":{"description":"bad_request (missing field), bad_code, code_consumed, code_expired or verifier_mismatch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many exchange attempts (see Retry-After)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/models/{author}/{model}/endpoints":{"get":{"summary":"Every provider that serves a model here, with per-provider pricing and health","description":"Provider-prefixed ids use the three-segment form /v1/models/{author}/{sub}/{model}/endpoints.","security":[],"parameters":[{"name":"author","in":"path","required":true,"schema":{"type":"string"}},{"name":"model","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelEndpoints"}}}},"404":{"description":"Unknown model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/models/{author}/{sub}/{model}/endpoints":{"get":{"summary":"Same as /v1/models/{author}/{model}/endpoints, for three-segment model ids","security":[],"parameters":[{"name":"author","in":"path","required":true,"schema":{"type":"string"}},{"name":"sub","in":"path","required":true,"schema":{"type":"string"}},{"name":"model","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelEndpoints"}}}},"404":{"description":"Unknown model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/models/{author}/{slug}/uptime":{"get":{"summary":"Hourly availability per provider for a model, last 72 hours","description":"72 UTC hour buckets per provider, oldest first, ending at the current hour. availability is ok / (ok + 5xx) for that hour (4xx count as neither); null means no traffic that hour. Provider-prefixed ids use the three-segment form /v1/models/{author}/{sub}/{slug}/uptime.","security":[],"parameters":[{"name":"author","in":"path","required":true,"schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelUptime"}}}},"404":{"description":"Unknown model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/models/{author}/{sub}/{slug}/uptime":{"get":{"summary":"Same as /v1/models/{author}/{slug}/uptime, for three-segment model ids","security":[],"parameters":[{"name":"author","in":"path","required":true,"schema":{"type":"string"}},{"name":"sub","in":"path","required":true,"schema":{"type":"string"}},{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelUptime"}}}},"404":{"description":"Unknown model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/parameters/{author}/{model}":{"get":{"summary":"Request fields the gateway honours for a model","security":[],"parameters":[{"name":"author","in":"path","required":true,"schema":{"type":"string"}},{"name":"model","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"object","properties":{"model":{"type":"string"},"provider":{"type":"string"},"kind":{"type":"string","description":"chat, embedding, image, tts, ..."},"supported_parameters":{"type":"array","items":{"type":"string"}}}}}}}}},"404":{"description":"Unknown model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/audit":{"get":{"summary":"Your audit trail, newest first (dashboard session auth, up to 100 events)","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","required":["ok","data"],"properties":{"ok":{"type":"boolean","const":true},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditEvent"}}}}}}},"401":{"description":"Missing or invalid session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}