{"files":{"SKILL.md":"---\nname: openrouter-api\ndescription: \"OpenRouter API skill. Use when working with OpenRouter for activity, analytics, api. Covers 122 endpoints.\"\nversion: 1.0.0\ngenerator: lapsh\n---\n\n# OpenRouter API\nAPI version: 1.0.0\n\n## Auth\nBearer bearer | Bearer bearer\n\n## Base URL\nhttps://openrouter.ai/api/v1\n\n## Setup\n1. Set Authorization header with your Bearer token\n2. GET /activity -- verify access\n3. POST /analytics/query -- create first query\n\n## Endpoints\n\n122 endpoints across 36 groups. See references/api-spec.lap for full details.\n\n### activity\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /activity | Get user activity grouped by endpoint |\n\n### analytics\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /analytics/meta | Get available analytics metrics and dimensions |\n| POST | /analytics/query | Query analytics data |\n\n### api\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /api/alpha/decisions | Submit a Decisions (questions and answers) request |\n\n### audio\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /audio/speech | Create speech |\n| POST | /audio/transcriptions | Create transcription |\n\n### auth\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /auth/keys | Exchange authorization code for API key |\n| POST | /auth/keys/code | Create authorization code |\n\n### benchmarks\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /benchmarks | List Benchmarks |\n\n### byok\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /byok | List BYOK provider credentials |\n| POST | /byok | Create a BYOK provider credential |\n| DELETE | /byok/{id} | Delete a BYOK provider credential |\n| GET | /byok/{id} | Get a BYOK provider credential |\n| PATCH | /byok/{id} | Update a BYOK provider credential |\n\n### chat\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /chat/completions | Create a chat completion |\n\n### classifications\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /classifications/task | Task classification market share |\n\n### containers\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /containers/{container_id}/files | List container files |\n| GET | /containers/{container_id}/files/{file_id} | Retrieve a container file |\n| GET | /containers/{container_id}/files/{file_id}/content | Download container file content |\n| POST | /containers/{container_id}/files/{file_id}/promote | Promote a container file into workspace documents |\n\n### credits\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /credits | Get remaining credits |\n| POST | /credits/coinbase | Deprecated Coinbase Commerce charge endpoint |\n\n### datasets\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /datasets/app-rankings | Top apps by token usage |\n| GET | /datasets/rankings-daily | Daily token totals for top 50 models |\n| GET | /datasets/session-cost | Cost per session by harness and model |\n\n### embeddings\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /embeddings | Submit an embedding request |\n| GET | /embeddings/models | List all embeddings models |\n\n### endpoints\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /endpoints/zdr | Preview the impact of ZDR on the available endpoints |\n\n### files\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /files | List files |\n| POST | /files | Upload a file |\n| DELETE | /files/{file_id} | Delete a file |\n| GET | /files/{file_id} | Get file metadata |\n| GET | /files/{file_id}/content | Download file content |\n\n### generation\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /generation | Get request & usage metadata for a generation |\n| GET | /generation/content | Get stored prompt, completion, and error content for a generation |\n| POST | /generation/feedback | Submit feedback for a generation |\n\n### guardrails\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /guardrails | List guardrails |\n| POST | /guardrails | Create a guardrail |\n| DELETE | /guardrails/{id} | Delete a guardrail |\n| GET | /guardrails/{id} | Get a guardrail |\n| PATCH | /guardrails/{id} | Update a guardrail |\n| GET | /guardrails/{id}/assignments/keys | List key assignments for a guardrail |\n| POST | /guardrails/{id}/assignments/keys | Bulk assign keys to a guardrail |\n| POST | /guardrails/{id}/assignments/keys/remove | Bulk unassign keys from a guardrail |\n| GET | /guardrails/{id}/assignments/members | List member assignments for a guardrail |\n| POST | /guardrails/{id}/assignments/members | Bulk assign members to a guardrail |\n| POST | /guardrails/{id}/assignments/members/remove | Bulk unassign members from a guardrail |\n| GET | /guardrails/assignments/keys | List all key assignments |\n| GET | /guardrails/assignments/members | List all member assignments |\n\n### images\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /images | Generate an image |\n| GET | /images/models | List image generation models |\n| GET | /images/models/{author}/{slug}/endpoints | List endpoints for an image model |\n\n### interns\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /interns | List interns |\n| POST | /interns | Create an intern |\n| DELETE | /interns/{internId} | Delete an intern |\n| GET | /interns/{internId} | Get an intern |\n| PATCH | /interns/{internId} | Update an intern |\n| POST | /interns/{internId}/chat/completions | Stream a chat completion with an intern |\n| POST | /interns/{internId}/provision | Provision an intern |\n| POST | /interns/{internId}/suspend | Suspend an intern |\n\n### key\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /key | Get current API key |\n\n### keys\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /keys | List API keys |\n| POST | /keys | Create a new API key |\n| DELETE | /keys/{hash} | Delete an API key |\n| GET | /keys/{hash} | Get a single API key |\n| PATCH | /keys/{hash} | Update an API key |\n\n### messages\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /messages | Create a message |\n\n### model\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /model/{author}/{slug} | Get a model by its slug |\n\n### models\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /models | List all models and their properties |\n| GET | /models/{author}/{slug}/endpoints | List all endpoints for a model |\n| GET | /models/count | Get total count of available models |\n| GET | /models/user | List models filtered by user provider preferences, privacy settings, and guardrails |\n\n### oauth\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /oauth/jwks | OpenRouter access token signing keys |\n| POST | /oauth/token | Exchange a workload identity token |\n\n### observability\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /observability/destinations | List observability destinations |\n| POST | /observability/destinations | Create an observability destination |\n| DELETE | /observability/destinations/{id} | Delete an observability destination |\n| GET | /observability/destinations/{id} | Get an observability destination |\n| PATCH | /observability/destinations/{id} | Update an observability destination |\n\n### organization\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /organization/members | List organization members |\n\n### presets\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /presets | List presets |\n| GET | /presets/{slug} | Get a preset |\n| POST | /presets/{slug}/chat/completions | Create a preset from a chat-completions request body |\n| POST | /presets/{slug}/messages | Create a preset from a messages request body |\n| POST | /presets/{slug}/responses | Create a preset from a responses request body |\n| GET | /presets/{slug}/versions | List versions of a preset |\n| GET | /presets/{slug}/versions/{version} | Get a specific version of a preset |\n\n### providers\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /providers | List all providers |\n\n### rerank\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /rerank | Submit a rerank request |\n\n### responses\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /responses | Create a response |\n\n### scim\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /scim/group-mappings | List SCIM group mappings |\n| POST | /scim/group-mappings | Create a SCIM group mapping |\n| DELETE | /scim/group-mappings/{id} | Delete a SCIM group mapping |\n| GET | /scim/group-mappings/{id} | Get a SCIM group mapping |\n| PATCH | /scim/group-mappings/{id} | Update a SCIM group mapping |\n| GET | /scim/groups | List SCIM groups |\n| POST | /scim/sync-jobs | Start a SCIM directory sync |\n| GET | /scim/sync-jobs/{id} | Get SCIM directory sync status |\n\n### systemone\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /systemone | Submit a System One request |\n\n### vault\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /vault/interns/{internId}/secrets | List intern secrets |\n| DELETE | /vault/interns/{internId}/secrets/{name} | Delete an intern secret |\n| PUT | /vault/interns/{internId}/secrets/{name} | Store an intern secret |\n| POST | /vault/interns/{internId}/secrets/copy | Copy workspace secrets to an intern |\n| GET | /vault/secrets | List workspace secrets |\n| DELETE | /vault/secrets/{name} | Delete a workspace secret |\n| PUT | /vault/secrets/{name} | Store a workspace secret |\n\n### videos\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | /videos | Submit a video generation request |\n| GET | /videos/{jobId} | Poll video generation status |\n| GET | /videos/{jobId}/content | Download generated video content |\n| GET | /videos/models | List all video generation models |\n\n### workspaces\n| Method | Path | Description |\n|--------|------|-------------|\n| GET | /workspaces | List workspaces |\n| POST | /workspaces | Create a workspace |\n| DELETE | /workspaces/{id} | Delete a workspace |\n| GET | /workspaces/{id} | Get a workspace |\n| PATCH | /workspaces/{id} | Update a workspace |\n| GET | /workspaces/{id}/members | List workspace members |\n| POST | /workspaces/{id}/members/add | Bulk add members to a workspace |\n| POST | /workspaces/{id}/members/remove | Bulk remove members from a workspace |\n| GET | /workspaces/{workspace_ref}/budgets | List workspace budgets |\n| DELETE | /workspaces/{workspace_ref}/budgets/{interval} | Delete a workspace budget |\n| GET | /workspaces/{workspace_ref}/budgets/{interval} | Get a workspace budget |\n| PUT | /workspaces/{workspace_ref}/budgets/{interval} | Create or update a workspace budget |\n\n## Common Questions\n\nMatch user requests to endpoints in references/api-spec.lap. Key patterns:\n- \"List all activity?\" -> GET /activity\n- \"List all meta?\" -> GET /analytics/meta\n- \"Create a query?\" -> POST /analytics/query\n- \"Create a decision?\" -> POST /api/alpha/decisions\n- \"Create a speech?\" -> POST /audio/speech\n- \"Create a transcription?\" -> POST /audio/transcriptions\n- \"Create a key?\" -> POST /auth/keys\n- \"Create a code?\" -> POST /auth/keys/code\n- \"List all benchmarks?\" -> GET /benchmarks\n- \"List all byok?\" -> GET /byok\n- \"Create a byok?\" -> POST /byok\n- \"Delete a byok?\" -> DELETE /byok/{id}\n- \"Get byok details?\" -> GET /byok/{id}\n- \"Partially update a byok?\" -> PATCH /byok/{id}\n- \"Create a completion?\" -> POST /chat/completions\n- \"List all task?\" -> GET /classifications/task\n- \"List all files?\" -> GET /containers/{container_id}/files\n- \"Get file details?\" -> GET /containers/{container_id}/files/{file_id}\n- \"List all content?\" -> GET /containers/{container_id}/files/{file_id}/content\n- \"Create a promote?\" -> POST /containers/{container_id}/files/{file_id}/promote\n- \"List all credits?\" -> GET /credits\n- \"Create a coinbase?\" -> POST /credits/coinbase\n- \"List all app-rankings?\" -> GET /datasets/app-rankings\n- \"List all rankings-daily?\" -> GET /datasets/rankings-daily\n- \"List all session-cost?\" -> GET /datasets/session-cost\n- \"Create a embedding?\" -> POST /embeddings\n- \"List all models?\" -> GET /embeddings/models\n- \"List all zdr?\" -> GET /endpoints/zdr\n- \"List all files?\" -> GET /files\n- \"Create a file?\" -> POST /files\n- \"Delete a file?\" -> DELETE /files/{file_id}\n- \"Get file details?\" -> GET /files/{file_id}\n- \"List all content?\" -> GET /files/{file_id}/content\n- \"List all generation?\" -> GET /generation\n- \"List all content?\" -> GET /generation/content\n- \"Create a feedback?\" -> POST /generation/feedback\n- \"List all guardrails?\" -> GET /guardrails\n- \"Create a guardrail?\" -> POST /guardrails\n- \"Delete a guardrail?\" -> DELETE /guardrails/{id}\n- \"Get guardrail details?\" -> GET /guardrails/{id}\n- \"Partially update a guardrail?\" -> PATCH /guardrails/{id}\n- \"List all keys?\" -> GET /guardrails/{id}/assignments/keys\n- \"Create a key?\" -> POST /guardrails/{id}/assignments/keys\n- \"Create a remove?\" -> POST /guardrails/{id}/assignments/keys/remove\n- \"List all members?\" -> GET /guardrails/{id}/assignments/members\n- \"Create a member?\" -> POST /guardrails/{id}/assignments/members\n- \"Create a remove?\" -> POST /guardrails/{id}/assignments/members/remove\n- \"List all keys?\" -> GET /guardrails/assignments/keys\n- \"List all members?\" -> GET /guardrails/assignments/members\n- \"Create a image?\" -> POST /images\n- \"List all models?\" -> GET /images/models\n- \"List all endpoints?\" -> GET /images/models/{author}/{slug}/endpoints\n- \"List all interns?\" -> GET /interns\n- \"Create a intern?\" -> POST /interns\n- \"Delete a intern?\" -> DELETE /interns/{internId}\n- \"Get intern details?\" -> GET /interns/{internId}\n- \"Partially update a intern?\" -> PATCH /interns/{internId}\n- \"Create a completion?\" -> POST /interns/{internId}/chat/completions\n- \"Create a provision?\" -> POST /interns/{internId}/provision\n- \"Create a suspend?\" -> POST /interns/{internId}/suspend\n- \"List all key?\" -> GET /key\n- \"List all keys?\" -> GET /keys\n- \"Create a key?\" -> POST /keys\n- \"Delete a key?\" -> DELETE /keys/{hash}\n- \"Get key details?\" -> GET /keys/{hash}\n- \"Partially update a key?\" -> PATCH /keys/{hash}\n- \"Create a message?\" -> POST /messages\n- \"Get model details?\" -> GET /model/{author}/{slug}\n- \"Search models?\" -> GET /models\n- \"List all endpoints?\" -> GET /models/{author}/{slug}/endpoints\n- \"List all count?\" -> GET /models/count\n- \"List all user?\" -> GET /models/user\n- \"List all jwks?\" -> GET /oauth/jwks\n- \"Create a token?\" -> POST /oauth/token\n- \"List all destinations?\" -> GET /observability/destinations\n- \"Create a destination?\" -> POST /observability/destinations\n- \"Delete a destination?\" -> DELETE /observability/destinations/{id}\n- \"Get destination details?\" -> GET /observability/destinations/{id}\n- \"Partially update a destination?\" -> PATCH /observability/destinations/{id}\n- \"List all members?\" -> GET /organization/members\n- \"List all presets?\" -> GET /presets\n- \"Get preset details?\" -> GET /presets/{slug}\n- \"Create a completion?\" -> POST /presets/{slug}/chat/completions\n- \"Create a message?\" -> POST /presets/{slug}/messages\n- \"Create a response?\" -> POST /presets/{slug}/responses\n- \"List all versions?\" -> GET /presets/{slug}/versions\n- \"Get version details?\" -> GET /presets/{slug}/versions/{version}\n- \"List all providers?\" -> GET /providers\n- \"Create a rerank?\" -> POST /rerank\n- \"Create a response?\" -> POST /responses\n- \"List all group-mappings?\" -> GET /scim/group-mappings\n- \"Create a group-mapping?\" -> POST /scim/group-mappings\n- \"Delete a group-mapping?\" -> DELETE /scim/group-mappings/{id}\n- \"Get group-mapping details?\" -> GET /scim/group-mappings/{id}\n- \"Partially update a group-mapping?\" -> PATCH /scim/group-mappings/{id}\n- \"List all groups?\" -> GET /scim/groups\n- \"Create a sync-job?\" -> POST /scim/sync-jobs\n- \"Get sync-job details?\" -> GET /scim/sync-jobs/{id}\n- \"Create a systemone?\" -> POST /systemone\n- \"List all secrets?\" -> GET /vault/interns/{internId}/secrets\n- \"Delete a secret?\" -> DELETE /vault/interns/{internId}/secrets/{name}\n- \"Update a secret?\" -> PUT /vault/interns/{internId}/secrets/{name}\n- \"Create a copy?\" -> POST /vault/interns/{internId}/secrets/copy\n- \"List all secrets?\" -> GET /vault/secrets\n- \"Delete a secret?\" -> DELETE /vault/secrets/{name}\n- \"Update a secret?\" -> PUT /vault/secrets/{name}\n- \"Create a video?\" -> POST /videos\n- \"Get video details?\" -> GET /videos/{jobId}\n- \"List all content?\" -> GET /videos/{jobId}/content\n- \"List all models?\" -> GET /videos/models\n- \"List all workspaces?\" -> GET /workspaces\n- \"Create a workspace?\" -> POST /workspaces\n- \"Delete a workspace?\" -> DELETE /workspaces/{id}\n- \"Get workspace details?\" -> GET /workspaces/{id}\n- \"Partially update a workspace?\" -> PATCH /workspaces/{id}\n- \"List all members?\" -> GET /workspaces/{id}/members\n- \"Create a add?\" -> POST /workspaces/{id}/members/add\n- \"Create a remove?\" -> POST /workspaces/{id}/members/remove\n- \"List all budgets?\" -> GET /workspaces/{workspace_ref}/budgets\n- \"Delete a budget?\" -> DELETE /workspaces/{workspace_ref}/budgets/{interval}\n- \"Get budget details?\" -> GET /workspaces/{workspace_ref}/budgets/{interval}\n- \"Update a budget?\" -> PUT /workspaces/{workspace_ref}/budgets/{interval}\n- \"How to authenticate?\" -> See Auth section\n\n## Response Tips\n- Check response schemas in references/api-spec.lap for field details\n- List endpoints may support pagination; check for limit, offset, or cursor params\n- Create/update endpoints typically return the created/updated object\n\n## CLI\n\n```bash\n# Update this spec to the latest version\nnpx @lap-platform/lapsh get openrouter-api -o references/api-spec.lap\n\n# Search for related APIs\nnpx @lap-platform/lapsh search openrouter-api\n```\n\n## References\n- Full spec: See references/api-spec.lap for complete endpoint details, parameter tables, and response schemas\n\n> Generated from the official API spec by [LAP](https://lap.sh)\n","references/api-spec.lap":"@lap v0.3\n# Machine-readable API spec. Each @endpoint block is one API call.\n@api OpenRouter API\n@base https://openrouter.ai/api/v1\n@version 1.0.0\n@auth Bearer bearer | Bearer bearer\n@endpoints 122\n@hint download_for_search\n@toc activity(1), analytics(2), api(1), audio(2), auth(2), benchmarks(1), byok(5), chat(1), classifications(1), containers(4), credits(2), datasets(3), embeddings(2), endpoints(1), files(5), generation(3), guardrails(13), images(3), interns(8), key(1), keys(5), messages(1), model(1), models(4), oauth(2), observability(5), organization(1), presets(7), providers(1), rerank(1), responses(1), scim(8), systemone(1), vault(7), videos(4), workspaces(12)\n\n@group activity\n@endpoint GET /activity\n@desc Get user activity grouped by endpoint\n@optional {date: str # Filter by a single UTC date in the last 30 days (YYYY-MM-DD format)., api_key_hash: str # Filter by API key hash (SHA-256 hex string, as returned by the keys API)., user_id: str # Filter by org member user ID. Only applicable for organization accounts., group_by: str # Set to 'workspace' to split each row per workspace and include `workspace_id` on every item. Omitted by default, in which case rows are aggregated across workspaces (by date, model, and endpoint) and `workspace_id` is not returned — preserving the historical response shape., workspace_id: str # Filter by workspace ID (UUID). Returns only activity attributed to that workspace. The workspace must belong to the authenticated account.}\n@returns(200) {data: [map]} # Returns user activity data grouped by endpoint\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group analytics\n@endpoint GET /analytics/meta\n@desc Get available analytics metrics and dimensions\n@returns(200) {data: map{dimensions: [map], granularities: [map], metrics: [map], operators: [map]}} # Returns analytics query metadata\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /analytics/query\n@desc Query analytics data\n@required {metrics: [str]}\n@optional {classifier_dimensions: map{classifier_id!: str(uuid), dimension_names: [str], include_nulls: bool} # Group results by custom classifier tags, breaking down metrics by the specified dimension values. Requires an active classifier on the workspace., classifier_filters: map{classifier_id!: str(uuid), filters!: [map]} # Filter results to generations with specific classifier tag values. Can be combined with classifier_dimensions (must use the same classifier_id) or used independently with standard dimensions., dimensions: [str], filters: [map{field!: str, include_unset: bool, operator!: str, value!: any}], granularity: str # Time granularity, group_limit: int # Maximum rows per distinct combination of dimensions. When omitted on time-series queries (granularity + dimensions), auto-computed to avoid truncating time windows. Explicit values override the default and may truncate time buckets if set lower than the number of buckets in the range. Ignored when no dimensions are specified., limit: int # Maximum total rows returned. Defaults to 1000. On time-series queries with dimensions and no explicit group_limit, the server may raise this to accommodate the expected number of unique time-bucket/dimension combinations., order_by: map{direction!: str, field!: str}, time_range: map{end!: str(date-time), start!: str(date-time)}}\n@returns(200) {data: map{cachedAt: num(double), data: [map], metadata: map{query_time_ms: num(double), row_count: int, truncated: bool}, warnings: [str]}} # Analytics query results\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 408: Request Timeout - Operation exceeded time limit, 500: Internal Server Error - Unexpected server error}\n@example_request {\"dimensions\":[\"model\"],\"granularity\":\"day\",\"limit\":100,\"metrics\":[\"request_count\"],\"time_range\":{\"end\":\"2025-01-08T00:00:00Z\",\"start\":\"2025-01-01T00:00:00Z\"}}\n\n@endgroup\n\n@group api\n@endpoint POST /api/alpha/decisions\n@desc Submit a Decisions (questions and answers) request\n@required {model: str, questions: map, state: any # The content to evaluate: a plain string, or a JSON object or array of related context.}\n@optional {provider: any, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str}\n@returns(200) {answers: map, id: str, model: str, provider: str, usage: map{cost: num(double), input_tokens: int, output_tokens: int}} # Decisions response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"model\":\"typesafe/jev-1.13\",\"questions\":{\"is_bug\":{\"criteria\":{\"false\":\"The customer is asking a question or requesting a feature.\",\"true\":\"The customer describes broken or unexpected product behavior.\"},\"instructions\":\"Is the customer reporting a software defect?\",\"type\":\"noul\"},\"team\":{\"criteria\":{\"account\":\"Login, permissions, or profile issues.\",\"frontend\":\"Rendering, layout, or browser compatibility issues.\",\"payments\":\"Checkout, billing, or payment processing issues.\"},\"instructions\":\"Which team should own this ticket?\",\"type\":\"choice\"},\"urgency\":{\"criteria\":[\"Can wait for the next release\",\"Should be fixed this week\",\"Blocking revenue right now\"],\"instructions\":\"How urgent is this ticket?\",\"type\":\"score\"}},\"state\":{\"customer_tier\":\"enterprise\",\"ticket\":\"My checkout page shows a blank screen after I click Pay. I have tried two browsers.\"}}\n\n@endgroup\n\n@group audio\n@endpoint POST /audio/speech\n@desc Create speech\n@required {input: str # Text to synthesize, model: str # TTS model identifier}\n@optional {input_references: [any] # Reference content for stateless voice cloning: one `input_audio` part carrying the voice sample, optionally accompanied by one `text` part with its transcript. Only routed to endpoints that support voice cloning., provider: map{options: map} # Provider-specific passthrough configuration, response_format: str(mp3/pcm)=pcm # Audio output format, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., speed: num(double) # Playback speed multiplier. Only used by models that support it (e.g. OpenAI TTS). Ignored by other providers., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A unique identifier representing your end-user. Forwarded to Broadcast and private logging as the end-user id; never sent to the provider., voice: str # Voice identifier (provider-specific).}\n@returns(200) Audio bytes stream\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"input\":\"Hello world\",\"model\":\"mistralai/voxtral-mini-tts-2603\",\"response_format\":\"pcm\",\"speed\":1,\"voice\":\"en_paul_neutral\"}\n\n@endpoint POST /audio/transcriptions\n@desc Create transcription\n@required {input_audio: map{data!: str, format!: str} # Base64-encoded audio to transcribe, model: str # STT model identifier}\n@optional {language: str # ISO-639-1 language code (e.g., \"en\", \"ja\"). Auto-detected if omitted., provider: map{options: map} # Provider-specific passthrough configuration, response_format: str(json/verbose_json) # Output format. \"json\" (default) returns { text, usage }. \"verbose_json\" additionally returns task, language, duration, and segment-level timestamps; only supported by OpenAI-compatible providers., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., temperature: num(double) # Sampling temperature for transcription, timestamp_granularities: [str] # Timestamp detail levels to include when response_format is \"verbose_json\". \"segment\" returns segment-level timestamps; \"word\" additionally returns word-level timestamps in the words array. Ignored unless response_format is \"verbose_json\"., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A unique identifier representing your end-user. Forwarded to Broadcast and private logging as the end-user id; never sent to the provider.}\n@returns(200) {confidence: num(double), duration: num(double), language: str, segments: [map], task: str, text: str, usage: map{cost: num(double), input_tokens: int, output_tokens: int, seconds: num(double), total_tokens: int}, words: [map]} # Transcription result\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 504: Gateway Timeout - Provider did not respond before the upstream deadline, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"input_audio\":{\"data\":\"UklGRiQA...\",\"format\":\"wav\"},\"language\":\"en\",\"model\":\"openai/whisper-large-v3\"}\n\n@endgroup\n\n@group auth\n@endpoint POST /auth/keys\n@desc Exchange authorization code for API key\n@required {code: str # The authorization code received from the OAuth redirect}\n@optional {code_challenge_method: str(S256/plain) # The method used to generate the code challenge, code_verifier: str # The code verifier if code_challenge was used in the authorization request}\n@returns(200) {key: str, user_id: str?} # Successfully exchanged code for an API key\n@errors {400: Bad Request - Invalid request parameters or malformed input, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n@example_request {\"code\":\"auth_code_abc123def456\",\"code_challenge_method\":\"S256\",\"code_verifier\":\"dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk\"}\n\n@endpoint POST /auth/keys/code\n@desc Create authorization code\n@required {callback_url: str(uri) # The callback URL to redirect to after authorization. Supports https URLs and localhost/127.0.0.1 URLs on any port for local CLI tools.}\n@optional {code_challenge: str # PKCE code challenge for enhanced security, code_challenge_method: str(S256/plain) # The method used to generate the code challenge, expires_at: str(date-time) # Optional ISO 8601 UTC expiration timestamp. Must include seconds (YYYY-MM-DDTHH:MM:SSZ; fractional seconds allowed); minute-precision timestamps are rejected., key_label: str # Optional custom label for the API key. Defaults to the app name if not provided., limit: num(double) # Credit limit for the API key to be created, spawn_agent: str # Agent identifier for spawn telemetry, spawn_cloud: str # Cloud identifier for spawn telemetry, usage_limit_type: str(daily/weekly/monthly) # Optional credit limit reset interval. When set, the credit limit resets on this interval., workspace_id: str(uuid) # Optional workspace ID to associate the API key with}\n@returns(200) {data: map{app_id: int, created_at: str, id: str}} # Successfully created authorization code\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n@example_request {\"callback_url\":\"https://myapp.com/auth/callback\",\"code_challenge\":\"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM\",\"code_challenge_method\":\"S256\",\"limit\":100}\n\n@endgroup\n\n@group benchmarks\n@endpoint GET /benchmarks\n@desc List Benchmarks\n@optional {source: str(artificial-analysis/design-arena/openrouter) # Benchmark source to query. Determines the shape of the returned items. When omitted, returns results from all sources., task_type: str(coding/intelligence/agentic/search) # Filter results by task type. For Artificial Analysis, maps to the corresponding index. For Design Arena, maps to the matching category. `search` returns OpenRouter search benchmark results only., benchmark_type: str(gpqa_diamond/tau_bench_verified_airline/search_browsecomp/search_hle/search_dsqa/search_widesearch) # Return results for one exact OpenRouter benchmark. A `search_*` value narrows the response to search results only; a classic value narrows the OpenRouter items and leaves other sources' items as they are., include_run_config: bool=false # Search benchmarks only: include the published lane configuration whitelist in each search item. Defaults to false. The whitelist is limited to agent turn count, reasoning effort, and temperature so future harness configuration changes do not change the public contract., search_engine: str # OpenRouter search benchmarks only: filter by the search engine used., search_surface: str(server-tool/plugin) # OpenRouter search benchmarks only: filter by the request surface the lane ran on., arena: str(models/builders/agents) # Design Arena only: arena to query. Defaults to `models` when source is `design-arena`., category: str # Design Arena only: category within the arena (e.g. `codecategories`, `uicomponent`, `gamedev`, `3d`, `dataviz`, `image`, `video`, `svg`). When omitted, returns all categories., max_results: int # Maximum number of items to return. When omitted, all matching results are returned.}\n@returns(200) {data: [any], meta: map{as_of: str, citation: str?, model_count: int, source: str?, source_url: str?, task_type: str?, version: str}} # Benchmark results filtered by the specified source and optional task type.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group byok\n@endpoint GET /byok\n@desc List BYOK provider credentials\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100), workspace_id: str(uuid) # Optional workspace ID to filter by. When omitted, resolves to the account’s default workspace; if that default has been deleted, the request returns a 400 and you must pass `workspace_id` explicitly., provider: str(ai21/aion-labs/akashml/alibaba/amazon-bedrock/amazon-bedrock/claude-on-aws/amazon-nova/ambient/anthropic/anthropic/2/arcee-ai/assemblyai/atlas-cloud/avian/azure/baidu/baseten/black-forest-labs/byteplus/cerebras/chutes/cirrascale/clarifai/claude-on-aws/cloudflare/cohere/coreweave/cosine/crusoe/darkbloom/databricks/decart/deepgram/deepinfra/deepseek/dekallm/digitalocean/featherless/fireworks/fish-audio/friendli/gmicloud/google-ai-studio/google-vertex/groq/heygen/inception/inceptron/inferact-vllm/inference-net/infermatic/inflection/io-net/ionstream/krea/liquid/makora/mancer/mara/meta/minimax/mistral/modal/modelrun/modular/moonshotai/morph/near-ai/nebius/nex-agi/nextbit/novita/nvidia/ollama/open-inference/openai/parasail/perceptron/perplexity/phala/poolside/primeintellect/quiver/recraft/reka/relace/runway/sail-research/sakana/sakana-ai/sambanova/seed/siliconflow/sourceful/stepfun/streamlake/switchpoint/tencent/tenstorrent/thinkingmachines/together/typesafe/unbiased/upstage/venice/voyageai/wafer/wandb/wandb-legacy/xai/xiaomi/z-ai) # Optional provider slug to filter by (e.g. `openai`, `anthropic`, `amazon-bedrock`).}\n@returns(200) {data: [map], total_count: int} # List of BYOK credentials\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /byok\n@desc Create a BYOK provider credential\n@required {key: str # The raw provider API key or credential. This value is encrypted at rest and never returned in API responses., provider: str(ai21/aion-labs/akashml/alibaba/amazon-bedrock/amazon-bedrock/claude-on-aws/amazon-nova/ambient/anthropic/anthropic/2/arcee-ai/assemblyai/atlas-cloud/avian/azure/baidu/baseten/black-forest-labs/byteplus/cerebras/chutes/cirrascale/clarifai/claude-on-aws/cloudflare/cohere/coreweave/cosine/crusoe/darkbloom/databricks/decart/deepgram/deepinfra/deepseek/dekallm/digitalocean/featherless/fireworks/fish-audio/friendli/gmicloud/google-ai-studio/google-vertex/groq/heygen/inception/inceptron/inferact-vllm/inference-net/infermatic/inflection/io-net/ionstream/krea/liquid/makora/mancer/mara/meta/minimax/mistral/modal/modelrun/modular/moonshotai/morph/near-ai/nebius/nex-agi/nextbit/novita/nvidia/ollama/open-inference/openai/parasail/perceptron/perplexity/phala/poolside/primeintellect/quiver/recraft/reka/relace/runway/sail-research/sakana/sakana-ai/sambanova/seed/siliconflow/sourceful/stepfun/streamlake/switchpoint/tencent/tenstorrent/thinkingmachines/together/typesafe/unbiased/upstage/venice/voyageai/wafer/wandb/wandb-legacy/xai/xiaomi/z-ai) # The upstream provider this credential authenticates against, as a lowercase slug (e.g. `openai`, `anthropic`, `amazon-bedrock`).}\n@optional {allowed_api_key_hashes: [str] # Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) that may use this credential. `null` means no restriction. Must contain at least one hash if provided. Hashes that do not belong to your account return a 400., allowed_models: [str] # Optional allowlist of model slugs this credential may be used for. `null` means no restriction., allowed_user_ids: [str] # Optional allowlist of user IDs that may use this credential. `null` means no restriction., disabled: bool # Whether this credential should be created in a disabled state., is_byok_only: bool # Whether OpenRouter's shared endpoints on this provider are removed for every model, including models outside `allowed_models` and after all of your keys for the provider fail. The provider is skipped instead of spending OpenRouter credits. Only valid on non-fallback credentials. Defaults to `false`., is_fallback: bool # Whether this credential is treated as a fallback — used only after non-fallback keys for the same provider have been tried. Cannot be combined with `is_byok_only`., is_required: bool # Whether OpenRouter's shared endpoints on this provider are removed for the models this credential applies to (its `allowed_models`, or every model when `null`). Requests for those models run only on your keys; models outside the allowlist may still fall back to shared capacity on this provider. Defaults to `false`., name: str # Optional human-readable name for the credential., workspace_id: str(uuid) # Optional workspace ID to scope the credential to. When omitted, the credential is created in the account's default workspace; if that default has been deleted, the request returns a 400 and you must pass `workspace_id` explicitly.}\n@returns(201) {data: any} # BYOK credential created successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n@example_request {\"key\":\"sk-proj-abc123...\",\"name\":\"Production OpenAI Key\",\"provider\":\"openai\"}\n\n@endpoint DELETE /byok/{id}\n@desc Delete a BYOK provider credential\n@required {id: str(uuid) # The BYOK credential ID (UUID).}\n@returns(200) {deleted: bool} # BYOK credential deleted successfully\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /byok/{id}\n@desc Get a BYOK provider credential\n@required {id: str(uuid) # The BYOK credential ID (UUID).}\n@returns(200) {data: any} # BYOK credential details\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint PATCH /byok/{id}\n@desc Update a BYOK provider credential\n@required {id: str(uuid) # The BYOK credential ID (UUID).}\n@optional {allowed_api_key_hashes: [str] # Optional allowlist of OpenRouter API key hashes (`api_keys.hash`) that may use this credential. `null` clears the restriction. Must contain at least one hash if provided. Hashes that do not belong to your account return a 400., allowed_models: [str] # Optional allowlist of model slugs this credential may be used for. `null` means no restriction., allowed_user_ids: [str] # Optional allowlist of user IDs that may use this credential. `null` means no restriction., disabled: bool # Whether this credential is disabled., is_byok_only: bool # Whether OpenRouter's shared endpoints on this provider are removed for every model, including models outside `allowed_models` and after all of your keys for the provider fail. The provider is skipped instead of spending OpenRouter credits. Only valid on non-fallback credentials. Omit to leave the stored value unchanged., is_fallback: bool # Whether this credential is treated as a fallback — used only after non-fallback keys for the same provider have been tried. Cannot be combined with `is_byok_only`. Omit to leave the stored value unchanged., is_required: bool # Whether OpenRouter's shared endpoints on this provider are removed for the models this credential applies to (its `allowed_models`, or every model when `null`). Requests for those models run only on your keys; models outside the allowlist may still fall back to shared capacity on this provider. Omit to leave the stored value unchanged., key: str # A new raw provider API key to rotate the credential in-place. The previous key material is overwritten and the masked label is regenerated. Encrypted at rest and never returned in API responses., name: str # Optional human-readable name for the credential.}\n@returns(200) {data: any} # BYOK credential updated successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"disabled\":false,\"name\":\"Updated OpenAI Key\"}\n\n@endgroup\n\n@group chat\n@endpoint POST /chat/completions\n@desc Create a chat completion\n@required {messages: [any] # List of messages for the conversation}\n@optional {X-OpenRouter-Metadata: str # Opt-in to surface routing metadata on the response under `openrouter_metadata`. Defaults to `disabled`. The legacy header `X-OpenRouter-Experimental-Metadata` is also accepted for backward compatibility., cache_control: map{ttl: str, type!: str} # Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format., debug: map{echo_upstream_body: bool} # Debug options for inspecting request transformations (streaming only), frequency_penalty: num(double) # Frequency penalty (-2.0 to 2.0), image_config: map # Provider-specific image configuration options. Keys and values vary by model/provider. See https://openrouter.ai/docs/guides/overview/multimodal/image-generation for more details., logit_bias: map # Token logit bias adjustments, logprobs: bool # Return log probabilities, max_completion_tokens: int # Maximum tokens in completion, max_tokens: int # Maximum tokens (deprecated, use max_completion_tokens). Note: some providers enforce a minimum of 16., metadata: map # Key-value pairs for additional object information (max 16 pairs, 64 char keys, 512 char values), min_p: num(double) # Minimum probability threshold relative to the most likely token. Tokens with probability below min_p * (probability of top token) are filtered out. Not all providers support this parameter., modalities: [str] # Output modalities for the response. Supported values are \"text\", \"image\", and \"audio\"., model: str # Model to use for completion, models: [any] # Models to use for completion, parallel_tool_calls: bool # Whether to enable parallel function calling during tool use. When true, the model may generate multiple tool calls in a single response., plugins: [any] # Plugins you want to enable for this request, including their settings., prediction: map{content!: any, type!: str} # Static predicted output content. Supported models can use this to reduce latency when much of the response is known in advance., presence_penalty: num(double) # Presence penalty (-2.0 to 2.0), prompt_cache_key: str, prompt_cache_options: map{mode!: str, ttl: str} # Request-level prompt-cache controls. `mode: \"explicit\"` disables OpenAI-managed breakpoints so only blocks marked with `prompt_cache_breakpoint` are cached. Only supported by OpenAI GPT-5.6 and newer., provider: map{allow_fallbacks: bool, data_collection: str, enforce_distillable_text: bool, ignore: [any], max_price: map, only: [any], order: [any], preferred_max_latency: any, preferred_min_throughput: any, quantizations: [str], require_parameters: bool, sort: any, zdr: bool} # When multiple model providers are available, optionally indicate your routing preference., reasoning: map{effort: str, summary: str} # Configuration options for reasoning models, reasoning_effort: str(max/xhigh/high/medium/low/minimal/none) # Shorthand for setting reasoning effort. Equivalent to setting reasoning.effort. Cannot be used simultaneously with reasoning.effort if they differ., repetition_penalty: num(double) # Penalizes tokens based on how much they have already appeared in the text. A value of 1.0 means no penalty. Values above 1.0 penalize repeated tokens more strongly. Not all providers support this parameter., response_format: any # Response format configuration, route: str(fallback/sort) # **DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\")., seed: int # Random seed for deterministic outputs, service_tier: str(auto/default/fast/flex/priority/scale) # The service tier to use for processing this request. `fast` is accepted as an alias for `priority`., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., stop: any # Stop sequences (up to 4), stop_server_tools_when: [any] # Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call., stream: bool=false # Enable streaming response, stream_options: map{include_usage: bool} # Streaming configuration options, temperature: num(double) # Sampling temperature (0-2), tool_choice: any # Tool choice configuration, tools: [any] # Available tools for function calling, top_a: num(double) # Consider only tokens with \"sufficiently high\" probabilities based on the probability of the most likely token. Not all providers support this parameter., top_k: int # Limits the model to choose from the top K most likely tokens at each step. A value of 1 means the model will always pick the most likely next token. Not all providers support this parameter., top_logprobs: int # Number of top log probabilities to return (0-20), top_p: num(double) # Nucleus sampling parameter (0-1), trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # Per-end-user identifier for abuse isolation. Use a stable ID, hash, or pseudonym. When a provider requires a user identity, OpenRouter folds it into the hashed identity sent upstream and never forwards it raw. If omitted, requests use an account-level identity, so provider policy blocks can affect the whole account.}\n@returns(200) {choices: [map], created: int, id: str, model: str, object: str, openrouter_metadata: map{attempt: int, attempts: [map], endpoints: map{available: [map], total: int}, generation_time: int, is_byok: bool, params: map{quality_floor: num(double), throughput_floor: num(double), version_group: str}, pipeline: [map], region: str?, requested: str, strategy: str, summary: str}, service_tier: str?, system_fingerprint: str?, usage: map{completion_tokens: int, completion_tokens_details: map?, cost: num(double)?, cost_details: map?, is_byok: bool, prompt_tokens: int, prompt_tokens_details: map?, server_tool_use_details: map?, total_tokens: int}} # Successful chat completion response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, or a guardrail blocked the request. When guardrails block and the `X-OpenRouter-Metadata: enabled` header is present, the response includes `openrouter_metadata` with full routing context and a `pipeline` array containing guardrail stage details., 404: Not Found - Resource does not exist, 408: Request Timeout - Operation exceeded time limit, 413: Payload Too Large - Request payload exceeds size limits, 422: Unprocessable Entity - Semantic validation failure, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"max_tokens\":150,\"messages\":[{\"content\":\"You are a helpful assistant.\",\"role\":\"system\"},{\"content\":\"What is the capital of France?\",\"role\":\"user\"}],\"model\":\"openai/gpt-4\",\"temperature\":0.7}\n\n@endgroup\n\n@group classifications\n@endpoint GET /classifications/task\n@desc Task classification market share\n@optional {window: str=7d # Trailing time window for the classification data. Currently only `7d` (trailing 7 days) is supported.}\n@returns(200) {data: map{as_of: str, classifications: [map], macro_categories: [map], window_days: int}} # Task classification market-share data for the requested trailing window.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group containers\n@endpoint GET /containers/{container_id}/files\n@desc List container files\n@required {container_id: str # The canonical container id, exactly as returned in a bash/shell tool result — a restarted session has its own `-r`-suffixed id. A session-derived id is always `sess_` + the sanitized session key, which is not necessarily the raw session id that was sent.}\n@optional {limit: int=100 # Maximum number of files to return (1-1000). Defaults to 100 when absent., after: str # Forward cursor: the previous page’s `last_id` (or any container file id); listing resumes strictly after that path.}\n@returns(200) {data: [map], first_id: str?, has_more: bool, last_id: str?, object: str} # The files in the container.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint GET /containers/{container_id}/files/{file_id}\n@desc Retrieve a container file\n@required {container_id: str # The canonical container id, exactly as returned in a bash/shell tool result — a restarted session has its own `-r`-suffixed id. A session-derived id is always `sess_` + the sanitized session key, which is not necessarily the raw session id that was sent., file_id: str # Container file id (`cfile_` + base64url of the file path).}\n@returns(200) {bytes: int, container_id: str, created_at: int, id: str, object: str, path: str, source: str} # The container file.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint GET /containers/{container_id}/files/{file_id}/content\n@desc Download container file content\n@required {container_id: str # The canonical container id, exactly as returned in a bash/shell tool result — a restarted session has its own `-r`-suffixed id. A session-derived id is always `sess_` + the sanitized session key, which is not necessarily the raw session id that was sent., file_id: str # Container file id (`cfile_` + base64url of the file path).}\n@returns(200) The raw file content.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint POST /containers/{container_id}/files/{file_id}/promote\n@desc Promote a container file into workspace documents\n@required {container_id: str # The canonical container id, exactly as returned in a bash/shell tool result — a restarted session has its own `-r`-suffixed id. A session-derived id is always `sess_` + the sanitized session key, which is not necessarily the raw session id that was sent., file_id: str # Container file id (`cfile_` + base64url of the file path).}\n@returns(200) The promoted file, as a workspace document.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 503: Service Unavailable - Service temporarily unavailable}\n\n@endgroup\n\n@group credits\n@endpoint GET /credits\n@desc Get remaining credits\n@returns(200) {data: map{total_credits: num(double), total_usage: num(double)}} # Returns the total credits purchased and used\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /credits/coinbase\n@desc Deprecated Coinbase Commerce charge endpoint\n@returns(200) This endpoint is deprecated and will never return a 200 response.\n@errors {410: Gone - Endpoint has been permanently removed or deprecated}\n\n@endgroup\n\n@group datasets\n@endpoint GET /datasets/app-rankings\n@desc Top apps by token usage\n@optional {category: str(coding/creative/productivity/entertainment) # Marketplace category group to filter by (e.g. `coding`). Only apps tagged with a subcategory inside this group are returned. Mutually combinable with `subcategory` — when both are supplied the `subcategory` must belong to the `category` group., subcategory: str(cli-agent/ide-extension/cloud-agent/programming-app/native-app-builder/creative-writing/video-gen/image-gen/audio-gen/roleplay/game/writing-assistant/general-chat/personal-agent/legal) # Marketplace subcategory to filter by (e.g. `cli-agent`). Takes precedence over `category` for the actual filter; when `category` is also supplied the pair must be consistent., sort: str(popular/trending)=popular # `popular` ranks apps by total token volume inside the date window. `trending` ranks apps by absolute excess token growth: window volume minus the average volume of the three equal-length periods immediately preceding the window. Apps with no excess growth are omitted from `trending` results., start_date: str # Start of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to 30 days before `end_date`. The dataset begins at 2025-01-01; earlier values are clamped forward to that floor and the resolved value is echoed in `meta.start_date`., end_date: str # End of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to the most recent completed UTC day. Must be on or after 2025-01-01; earlier values are rejected with a 400., limit: int=50 # Maximum number of apps to return (1-100). Defaults to 50., offset: int=0 # Number of ranked apps to skip before the first returned row (0-100). Defaults to 0. `rank` stays absolute, so the first row of `offset=50` is `rank: 51`.}\n@returns(200) {data: [map], meta: map{as_of: str, end_date: str, start_date: str, version: str}} # Apps ranked per the requested `sort`, re-numbered 1..N. `popular` sorts by `total_tokens` descending; `trending` sorts by absolute excess token growth descending and may return fewer than `limit` rows.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /datasets/rankings-daily\n@desc Daily token totals for top 50 models\n@optional {start_date: str # Start of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to 30 days before `end_date`. The dataset begins at 2025-01-01; earlier values are clamped forward to that floor and the resolved value is echoed in `meta.start_date`., end_date: str # End of the date window in YYYY-MM-DD (UTC), inclusive. Defaults to the most recent completed UTC day. Must be on or after 2025-01-01; earlier values are rejected with a 400., period: str(day/week/month) # Time grain of each row. `day` (default) returns the per-UTC-day series; `week` buckets by ISO week start; `month` buckets by month start. With `category` or `language_type` only `week` (default) and `month` are available — `day` is rejected with a 400 because those datasets are aggregated weekly. For those sampled datasets `period=month` buckets each week by its week-start month, so totals are approximate at month boundaries., modality: str(text/image/image_output/audio/tool_calling) # Restrict to models for a modality surface: `text` / `image_output` match output modality, `image` / `audio` match input modality, and `tool_calling` keeps only rows that recorded at least one tool call. Exact dataset — cannot be combined with `category` or `language_type`., context_bucket: str(1K/10K/100K/1M/10M) # Restrict to requests whose context length falls in this bucket (`1K`, `10K`, `100K`, `1M`, or `10M`). Exact dataset — cannot be combined with `category` or `language_type`., category: str(programming/roleplay/marketing/marketing/seo/technology/science/translation/legal/finance/health/trivia/academia) # Restrict to a use-case category (e.g. `programming`, `roleplay`). Sourced from a sampled, upsampled dataset, so `total_tokens` is an estimate and is aggregated weekly (the trailing weekly bucket may include traffic past `end_date`). Cannot be combined with `modality`, `context_bucket`, or `language_type`., language_type: str(natural/programming) # Restrict to natural-language or programming-language tagged activity. Sourced from a sampled, upsampled dataset, so `total_tokens` is an estimate and is aggregated weekly (the trailing weekly bucket may include traffic past `end_date`). Cannot be combined with `modality`, `context_bucket`, or `category`.}\n@returns(200) {data: [map], meta: map{as_of: str, end_date: str, start_date: str, version: str}} # Up to 51 rows per day — the top 50 public models by `total_tokens` plus a single aggregated `other` row covering every model outside that top 50. Sorted by `date` ascending, then by `total_tokens` descending, with `other` pinned last within its date.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /datasets/session-cost\n@desc Cost per session by harness and model\n@optional {app_slug: str # Filter to one published harness slug., model: str # Exact model permaslug filter. Works across all harness apps., turn_range: str(1-turn/2-9-turns/10-49-turns/50-plus-turns) # Filter by the inclusive number of turns in a session., limit: int=100 # Maximum number of cells to return (1-500). Defaults to 100., offset: int=0 # Number of sorted cells to skip (0-5000). Defaults to 0.}\n@returns(200) {data: [map], meta: map{as_of: str, version: str, window_days: int?, window_end_date: str?}} # Aggregated cost-per-session cells for the requested filters.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group embeddings\n@endpoint POST /embeddings\n@desc Submit an embedding request\n@required {input: any # Text, token, or multimodal input(s) to embed, model: str # The model to use for embeddings}\n@optional {dimensions: int # The number of dimensions for the output embeddings, encoding_format: str(float/base64) # The format of the output embeddings, input_type: str # The type of input (e.g. search_query, search_document), provider: any, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A unique identifier for the end-user}\n@returns(200) {data: [map], id: str, model: str, object: str, usage: map{cost: num(double), cost_details: map?, is_byok: bool, prompt_tokens: int, prompt_tokens_details: map{audio_tokens: int, file_tokens: int, image_tokens: int, text_tokens: int, video_tokens: int}, total_tokens: int}} # Embedding response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 408: Request Timeout - Operation exceeded time limit, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n\n@endpoint GET /embeddings/models\n@desc List all embeddings models\n@optional {offset: int=0 # Number of records to skip for pagination. When both offset and limit are omitted, the full list is returned, limit: int=500 # Maximum number of records to return (max 1000). When both offset and limit are omitted, the full list is returned}\n@returns(200) {data: [map], links: map{next: str?}, total_count: int} # Returns a list of embeddings models\n@errors {400: Bad Request - Invalid request parameters or malformed input, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group endpoints\n@endpoint GET /endpoints/zdr\n@desc Preview the impact of ZDR on the available endpoints\n@returns(200) {data: [map]} # Returns a list of endpoints\n@errors {403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group files\n@endpoint GET /files\n@desc List files\n@optional {limit: int # Maximum number of files to return (1–1000)., cursor: str # Opaque pagination cursor from a previous response., workspace_id: str(uuid) # Workspace to scope the request to. Defaults to the caller’s default workspace., provider: str # Store or read this file on the named provider using your own API key for it. Omit to use OpenRouter storage., after: str # OpenAI-style forward cursor: the id to list after., after_id: str # Anthropic-style forward cursor: the id to list after., before_id: str # Anthropic-style reverse cursor. Not supported by OpenRouter storage., order: str(asc/desc) # Sort direction. Only `asc` is supported by OpenRouter storage.}\n@returns(200) A page of files.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint POST /files\n@desc Upload a file\n@optional {workspace_id: str(uuid) # Workspace to scope the request to. Defaults to the caller’s default workspace., provider: str # Store or read this file on the named provider using your own API key for it. Omit to use OpenRouter storage.}\n@returns(200) The uploaded file metadata.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint DELETE /files/{file_id}\n@desc Delete a file\n@required {file_id: str}\n@optional {workspace_id: str(uuid) # Workspace to scope the request to. Defaults to the caller’s default workspace., provider: str # Store or read this file on the named provider using your own API key for it. Omit to use OpenRouter storage.}\n@returns(200) The file was deleted.\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint GET /files/{file_id}\n@desc Get file metadata\n@required {file_id: str}\n@optional {workspace_id: str(uuid) # Workspace to scope the request to. Defaults to the caller’s default workspace., provider: str # Store or read this file on the named provider using your own API key for it. Omit to use OpenRouter storage.}\n@returns(200) The file metadata.\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable}\n\n@endpoint GET /files/{file_id}/content\n@desc Download file content\n@required {file_id: str}\n@optional {workspace_id: str(uuid) # Workspace to scope the request to. Defaults to the caller’s default workspace., provider: str # Store or read this file on the named provider using your own API key for it. Omit to use OpenRouter storage.}\n@returns(200) The raw file content.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable}\n\n@endgroup\n\n@group generation\n@endpoint GET /generation\n@desc Get request & usage metadata for a generation\n@required {id: str # The generation ID}\n@returns(200) {data: map{api_type: str?, app_id: int?, cache_discount: num(double)?, cancelled: bool?, created_at: str, data_region: str, external_user: str?, finish_reason: str?, generation_time: num(double)?, http_referer: str?, id: str, is_byok: bool, latency: num(double)?, model: str, moderation_latency: num(double)?, native_finish_reason: str?, native_tokens_cached: int?, native_tokens_completion: int?, native_tokens_completion_images: int?, native_tokens_prompt: int?, native_tokens_reasoning: int?, num_fetches: int?, num_input_audio_prompt: int?, num_media_completion: int?, num_media_prompt: int?, num_search_results: int?, origin: str, preset_id: str?, provider_name: str?, provider_responses: [map]?, request_id: str?, response_cache_source_id: str?, router: str?, service_tier: str?, session_id: str?, streamed: bool?, tokens_completion: int?, tokens_prompt: int?, total_cost: num(double), upstream_id: str?, upstream_inference_cost: num(double)?, usage: num(double), user_agent: str?, web_search_engine: str?, workspace_id: str?}} # Returns the request metadata for this generation\n@errors {401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n\n@endpoint GET /generation/content\n@desc Get stored prompt, completion, and error content for a generation\n@required {id: str # The generation ID}\n@returns(200) {data: map{error: map?, input: any, output: map{completion: str?, reasoning: str?}}} # Returns the stored prompt and completion content, plus the failure error when the generation failed\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n\n@endpoint POST /generation/feedback\n@desc Submit feedback for a generation\n@required {category: str(latency/incoherence/incorrect_response/formatting/billing/api_error/other) # The category of feedback being reported, generation_id: str # The generation to submit feedback on}\n@optional {comment: str # An optional free-text comment describing the feedback}\n@returns(200) {data: map{success: bool}} # Feedback recorded successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n@example_request {\"category\":\"incorrect_response\",\"comment\":\"The model repeated the same paragraph three times.\",\"generation_id\":\"gen-3bhGkxlo4XFrqiabUM7NDtwDzWwG\"}\n\n@endgroup\n\n@group guardrails\n@endpoint GET /guardrails\n@desc List guardrails\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100), workspace_id: str(uuid) # Filter guardrails by workspace ID. By default, guardrails in the default workspace are returned.}\n@returns(200) {data: [map], total_count: int} # List of guardrails\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /guardrails\n@desc Create a guardrail\n@required {name: str # Name for the new guardrail}\n@optional {allowed_data_regions: [str] # Data regions through which requests governed by this guardrail must arrive. `global` is https://openrouter.ai, `europe` is https://eu.openrouter.ai, and `us` is https://us.openrouter.ai. Requests arriving through any other region are rejected. `null` leaves the ingress region unrestricted. When several guardrails apply (workspace default, member, API key), the effective regions are the intersection of every non-null value. An empty array is rejected., allowed_models: [str] # Array of model identifiers (slug or canonical_slug accepted), allowed_providers: [str] # List of allowed provider IDs, content_filter_builtins: [map{action!: str, label: str, scan_scope: str, slug!: str}] # Builtin content filters to apply. Every builtin slug supports \"block\", \"redact\", and the detect-only \"flag\" action., content_filters: [map{action!: str, label: str, pattern!: str}] # Custom regex content filters to apply to request messages, description: str # Description of the guardrail, enable_free_model_publication: bool # Whether this guardrail allows free endpoints that publish prompts., enable_free_model_training: bool # Whether this guardrail allows free endpoints that train on request data., enable_paid_model_training: bool # Whether this guardrail allows paid endpoints that train on request data., enforce_zdr: bool # Deprecated. Use enforce_zdr_anthropic, enforce_zdr_openai, enforce_zdr_google, enforce_zdr_xai, and enforce_zdr_other instead. When provided, its value is copied into any of those per-provider fields that are not explicitly specified on the request., enforce_zdr_anthropic: bool # Whether to enforce zero data retention for Anthropic models. Falls back to enforce_zdr when not provided., enforce_zdr_google: bool # Whether to enforce zero data retention for Google models. Falls back to enforce_zdr when not provided., enforce_zdr_openai: bool # Whether to enforce zero data retention for OpenAI models. Falls back to enforce_zdr when not provided., enforce_zdr_other: bool # Whether to enforce zero data retention for models that are not from Anthropic, OpenAI, Google, or xAI. Falls back to enforce_zdr when not provided., enforce_zdr_xai: bool # Whether to enforce zero data retention for xAI models. Falls back to enforce_zdr when not provided., ignored_models: [str] # Array of model identifiers to exclude from routing (slug or canonical_slug accepted), ignored_providers: [str] # List of provider IDs to exclude from routing, include_byok_in_budgets: bool # Whether BYOK (bring-your-own-key) inference spend counts toward this guardrail's limit_usd, in addition to OpenRouter credit spend. Defaults to false., limit_usd: num(double) # Spending limit in USD. Must be provided together with `reset_interval`: a request that sets only one of the two is rejected with a 400., reset_interval: str(daily/weekly/monthly) # Interval at which the limit resets (daily, weekly, monthly), workspace_id: str(uuid) # The workspace to create the guardrail in. When omitted, the guardrail is created in the default workspace; if that default has been deleted, the request returns a 400 and you must pass `workspace_id` explicitly. This only places the guardrail in the workspace; the created guardrail enforces nothing for that workspace's traffic until it is assigned to API keys or members. To restrict all traffic in a workspace, update the workspace's default guardrail instead.}\n@returns(201) {data: any} # Guardrail created successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: The workspace is not owned by this account, or the guardrail would give a HIPAA-enabled workspace a person-name or address sensitive-info filter, which is not available there., 500: Internal Server Error - Unexpected server error}\n@example_request {\"allowed_data_regions\":[\"europe\"],\"allowed_models\":null,\"allowed_providers\":[\"openai\",\"anthropic\",\"deepseek\"],\"description\":\"A guardrail for limiting API usage\",\"enforce_zdr_anthropic\":true,\"enforce_zdr_google\":false,\"enforce_zdr_openai\":true,\"enforce_zdr_other\":false,\"enforce_zdr_xai\":false,\"ignored_models\":null,\"ignored_providers\":null,\"limit_usd\":50,\"name\":\"My New Guardrail\",\"reset_interval\":\"monthly\"}\n\n@endpoint DELETE /guardrails/{id}\n@desc Delete a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail to delete}\n@returns(200) {deleted: bool} # Guardrail deleted successfully\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /guardrails/{id}\n@desc Get a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail to retrieve}\n@returns(200) {data: any} # Guardrail details\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Guardrail not found, or the workspace default guardrail has not been configured yet., 500: Internal Server Error - Unexpected server error}\n\n@endpoint PATCH /guardrails/{id}\n@desc Update a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail to update}\n@optional {allowed_data_regions: [str] # Data regions through which requests governed by this guardrail must arrive. `global` is https://openrouter.ai, `europe` is https://eu.openrouter.ai, and `us` is https://us.openrouter.ai. Requests arriving through any other region are rejected. `null` leaves the ingress region unrestricted. When several guardrails apply (workspace default, member, API key), the effective regions are the intersection of every non-null value. An empty array is rejected., allowed_models: [str] # Array of model identifiers (slug or canonical_slug accepted), allowed_providers: [str] # New list of allowed provider IDs, content_filter_builtins: [map{action!: str, label: str, scan_scope: str, slug!: str}] # Builtin content filters to apply. Set to null to remove. Every builtin slug supports \"block\", \"redact\", and the detect-only \"flag\" action., content_filters: [map{action!: str, label: str, pattern!: str}] # Custom regex content filters to apply. Set to null to remove., description: str # New description for the guardrail, enable_free_model_publication: bool # Whether this guardrail allows free endpoints that publish prompts., enable_free_model_training: bool # Whether this guardrail allows free endpoints that train on request data., enable_paid_model_training: bool # Whether this guardrail allows paid endpoints that train on request data., enforce_zdr: bool # Deprecated. Use enforce_zdr_anthropic, enforce_zdr_openai, enforce_zdr_google, enforce_zdr_xai, and enforce_zdr_other instead. When provided, its value is copied into any of those per-provider fields that are not explicitly specified on the request., enforce_zdr_anthropic: bool # Whether to enforce zero data retention for Anthropic models. Falls back to enforce_zdr when not provided., enforce_zdr_google: bool # Whether to enforce zero data retention for Google models. Falls back to enforce_zdr when not provided., enforce_zdr_openai: bool # Whether to enforce zero data retention for OpenAI models. Falls back to enforce_zdr when not provided., enforce_zdr_other: bool # Whether to enforce zero data retention for models that are not from Anthropic, OpenAI, Google, or xAI. Falls back to enforce_zdr when not provided., enforce_zdr_xai: bool # Whether to enforce zero data retention for xAI models. Falls back to enforce_zdr when not provided., ignored_models: [str] # Array of model identifiers to exclude from routing (slug or canonical_slug accepted), ignored_providers: [str] # List of provider IDs to exclude from routing, include_byok_in_budgets: bool # Whether BYOK (bring-your-own-key) inference spend counts toward this guardrail's limit_usd, in addition to OpenRouter credit spend. Omit to leave unchanged., limit_usd: num(double) # New spending limit in USD, name: str # New name for the guardrail, reset_interval: str(daily/weekly/monthly) # Interval at which the limit resets (daily, weekly, monthly)}\n@returns(200) {data: any} # Guardrail updated successfully\n@errors {400: Invalid request, or an attempt to change a workspace default guardrail's name (which is derived from its workspace and not editable; sending the current name unchanged is accepted)., 401: Unauthorized - Authentication required or invalid credentials, 403: The update would give a HIPAA-enabled workspace a person-name or address sensitive-info filter, which is not available there., 404: Not Found - Resource does not exist, 409: Guardrail name conflict — another guardrail in this workspace already uses the requested name., 500: Internal Server Error - Unexpected server error}\n@example_request {\"description\":\"Updated description\",\"limit_usd\":75,\"name\":\"Updated Guardrail Name\",\"reset_interval\":\"weekly\"}\n\n@endpoint GET /guardrails/{id}/assignments/keys\n@desc List key assignments for a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail}\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of key assignments\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /guardrails/{id}/assignments/keys\n@desc Bulk assign keys to a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail, key_hashes: [str] # Array of API key hashes to assign to the guardrail}\n@returns(200) {assigned_count: int} # Assignment result\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: The guardrail has no workspace and carries a person-name or address sensitive-info filter, and at least one target key belongs to a HIPAA-enabled workspace, where that filter is not available., 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"key_hashes\":[\"c56454edb818d6b14bc0d61c46025f1450b0f4012d12304ab40aacb519fcbc93\"]}\n\n@endpoint POST /guardrails/{id}/assignments/keys/remove\n@desc Bulk unassign keys from a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail, key_hashes: [str] # Array of API key hashes to unassign from the guardrail}\n@returns(200) {unassigned_count: int} # Unassignment result\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"key_hashes\":[\"c56454edb818d6b14bc0d61c46025f1450b0f4012d12304ab40aacb519fcbc93\"]}\n\n@endpoint GET /guardrails/{id}/assignments/members\n@desc List member assignments for a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail}\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of member assignments\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /guardrails/{id}/assignments/members\n@desc Bulk assign members to a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail, member_user_ids: [str] # Array of member user IDs to assign to the guardrail}\n@returns(200) {assigned_count: int} # Assignment result\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"member_user_ids\":[\"user_abc123\",\"user_def456\"]}\n\n@endpoint POST /guardrails/{id}/assignments/members/remove\n@desc Bulk unassign members from a guardrail\n@required {id: str(uuid) # The unique identifier of the guardrail, member_user_ids: [str] # Array of member user IDs to unassign from the guardrail}\n@returns(200) {unassigned_count: int} # Unassignment result\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"member_user_ids\":[\"user_abc123\",\"user_def456\"]}\n\n@endpoint GET /guardrails/assignments/keys\n@desc List all key assignments\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of key assignments\n@errors {401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /guardrails/assignments/members\n@desc List all member assignments\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of member assignments\n@errors {401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group images\n@endpoint POST /images\n@desc Generate an image\n@required {model: str # The image generation model to use, prompt: str # Text description of the desired image}\n@optional {aspect_ratio: str(1:1/1:2/1:4/1:8/2:1/2:3/2.35:1/3:2/3:4/4:1/4:3/4:5/5:2/5:4/8:1/9:16/16:9/9:19.5/19.5:9/9:20/20:9/9:21/21:9/auto) # Normalized aspect ratio of the generated image. Providers clamp to their supported subset., background: str(auto/transparent/opaque) # Background treatment. `transparent` requires an output_format that supports alpha (png or webp)., input_references: [map{image_url!: map, type!: str}] # Reference images to guide image-to-image generation, as base64 data URLs or HTTP(S) URLs., n: int # Upper bound on the number of images to generate (1-10). Providers may return fewer images, and providers that only support single-image generation reject n > 1., output_compression: int # Compression level (0-100) for webp/jpeg output. Ignored for png and by providers without a compression knob., output_format: str(png/jpeg/webp/svg) # Encoding of the returned image bytes. Most models produce raster formats (png, jpeg, webp). SVG is supported by vectorization models (e.g. Quiver) — the SVG markup is UTF-8 base64-encoded in `b64_json`., provider: map{allow_fallbacks: bool, ignore: [any], only: [any], options: any, order: [any], sort: any} # Provider routing preferences and provider-specific passthrough configuration., quality: str(auto/low/medium/high/xhigh/max) # Rendering quality. Providers without a quality knob ignore this., resolution: str(512/1K/2K/4K) # Normalized resolution tier of the generated image. Concrete pixel dimensions are derived per-provider., seed: int # If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., size: str # Optional. A convenience shorthand for output dimensions — pass a tier (\"2K\", \"4K\") or explicit pixels (\"2048x2048\") and we normalize it to the right dimensions for the chosen provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative: a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400., stream: bool # If true, partial images are streamed as SSE events as they become available. Only supported by providers with native streaming (currently OpenAI). Non-streaming providers ignore this flag and return a buffered response., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A stable identifier for your end-users. Used to help detect and prevent abuse. Never sent to providers verbatim: for providers whose data policy requires user IDs, it is folded into a hashed, per-account upstream user identifier.}\n@returns(200) {created: int, data: [map], usage: map{cache_creation: map?, completion_tokens: int, completion_tokens_details: map?, cost: num(double)?, cost_details: map?, is_byok: bool, iterations: [any]?, prompt_tokens: int, prompt_tokens_details: map?, server_tool_use: map?, service_tier: str?, speed: str?, total_tokens: int}} # Image generation response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"model\":\"bytedance-seed/seedream-4.5\",\"prompt\":\"a red panda astronaut floating in space, studio lighting\"}\n\n@endpoint GET /images/models\n@desc List image generation models\n@returns(200) {data: [map]} # List of image generation models\n@errors {500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /images/models/{author}/{slug}/endpoints\n@desc List endpoints for an image model\n@required {author: str # Model author/organization, slug: str # Model slug}\n@returns(200) {endpoints: [map], id: str} # The full per-endpoint records for an image model\n@errors {404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group interns\n@endpoint GET /interns\n@desc List interns\n@optional {limit: int # Maximum number of interns to return, from 1 through 500., status: [str] # Comma-separated lifecycle statuses to include., starting_after: str # The opaque `next_cursor` of the previous page. Returns the interns that come after it in the newest-first order. A malformed cursor is a 400., workspace_id: str(uuid) # Only return interns in this workspace. It must match the API key workspace.}\n@returns(200) {data: [map], has_more: bool, next_cursor: str} # Interns matching the filters.\n@errors {400: The list filters are invalid., 401: Missing, unknown or provisioning API key., 403: The key owner no longer has access, or the request used a regional hostname., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 500: The request could not be completed.}\n\n@endpoint POST /interns\n@desc Create an intern\n@required {name: str # Intern name, unique per creator within the workspace.}\n@optional {Idempotency-Key: str # Key that makes retries resume the same create operation. Without one, the server derives a stable key from the request body., description: str # Free-form description, or null., instructions: str # Standing instructions the intern boots with, or null., provision: bool=false # Start provisioning during this create operation. Defaults to false., vault_id: str(uuid) # Vault owned by another intern in this workspace to attach as a borrowed vault., workspace_id: str(uuid) # Workspace that will own the intern. Defaults to the workspace the API key resolves to. When given, it must match the API key workspace.}\n@returns(200) {attached_vault_id: str?, created_at: str, description: str?, hostname: str?, id: str, instructions: str?, last_failure_message: str?, model: str?, name: str, progress: map?, status: str, updated_at: str, vault_id: str?, workspace_id: str} # A completed create operation was replayed.\n@returns(201) {attached_vault_id: str?, created_at: str, description: str?, hostname: str?, id: str, instructions: str?, last_failure_message: str?, model: str?, name: str, progress: map?, status: str, updated_at: str, vault_id: str?, workspace_id: str} # Intern created.\n@errors {400: The request body is invalid., 401: Missing, unknown or provisioning API key., 403: The key acts as an organization and has no member who can own the intern, or regional access is refused., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 409: The idempotency key was reused, the intern name is already taken in the workspace, the member reached the intern limit, or the requested vault cannot be attached., 413: The request body is larger than 1048576 bytes., 500: The request could not be completed., 502: The vault or provisioner did not complete a recoverable create step. Retry the same request.}\n@example_request {\"name\":\"research-assistant\",\"provision\":true,\"workspace_id\":\"89f9f5b2-3f89-4eaf-83ca-5ceae149e8bb\"}\n\n@endpoint DELETE /interns/{internId}\n@desc Delete an intern\n@required {internId: str # ID of an intern visible to the authenticated API key.}\n@optional {acknowledge_workspace_loss: bool=false # Delete even though the workspace backup was not confirmed. Defaults to false, which refuses the teardown when a workspace archive is missing.}\n@returns(202) {deleting: bool} # The operation was accepted.\n@errors {400: The request body is invalid., 401: Missing, unknown or provisioning API key., 403: The key owner no longer has access, or the request used a regional hostname., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 409: The intern is not in a state that allows this operation., 413: The request body is larger than 1048576 bytes., 500: The request could not be completed., 502: The intern service could not accept the operation.}\n@example_request {\"acknowledge_workspace_loss\":true}\n\n@endpoint GET /interns/{internId}\n@desc Get an intern\n@required {internId: str # ID of an intern visible to the authenticated API key.}\n@returns(200) {attached_vault_id: str?, created_at: str, description: str?, hostname: str?, id: str, instructions: str?, last_failure_message: str?, model: str?, name: str, progress: map?, status: str, updated_at: str, vault_id: str?, workspace_id: str} # Intern lifecycle state and settings.\n@errors {401: Missing, unknown or provisioning API key., 403: The key owner no longer has access, or the request used a regional hostname., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 500: The request could not be completed.}\n\n@endpoint PATCH /interns/{internId}\n@desc Update an intern\n@required {internId: str # ID of an intern visible to the authenticated API key.}\n@optional {description: str # New free-form description. Null clears it., instructions: str # New standing instructions. Null clears them., model: str # New OpenRouter model slug in `author/slug` form (an optional `:variant` suffix is accepted). Other shapes are refused with 400. Null restores the workspace default. Takes effect on the next provision: until then `GET` shows this configured model while chat chunks show the model the running intern reports., name: str # New intern name, unique per creator within the workspace.}\n@returns(200) {attached_vault_id: str?, created_at: str, description: str?, hostname: str?, id: str, instructions: str?, last_failure_message: str?, model: str?, name: str, progress: map?, status: str, updated_at: str, vault_id: str?, workspace_id: str} # Updated intern.\n@errors {400: The request body is invalid., 401: Missing, unknown or provisioning API key., 403: The key owner no longer has access, or the request used a regional hostname., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 413: The request body is larger than 1048576 bytes., 500: The request could not be completed.}\n@example_request {\"description\":\"Researches customer questions\",\"model\":\"openai/gpt-5.4\"}\n\n@endpoint POST /interns/{internId}/chat/completions\n@desc Stream a chat completion with an intern\n@required {internId: str # The intern to talk to., messages: [any] # The conversation. Only the last message is read. A last `user` message starts a run. A last `tool` message answers the interaction named by its `tool_call_id` and requires `session_id`., stream: bool # Must be `true`. This endpoint only streams. `false` or an omitted `stream` is refused with `400` and reason `bad_request`.}\n@optional {approval_mode: str(manual/self-drive) # How the run started by this prompt handles tool approvals. `self-drive` (the default when omitted) consents on your behalf and runs the shell unsandboxed. `manual` asks you before an approval-bearing tool runs, as an `openrouter.provide_input` permission request, and keeps the shell sandboxed until an escalation is allowed. The mode applies to the run this prompt starts and is not remembered by the session. Repeat it on each new prompt that should use it. A `tool` reply continues the run under the mode it started with., model: str # Accepted for OpenAI compatibility and never used. The intern runs the model configured on it (`PATCH` the intern to change it). Streamed chunks report the runtime's identifier for that model as the intern reports it, or `openrouter/intern` on chunks whose event carries no model (before the intern reports one, and on the chunks the API emits itself: the timeout, run-ended and severed-stream error chunks, the stop chunk of a replay that ends without a terminal daemon event, and the final usage chunk after any of them). A usage chunk that follows a daemon completion event carries the model the intern reported., session_id: str # The daemon session to continue, as returned in `session_id` on the final chunk of an earlier response. Omit it to start a new session. An id the intern has not seen before is not an error: it starts a new session under that id, so a mistyped id forks the conversation. Sessions are scoped to the intern's own daemon. Required when the last message has role `tool`.}\n@returns(200) The streamed completion. Chunks carry text, then a finish chunk: `finish_reason: \"stop\"` when the turn is complete, `finish_reason: \"tool_calls\"` when the intern is waiting for an answer, or `finish_reason: \"error\"` for a failure after this status. A final chunk with empty `choices` follows in every case, carrying `session_id` and `usage` (`null` unless the intern reported usage, and always `null` after `tool_calls`), and the stream ends with `data: [DONE]`.\n@errors {400: The body is not a valid request (`bad_request`), or the intern did not accept the answer for the pending question, such as a permission option it did not offer., 401: No valid API key., 403: The key belongs to a member who has left the organization and holds no grant., 404: The caller is outside the interns programme, the intern does not exist for this key (`not_found`), or no pending question has this `tool_call_id` in this session (`interaction_unknown`)., 409: The intern is not running (`intern_not_ready`), another turn is running in this session (`busy`), the question is no longer waiting (`interaction_not_pending`), or another request is already attached to the run (`attachment_failed`). `intern_not_ready` and `busy` report `retryable: true`, and a `busy` refusal carries `Retry-After`., 410: The run produced more output than the intern retains, so the paused stream cannot be resumed (`attachment_failed`)., 413: The body exceeds 1 MiB (`payload_too_large`)., 429: Too many turns for the user or organization this key acts as (`rate_limited`). It reports `retryable: true` and carries `Retry-After`., 502: The intern could not be reached or rejected the request (`intern_unreachable`, `intern_rejected`), the intern refused the turn before any output (`turn_failed`), or its stream ended before the turn started (`stream_severed`). Every one of those but `intern_rejected` is transient and reports `retryable: true`., 503: The intern cannot hold another run open across a question right now (`busy`). It reports `retryable: true` and carries `Retry-After`., 504: The intern did not answer within the request budget (`timeout`).}\n@example_request {\"approval_mode\":\"manual\",\"messages\":[{\"content\":\"Summarize the open pull requests.\",\"role\":\"user\"}],\"stream\":true}\n\n@endpoint POST /interns/{internId}/provision\n@desc Provision an intern\n@required {internId: str # ID of an intern visible to the authenticated API key.}\n@returns(202) {provisioning: bool} # The operation was accepted.\n@errors {401: Missing, unknown or provisioning API key., 403: The key owner no longer has access, or the request used a regional hostname., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 409: The intern is not in a state that allows this operation., 500: The request could not be completed., 502: The intern service could not accept the operation.}\n\n@endpoint POST /interns/{internId}/suspend\n@desc Suspend an intern\n@required {internId: str # ID of an intern visible to the authenticated API key.}\n@returns(200) {suspended: bool} # Intern suspended.\n@errors {401: Missing, unknown or provisioning API key., 403: The key owner no longer has access, or the request used a regional hostname., 404: The caller is outside the Intern API programme, the intern is hidden, or lifecycle writes are disabled., 408: The request exceeded its route deadline., 409: The intern is not in a state that allows this operation., 500: The request could not be completed., 502: The intern service could not accept the operation.}\n\n@endgroup\n\n@group key\n@endpoint GET /key\n@desc Get current API key\n@returns(200) {data: map{allowed_data_regions: [str], byok_usage: num(double), byok_usage_daily: num(double), byok_usage_monthly: num(double), byok_usage_weekly: num(double), creator_user_id: str?, expires_at: str(date-time)?, free_model_daily_requests: map{limit: int, remaining: int, used: int}, include_byok_in_limit: bool, is_free_tier: bool, is_management_key: bool, is_provisioning_key: bool, label: str, limit: num(double)?, limit_remaining: num(double)?, limit_reset: str?, organization_id: str?, rate_limit: map{interval: str, note: str, requests: int}, usage: num(double), usage_daily: num(double), usage_monthly: num(double), usage_weekly: num(double), workspace_id: str?}} # API key details\n@errors {401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group keys\n@endpoint GET /keys\n@desc List API keys\n@optional {include_disabled: bool # Whether to include disabled API keys in the response, offset: int # Number of API keys to skip for pagination, workspace_id: str(uuid) # Filter API keys by workspace ID. By default, keys in the default workspace are returned.}\n@returns(200) {data: [map]} # List of API keys\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /keys\n@desc Create a new API key\n@required {name: str # Name for the new API key}\n@optional {creator_user_id: str # Optional user ID of the key creator. Only meaningful for organization-owned keys where a specific member is creating the key., expires_at: str(date-time) # Optional ISO 8601 UTC expiration timestamp. Must include seconds (YYYY-MM-DDTHH:MM:SSZ; fractional seconds allowed); minute-precision timestamps are rejected., external: map{api_key: str, user!: str} # Optional partner-defined identity associated with the created API key., include_byok_in_limit: bool # Whether to include BYOK usage in the limit, limit: num(double) # Optional spending limit for the API key in USD, limit_reset: str(daily/weekly/monthly) # Type of limit reset for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday., workspace_id: str(uuid) # The workspace to create the API key in. Defaults to the default workspace if not provided.}\n@returns(201) {data: map{byok_usage: num(double), byok_usage_daily: num(double), byok_usage_monthly: num(double), byok_usage_weekly: num(double), created_at: str, creator_user_id: str?, disabled: bool, expires_at: str(date-time)?, external_user: str?, hash: str, include_byok_in_limit: bool, label: str, limit: num(double)?, limit_remaining: num(double)?, limit_reset: str?, name: str, updated_at: str?, usage: num(double), usage_daily: num(double), usage_monthly: num(double), usage_weekly: num(double), workspace_id: str}, key: str} # API key created successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n@example_request {\"expires_at\":\"2027-12-31T23:59:59Z\",\"include_byok_in_limit\":true,\"limit\":50,\"limit_reset\":\"monthly\",\"name\":\"My New API Key\"}\n\n@endpoint DELETE /keys/{hash}\n@desc Delete an API key\n@required {hash: str # The hash identifier of the API key to delete}\n@returns(200) {deleted: bool} # API key deleted successfully\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /keys/{hash}\n@desc Get a single API key\n@required {hash: str # The hash identifier of the API key to retrieve}\n@returns(200) {data: map{byok_usage: num(double), byok_usage_daily: num(double), byok_usage_monthly: num(double), byok_usage_weekly: num(double), created_at: str, creator_user_id: str?, disabled: bool, expires_at: str(date-time)?, external_user: str?, hash: str, include_byok_in_limit: bool, label: str, limit: num(double)?, limit_remaining: num(double)?, limit_reset: str?, name: str, updated_at: str?, usage: num(double), usage_daily: num(double), usage_monthly: num(double), usage_weekly: num(double), workspace_id: str}} # API key details\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n\n@endpoint PATCH /keys/{hash}\n@desc Update an API key\n@required {hash: str # The hash identifier of the API key to update}\n@optional {disabled: bool # Whether to disable the API key, include_byok_in_limit: bool # Whether to include BYOK usage in the limit, limit: num(double) # New spending limit for the API key in USD, limit_reset: str(daily/weekly/monthly) # New limit reset type for the API key (daily, weekly, monthly, or null for no reset). Resets happen automatically at midnight UTC, and weeks are Monday through Sunday., name: str # New name for the API key}\n@returns(200) {data: map{byok_usage: num(double), byok_usage_daily: num(double), byok_usage_monthly: num(double), byok_usage_weekly: num(double), created_at: str, creator_user_id: str?, disabled: bool, expires_at: str(date-time)?, external_user: str?, hash: str, include_byok_in_limit: bool, label: str, limit: num(double)?, limit_remaining: num(double)?, limit_reset: str?, name: str, updated_at: str?, usage: num(double), usage_daily: num(double), usage_monthly: num(double), usage_weekly: num(double), workspace_id: str}} # API key updated successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n@example_request {\"disabled\":false,\"include_byok_in_limit\":true,\"limit\":75,\"limit_reset\":\"daily\",\"name\":\"Updated API Key Name\"}\n\n@endgroup\n\n@group messages\n@endpoint POST /messages\n@desc Create a message\n@required {messages: [map{clear_at: str, content!: any, output_config: map, role!: str}], model: str}\n@optional {X-OpenRouter-Metadata: str # Opt-in to surface routing metadata on the response under `openrouter_metadata`. Defaults to `disabled`. The legacy header `X-OpenRouter-Experimental-Metadata` is also accepted for backward compatibility., cache_control: map{ttl: str, type!: str} # Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format., context_management: map{edits: [any]}, fallbacks: [map{model!: str}] # Fallback models to try if the primary model fails or refuses, in order. Handled by OpenRouter multi-model routing rather than Anthropic server-side fallbacks; cannot be combined with `models`. Each entry accepts only `model`. Maximum of 3 entries., max_tokens: int, metadata: map{user_id: str}, models: [str], output_config: map{effort: str, format: map, task_budget: map} # Configuration for controlling output behavior. Supports the effort parameter and structured output format., plugins: [any] # Plugins you want to enable for this request, including their settings., provider: map{allow_fallbacks: bool, data_collection: str, enforce_distillable_text: bool, ignore: [any], max_price: map, only: [any], order: [any], preferred_max_latency: any, preferred_min_throughput: any, quantizations: [str], require_parameters: bool, sort: any, zdr: bool} # When multiple model providers are available, optionally indicate your routing preference., route: str(fallback/sort) # **DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\")., service_tier: str, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., speed: any, stop_sequences: [str], stop_server_tools_when: [any] # Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call., stream: bool, system: any, temperature: num(double), thinking: any, tool_choice: any, tools: [any], top_k: int, top_p: num(double), trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters.}\n@returns(200) Successful response\n@errors {400: Invalid request error, 401: Authentication error, 403: Forbidden error, 404: Not found error, 429: Rate limit error, 500: API error, 503: Overloaded error, 529: Overloaded error}\n@example_request {\"max_tokens\":1024,\"messages\":[{\"content\":\"Hello, how are you?\",\"role\":\"user\"}],\"model\":\"anthropic/claude-sonnet-4\"}\n\n@endgroup\n\n@group model\n@endpoint GET /model/{author}/{slug}\n@desc Get a model by its slug\n@required {author: str # The author/organization of the model, slug: str # The model slug, optionally including a variant suffix (e.g. gpt-4 or gpt-4:free)}\n@returns(200) {data: map{alias_target: map{name: str, slug: str}, architecture: map{input_modalities: [str], instruct_type: str?, modality: str?, output_modalities: [str], tokenizer: str}, benchmarks: map{artificial_analysis: map{agentic_index: num(double)?, coding_index: num(double)?, intelligence_index: num(double)?}, design_arena: [map]}, canonical_slug: str, context_length: int?, created: int, default_parameters: map?, description: str, expiration_date: str?, hugging_face_id: str?, id: str, knowledge_cutoff: str?, links: map{details: str}, name: str, per_request_limits: map?, pricing: map{audio: str, audio_output: str, completion: str, discount: num(double), image: str, image_output: str, image_token: str, input_audio_cache: str, input_cache_read: str, input_cache_write: str, input_cache_write_1h: str, internal_reasoning: str, overrides: [map], prompt: str, request: str, web_search: str}, reasoning: map{default_effort: any, default_enabled: bool, mandatory: bool, supported_efforts: [str]?, supports_max_tokens: bool}, supported_parameters: [str], supported_voices: [str]?, top_provider: map{context_length: int?, is_moderated: bool, max_completion_tokens: int?}}} # Returns the model details\n@errors {403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group models\n@endpoint GET /models\n@desc List all models and their properties\n@optional {offset: int=0 # Number of records to skip for pagination. When both offset and limit are omitted, the full list is returned, limit: int=500 # Maximum number of records to return (max 1000). When both offset and limit are omitted, the full list is returned, category: str(programming/roleplay/marketing/marketing/seo/technology/science/translation/legal/finance/health/trivia/academia) # Filter models by use case category, supported_parameters: str # Filter models by supported parameter (comma-separated), output_modalities: str # Filter models by output modality. Accepts a comma-separated list of modalities (text, image, embeddings, audio, video, rerank, decisions, speech, transcription) or \"all\" to include all models. Defaults to \"text\"., sort: str(most-popular/newest/top-weekly/pricing-low-to-high/pricing-high-to-low/context-high-to-low/throughput-high-to-low/latency-low-to-high/intelligence-high-to-low/coding-high-to-low/agentic-high-to-low/design-arena-elo-high-to-low) # Sort the returned models server-side. Prefer this over fetching the full list and sorting client-side. Options: pricing-low-to-high, pricing-high-to-low (average prompt/completion price), context-high-to-low (context length), throughput-high-to-low, latency-low-to-high (recent median performance), most-popular, top-weekly (tokens processed in the last week), newest (creation date), intelligence-high-to-low, coding-high-to-low, agentic-high-to-low (Artificial Analysis indices), design-arena-elo-high-to-low (best Design Arena ELO across arenas). Models without a score for the chosen benchmark are placed last. When omitted, the existing default ordering is preserved., q: str # Free-text search by model name or slug., input_modalities: str # Filter models by input modality. Comma-separated list of: text, image, audio, file., context: int # Minimum context length (tokens). Models with smaller context are excluded., min_price: num # Minimum prompt price in $/M tokens., max_price: num # Maximum prompt price in $/M tokens., arch: str # Filter models by architecture/model family (e.g. GPT, Claude, Gemini, Llama)., model_authors: str # Filter models by the organization that created the model. Comma-separated list of author slugs., providers: str # Filter models by hosting provider. Comma-separated list of provider names., distillable: str(true/false) # Filter by distillation capability. \"true\" returns only distillable models, \"false\" excludes them., zdr: str # When set to \"true\", return only models with zero data retention endpoints., region: str(eu/us) # Filter to models with endpoints in the given data region (\"eu\" or \"us\")., min_output_price: num # Minimum completion (output) price in $/M tokens., max_output_price: num # Maximum completion (output) price in $/M tokens., min_age_days: int # Minimum model age in days since its creation date., max_age_days: int # Maximum model age in days since its creation date., min_intelligence_index: num # Minimum Artificial Analysis intelligence index., max_intelligence_index: num # Maximum Artificial Analysis intelligence index., min_coding_index: num # Minimum Artificial Analysis coding index., max_coding_index: num # Maximum Artificial Analysis coding index., min_agentic_index: num # Minimum Artificial Analysis agentic index., max_agentic_index: num # Maximum Artificial Analysis agentic index., min_tool_success_rate: num # Minimum tool-calling success rate, as a fraction in [0, 1] (e.g. 0.9 = 90% of requests finishing with a tool_calls finish reason)., max_tool_success_rate: num # Maximum tool-calling success rate, as a fraction in [0, 1].}\n@returns(200) {data: [map], links: map{next: str?}, total_count: int} # Returns a list of models or RSS feed\n@errors {400: Bad Request - Invalid request parameters or malformed input, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /models/{author}/{slug}/endpoints\n@desc List all endpoints for a model\n@required {author: str # The author/organization of the model, slug: str # The model slug}\n@returns(200) {data: map{architecture: any, created: int, description: str, endpoints: [map], id: str, name: str}} # Returns a list of endpoints\n@errors {403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /models/count\n@desc Get total count of available models\n@optional {output_modalities: str # Filter models by output modality. Accepts a comma-separated list of modalities (text, image, embeddings, audio, video, rerank, decisions, speech, transcription) or \"all\" to include all models. Defaults to \"text\".}\n@returns(200) {data: map{count: int}} # Returns the total count of available models\n@errors {400: Bad Request - Invalid request parameters or malformed input, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /models/user\n@desc List models filtered by user provider preferences, privacy settings, and guardrails\n@optional {offset: int=0 # Number of records to skip for pagination. When both offset and limit are omitted, the full list is returned, limit: int=500 # Maximum number of records to return (max 1000). When both offset and limit are omitted, the full list is returned, output_modalities: str # Filter models by output modality. Accepts a comma-separated list of modalities (text, image, embeddings, audio, video, rerank, decisions, speech, transcription) or \"all\" to include all models. Defaults to \"text\".}\n@returns(200) {data: [map], links: map{next: str?}, total_count: int} # Returns a list of models filtered by user provider preferences\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group oauth\n@endpoint GET /oauth/jwks\n@desc OpenRouter access token signing keys\n@returns(200) {keys: [map]} # JWK Set\n@errors {500: Signing keys are not configured}\n\n@endpoint POST /oauth/token\n@desc Exchange a workload identity token\n@returns(200) {access_token: str, expires_in: int, issued_token_type: str, scope: str, token_type: str} # Access token issued\n@errors {400: Malformed request, unsupported grant, or the subject token was not accepted, 429: Rate limited, 500: The token could not be issued, 503: The issuer’s discovery document or JWKS could not be fetched}\n\n@endgroup\n\n@group observability\n@endpoint GET /observability/destinations\n@desc List observability destinations\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100), workspace_id: str(uuid) # Optional workspace ID to filter by. Defaults to the authenticated entity's default workspace.}\n@returns(200) {data: [any], total_count: int} # List of observability destinations\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /observability/destinations\n@desc Create an observability destination\n@required {config: map # Provider-specific configuration. The shape depends on `type` and is validated server-side., name: str # Human-readable name for the destination., type: str(arize/braintrust/clickhouse/datadog/grafana/langfuse/langsmith/newrelic/opik/otel-collector/posthog/ramp/s3/sentry/snowflake/weave/webhook) # The destination type. Only stable destination types are accepted.}\n@optional {api_key_hashes: [str] # Optional allowlist of OpenRouter API key hashes whose traffic is forwarded. `null` or omitted means all keys. Must contain at least one hash if provided., broadcast_generation_cost: bool=false # When true, include cost and billing generation metadata., broadcast_generation_identity: bool=false # When true, include identity generation metadata., broadcast_generation_request_context: bool=false # When true, include request-context generation metadata., enabled: bool=true # Whether this destination should be enabled immediately., filter_rules: map{enabled: bool, groups!: [map]} # Optional structured filter rules controlling which events are forwarded., privacy_mode: bool=false # When true, request/response bodies are not forwarded — only metadata., regions: [str]=global # Data regions this destination applies to. `eu` is accepted as an alias for `europe` and normalizes to `europe`. Omitting this field defaults to ['global']; the array must be non-empty., sampling_rate: num(double) # Sampling rate between 0.0001 and 1 (1 = 100%)., workspace_id: str(uuid) # Optional workspace ID. Defaults to the authenticated entity's default workspace.}\n@returns(201) {data: any} # Destination created successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n@example_request {\"config\":{\"baseUrl\":\"https://us.cloud.langfuse.com\",\"publicKey\":\"pk-l...EfGh\",\"secretKey\":\"sk-l...AbCd\"},\"name\":\"Production Langfuse\",\"type\":\"langfuse\"}\n\n@endpoint DELETE /observability/destinations/{id}\n@desc Delete an observability destination\n@required {id: str(uuid) # The destination ID (UUID).}\n@returns(200) {deleted: bool} # Destination deleted successfully\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /observability/destinations/{id}\n@desc Get an observability destination\n@required {id: str(uuid) # The destination ID (UUID).}\n@returns(200) {data: any} # The observability destination\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint PATCH /observability/destinations/{id}\n@desc Update an observability destination\n@required {id: str(uuid) # The destination ID (UUID).}\n@optional {api_key_hashes: [str] # Optional allowlist of OpenRouter API key hashes. `null` clears the filter (all keys). Omitting leaves the current value. Must contain at least one hash if provided., broadcast_generation_cost: bool # Whether to include cost and billing generation metadata., broadcast_generation_identity: bool # Whether to include identity generation metadata., broadcast_generation_request_context: bool # Whether to include request-context generation metadata., config: map # Provider-specific configuration fields to update. Masked values are ignored; unset fields keep their current value., enabled: bool # Whether the destination is enabled., filter_rules: any, name: str # Human-readable name for the destination., privacy_mode: bool # When true, request/response bodies are not forwarded — only metadata., regions: [str] # Data regions this destination applies to. `eu` is accepted as an alias for `europe` and normalizes to `europe`. Omitting this field keeps the current value; it cannot be cleared., sampling_rate: num(double) # Sampling rate between 0.0001 and 1 (1 = 100%).}\n@returns(200) {data: any} # Destination updated successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n@example_request {\"enabled\":false,\"name\":\"Updated Langfuse\"}\n\n@endgroup\n\n@group organization\n@endpoint GET /organization/members\n@desc List organization members\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of organization members\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group presets\n@endpoint GET /presets\n@desc List presets\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # Paginated list of presets.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /presets/{slug}\n@desc Get a preset\n@required {slug: str # URL-safe slug identifying the preset.}\n@returns(200) {data: any} # Preset with its designated version.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /presets/{slug}/chat/completions\n@desc Create a preset from a chat-completions request body\n@required {slug: str # URL-safe slug identifying the preset. Created if it does not exist., messages: [any] # List of messages for the conversation}\n@optional {cache_control: map{ttl: str, type!: str} # Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format., debug: map{echo_upstream_body: bool} # Debug options for inspecting request transformations (streaming only), frequency_penalty: num(double) # Frequency penalty (-2.0 to 2.0), image_config: map # Provider-specific image configuration options. Keys and values vary by model/provider. See https://openrouter.ai/docs/guides/overview/multimodal/image-generation for more details., logit_bias: map # Token logit bias adjustments, logprobs: bool # Return log probabilities, max_completion_tokens: int # Maximum tokens in completion, max_tokens: int # Maximum tokens (deprecated, use max_completion_tokens). Note: some providers enforce a minimum of 16., metadata: map # Key-value pairs for additional object information (max 16 pairs, 64 char keys, 512 char values), min_p: num(double) # Minimum probability threshold relative to the most likely token. Tokens with probability below min_p * (probability of top token) are filtered out. Not all providers support this parameter., modalities: [str] # Output modalities for the response. Supported values are \"text\", \"image\", and \"audio\"., model: str # Model to use for completion, models: [any] # Models to use for completion, parallel_tool_calls: bool # Whether to enable parallel function calling during tool use. When true, the model may generate multiple tool calls in a single response., plugins: [any] # Plugins you want to enable for this request, including their settings., prediction: map{content!: any, type!: str} # Static predicted output content. Supported models can use this to reduce latency when much of the response is known in advance., presence_penalty: num(double) # Presence penalty (-2.0 to 2.0), prompt_cache_key: str, prompt_cache_options: map{mode!: str, ttl: str} # Request-level prompt-cache controls. `mode: \"explicit\"` disables OpenAI-managed breakpoints so only blocks marked with `prompt_cache_breakpoint` are cached. Only supported by OpenAI GPT-5.6 and newer., provider: map{allow_fallbacks: bool, data_collection: str, enforce_distillable_text: bool, ignore: [any], max_price: map, only: [any], order: [any], preferred_max_latency: any, preferred_min_throughput: any, quantizations: [str], require_parameters: bool, sort: any, zdr: bool} # When multiple model providers are available, optionally indicate your routing preference., reasoning: map{effort: str, summary: str} # Configuration options for reasoning models, reasoning_effort: str(max/xhigh/high/medium/low/minimal/none) # Shorthand for setting reasoning effort. Equivalent to setting reasoning.effort. Cannot be used simultaneously with reasoning.effort if they differ., repetition_penalty: num(double) # Penalizes tokens based on how much they have already appeared in the text. A value of 1.0 means no penalty. Values above 1.0 penalize repeated tokens more strongly. Not all providers support this parameter., response_format: any # Response format configuration, route: str(fallback/sort) # **DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\")., seed: int # Random seed for deterministic outputs, service_tier: str(auto/default/fast/flex/priority/scale) # The service tier to use for processing this request. `fast` is accepted as an alias for `priority`., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., stop: any # Stop sequences (up to 4), stop_server_tools_when: [any] # Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call., stream: bool=false # Enable streaming response, stream_options: map{include_usage: bool} # Streaming configuration options, temperature: num(double) # Sampling temperature (0-2), tool_choice: any # Tool choice configuration, tools: [any] # Available tools for function calling, top_a: num(double) # Consider only tokens with \"sufficiently high\" probabilities based on the probability of the most likely token. Not all providers support this parameter., top_k: int # Limits the model to choose from the top K most likely tokens at each step. A value of 1 means the model will always pick the most likely next token. Not all providers support this parameter., top_logprobs: int # Number of top log probabilities to return (0-20), top_p: num(double) # Nucleus sampling parameter (0-1), trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # Per-end-user identifier for abuse isolation. Use a stable ID, hash, or pseudonym. When a provider requires a user identity, OpenRouter folds it into the hashed identity sent upstream and never forwards it raw. If omitted, requests use an account-level identity, so provider policy blocks can affect the whole account.}\n@returns(200) {data: any} # Preset created or updated successfully.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n@example_request {\"messages\":[{\"content\":\"You are a helpful assistant.\",\"role\":\"system\"},{\"content\":\"Hello!\",\"role\":\"user\"}],\"model\":\"openai/gpt-5.4\",\"temperature\":0.7}\n\n@endpoint POST /presets/{slug}/messages\n@desc Create a preset from a messages request body\n@required {slug: str # URL-safe slug identifying the preset. Created if it does not exist., messages: [map{clear_at: str, content!: any, output_config: map, role!: str}], model: str}\n@optional {cache_control: map{ttl: str, type!: str} # Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format., context_management: map{edits: [any]}, fallbacks: [map{model!: str}] # Fallback models to try if the primary model fails or refuses, in order. Handled by OpenRouter multi-model routing rather than Anthropic server-side fallbacks; cannot be combined with `models`. Each entry accepts only `model`. Maximum of 3 entries., max_tokens: int, metadata: map{user_id: str}, models: [str], output_config: map{effort: str, format: map, task_budget: map} # Configuration for controlling output behavior. Supports the effort parameter and structured output format., plugins: [any] # Plugins you want to enable for this request, including their settings., provider: map{allow_fallbacks: bool, data_collection: str, enforce_distillable_text: bool, ignore: [any], max_price: map, only: [any], order: [any], preferred_max_latency: any, preferred_min_throughput: any, quantizations: [str], require_parameters: bool, sort: any, zdr: bool} # When multiple model providers are available, optionally indicate your routing preference., route: str(fallback/sort) # **DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\")., service_tier: str, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., speed: any, stop_sequences: [str], stop_server_tools_when: [any] # Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call., stream: bool, system: any, temperature: num(double), thinking: any, tool_choice: any, tools: [any], top_k: int, top_p: num(double), trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters.}\n@returns(200) {data: any} # Preset created or updated successfully.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n@example_request {\"max_tokens\":1024,\"messages\":[{\"content\":\"Hello!\",\"role\":\"user\"}],\"model\":\"anthropic/claude-4.6-sonnet\",\"system\":\"You are a helpful assistant.\"}\n\n@endpoint POST /presets/{slug}/responses\n@desc Create a preset from a responses request body\n@required {slug: str # URL-safe slug identifying the preset. Created if it does not exist.}\n@optional {background: bool, cache_control: map{ttl: str, type!: str} # Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format., debug: map{echo_upstream_body: bool} # Debug options for inspecting request transformations (streaming only), frequency_penalty: num(double), image_config: map # Provider-specific image configuration options. Keys and values vary by model/provider. See https://openrouter.ai/docs/guides/overview/multimodal/image-generation for more details., include: [str], input: any # Input for a response request - can be a string or array of items, instructions: str, max_output_tokens: int, max_tool_calls: int # Maximum number of server-tool (e.g. `openrouter:web_search`) agent steps the model may take during a request. Defaults to 30, which is also the maximum. Ignored when `stop_server_tools_when` is set., metadata: map # Metadata key-value pairs for the request. Keys must be ≤64 characters and cannot contain brackets. Values must be ≤512 characters. Maximum 16 pairs allowed., modalities: [str] # Output modalities for the response. Supported values are \"text\" and \"image\"., model: str, models: [str], parallel_tool_calls: bool, plugins: [any] # Plugins you want to enable for this request, including their settings., presence_penalty: num(double), previous_response_id: any # Not supported. The Responses API is stateless: no responses are stored, so a previous response cannot be referenced. Requests with a non-null value are rejected with a 400 error. Send the full conversation history in `input` instead., prompt: map{id!: str, variables: map}, prompt_cache_key: str, prompt_cache_options: map{mode!: str, ttl: str} # Request-level prompt-cache controls. `mode: \"explicit\"` disables OpenAI-managed breakpoints so only blocks marked with `prompt_cache_breakpoint` are cached. Only supported by OpenAI GPT-5.6 and newer., provider: map{allow_fallbacks: bool, data_collection: str, enforce_distillable_text: bool, ignore: [any], max_price: map, only: [any], order: [any], preferred_max_latency: any, preferred_min_throughput: any, quantizations: [str], require_parameters: bool, sort: any, zdr: bool} # When multiple model providers are available, optionally indicate your routing preference., reasoning: any # Configuration for reasoning mode in the response, route: str(fallback/sort) # **DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\")., safety_identifier: str # Recommended per-end-user identifier for abuse isolation. Use a stable ID, hash, or pseudonym. When a provider requires a user identity, OpenRouter folds it into the hashed identity sent upstream and never forwards it raw. If omitted, requests use an account-level identity, so provider policy blocks can affect the whole account., service_tier: str(auto/default/fast/flex/priority/scale)=auto # The service tier to use for processing this request. `fast` is accepted as an alias for `priority`., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., stop_server_tools_when: [any] # Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call., store: bool=false, stream: bool=false, temperature: num(double), text: any # Text output configuration including format and verbosity, tool_choice: any, tools: [any], top_k: int, top_logprobs: int, top_p: num(double), trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., truncation: str(auto/disabled), user: str # A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters.}\n@returns(200) {data: any} # Preset created or updated successfully.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n@example_request {\"input\":\"Hello!\",\"instructions\":\"You are a helpful assistant.\",\"model\":\"openai/gpt-5.4\"}\n\n@endpoint GET /presets/{slug}/versions\n@desc List versions of a preset\n@required {slug: str # URL-safe slug identifying the preset.}\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # Paginated list of preset versions.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /presets/{slug}/versions/{version}\n@desc Get a specific version of a preset\n@required {slug: str # URL-safe slug identifying the preset., version: str # Version number of the preset.}\n@returns(200) {data: map?} # The requested preset version.\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group providers\n@endpoint GET /providers\n@desc List all providers\n@returns(200) {data: [map]} # Returns a list of providers\n@errors {500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group rerank\n@endpoint POST /rerank\n@desc Submit a rerank request\n@required {documents: [any] # The list of documents to rerank. Documents may be plain strings, or structured objects with `text` and/or `image` for multimodal models., model: str # The rerank model to use, query: str # The search query to rerank documents against}\n@optional {provider: any, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., top_n: int # Number of most relevant documents to return, trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str # A unique identifier representing your end-user. Forwarded to Broadcast and private logging as the end-user id; never sent to the provider.}\n@returns(200) {id: str, model: str, provider: str, results: [map], usage: map{cost: num(double), search_units: int, total_tokens: int}} # Rerank response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n\n@endgroup\n\n@group responses\n@endpoint POST /responses\n@desc Create a response\n@optional {X-OpenRouter-Metadata: str # Opt-in to surface routing metadata on the response under `openrouter_metadata`. Defaults to `disabled`. The legacy header `X-OpenRouter-Experimental-Metadata` is also accepted for backward compatibility., background: bool, cache_control: map{ttl: str, type!: str} # Enable automatic prompt caching. When set at the top level, the system automatically applies cache breakpoints to the last cacheable block in the request. When set on an individual content block, it marks an explicit cache breakpoint; block-level markers also work on OpenAI models that support explicit prompt caching — OpenRouter converts them to the provider's native format., debug: map{echo_upstream_body: bool} # Debug options for inspecting request transformations (streaming only), frequency_penalty: num(double), image_config: map # Provider-specific image configuration options. Keys and values vary by model/provider. See https://openrouter.ai/docs/guides/overview/multimodal/image-generation for more details., include: [str], input: any # Input for a response request - can be a string or array of items, instructions: str, max_output_tokens: int, max_tool_calls: int # Maximum number of server-tool (e.g. `openrouter:web_search`) agent steps the model may take during a request. Defaults to 30, which is also the maximum. Ignored when `stop_server_tools_when` is set., metadata: map # Metadata key-value pairs for the request. Keys must be ≤64 characters and cannot contain brackets. Values must be ≤512 characters. Maximum 16 pairs allowed., modalities: [str] # Output modalities for the response. Supported values are \"text\" and \"image\"., model: str, models: [str], parallel_tool_calls: bool, plugins: [any] # Plugins you want to enable for this request, including their settings., presence_penalty: num(double), previous_response_id: any # Not supported. The Responses API is stateless: no responses are stored, so a previous response cannot be referenced. Requests with a non-null value are rejected with a 400 error. Send the full conversation history in `input` instead., prompt: map{id!: str, variables: map}, prompt_cache_key: str, prompt_cache_options: map{mode!: str, ttl: str} # Request-level prompt-cache controls. `mode: \"explicit\"` disables OpenAI-managed breakpoints so only blocks marked with `prompt_cache_breakpoint` are cached. Only supported by OpenAI GPT-5.6 and newer., provider: map{allow_fallbacks: bool, data_collection: str, enforce_distillable_text: bool, ignore: [any], max_price: map, only: [any], order: [any], preferred_max_latency: any, preferred_min_throughput: any, quantizations: [str], require_parameters: bool, sort: any, zdr: bool} # When multiple model providers are available, optionally indicate your routing preference., reasoning: any # Configuration for reasoning mode in the response, route: str(fallback/sort) # **DEPRECATED** Use providers.sort.partition instead. Backwards-compatible alias for providers.sort.partition. Accepts legacy values: \"fallback\" (maps to \"model\"), \"sort\" (maps to \"none\")., safety_identifier: str # Recommended per-end-user identifier for abuse isolation. Use a stable ID, hash, or pseudonym. When a provider requires a user identity, OpenRouter folds it into the hashed identity sent upstream and never forwards it raw. If omitted, requests use an account-level identity, so provider policy blocks can affect the whole account., service_tier: str(auto/default/fast/flex/priority/scale)=auto # The service tier to use for processing this request. `fast` is accepted as an alias for `priority`., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). When provided, OpenRouter uses it as the sticky routing key, routing all requests in the session to the same provider to maximize prompt cache hits. Also used for observability grouping. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., stop_server_tools_when: [any] # Stop conditions for the server-tool agent loop. Any condition firing halts the loop (OR logic). When set, this overrides `max_tool_calls`. When a condition fires while the model is still emitting tool calls, the pending tool calls are executed and one final turn is made with tool calls disabled so the response ends with a natural-language answer instead of an unfinished tool call., store: bool=false, stream: bool=false, temperature: num(double), text: any # Text output configuration including format and verbosity, tool_choice: any, tools: [any], top_k: int, top_logprobs: int, top_p: num(double), trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., truncation: str(auto/disabled), user: str # A unique identifier representing your end-user, which helps distinguish between different users of your app. This allows your app to identify specific users in case of abuse reports, preventing your entire app from being affected by the actions of individual users. Maximum of 256 characters.}\n@returns(200) Successful response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, or a guardrail blocked the request. When guardrails block and the `X-OpenRouter-Metadata: enabled` header is present, the response includes `openrouter_metadata` with full routing context and a `pipeline` array containing guardrail stage details., 404: Not Found - Resource does not exist, 408: Request Timeout - Operation exceeded time limit, 413: Payload Too Large - Request payload exceeds size limits, 422: Unprocessable Entity - Semantic validation failure, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"input\":\"Tell me a joke\",\"model\":\"openai/gpt-4o\"}\n\n@endgroup\n\n@group scim\n@endpoint GET /scim/group-mappings\n@desc List SCIM group mappings\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of SCIM group mappings\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /scim/group-mappings\n@desc Create a SCIM group mapping\n@required {role: str(admin/member), scim_group_id: str(uuid), workspace_id: str(uuid)}\n@returns(201) {data: map{created_at: str, id: str(uuid), organization_id: str, role: str, scim_group_id: str(uuid), updated_at: str, workspace_id: str(uuid)}} # SCIM group mapping created\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 409: Conflict - Resource conflict or concurrent modification, 500: Internal Server Error - Unexpected server error}\n\n@endpoint DELETE /scim/group-mappings/{id}\n@desc Delete a SCIM group mapping\n@required {id: str(uuid), keep_members: any # Required. Whether to keep workspace members after deleting the mapping. `false` **removes** the members this mapping granted access to; `true` deletes the mapping while leaving membership intact as manually-managed. There is deliberately no default — omitting it returns `400` so the destructive path cannot be reached by accident. Mirrors the dashboard, whose `DeleteMappingSchema.keepMembers` is likewise required.}\n@returns(200) {deleted: bool} # SCIM group mapping deleted\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /scim/group-mappings/{id}\n@desc Get a SCIM group mapping\n@required {id: str(uuid)}\n@returns(200) {data: map{created_at: str, id: str(uuid), organization_id: str, role: str, scim_group_id: str(uuid), updated_at: str, workspace_id: str(uuid)}} # SCIM group mapping\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint PATCH /scim/group-mappings/{id}\n@desc Update a SCIM group mapping\n@required {id: str(uuid), role: str(admin/member)}\n@returns(200) {data: map{created_at: str, id: str(uuid), organization_id: str, role: str, scim_group_id: str(uuid), updated_at: str, workspace_id: str(uuid)}} # SCIM group mapping updated\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /scim/groups\n@desc List SCIM groups\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of SCIM groups\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /scim/sync-jobs\n@desc Start a SCIM directory sync\n@returns(202) {data: map{created_at: str, deleted_groups: int?, error_message: str?, finished_at: str?, id: str(uuid), started_at: str?, status: str, synced_groups: int?}} # SCIM directory sync job queued\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /scim/sync-jobs/{id}\n@desc Get SCIM directory sync status\n@required {id: str(uuid)}\n@returns(200) {data: map{created_at: str, deleted_groups: int?, error_message: str?, finished_at: str?, id: str(uuid), started_at: str?, status: str, synced_groups: int?}} # SCIM directory sync job\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group systemone\n@endpoint POST /systemone\n@desc Submit a System One request\n@required {model: str, questions: map, state: any # The content to evaluate: a plain string, or a JSON object or array of related context.}\n@optional {provider: any, session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., user: str}\n@returns(200) {answers: map, id: str, model: str, provider: str, usage: map{cost: num(double), input_tokens: int, output_tokens: int}} # Decisions response\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure, 503: Service Unavailable - Service temporarily unavailable, 524: Infrastructure Timeout - Provider request timed out at edge network, 529: Provider Overloaded - Provider is temporarily overloaded}\n@example_request {\"model\":\"typesafe/jev-1.13\",\"questions\":{\"is_bug\":{\"criteria\":{\"false\":\"The customer is asking a question or requesting a feature.\",\"true\":\"The customer describes broken or unexpected product behavior.\"},\"instructions\":\"Is the customer reporting a software defect?\",\"type\":\"noul\"},\"team\":{\"criteria\":{\"account\":\"Login, permissions, or profile issues.\",\"frontend\":\"Rendering, layout, or browser compatibility issues.\",\"payments\":\"Checkout, billing, or payment processing issues.\"},\"instructions\":\"Which team should own this ticket?\",\"type\":\"choice\"},\"urgency\":{\"criteria\":[\"Can wait for the next release\",\"Should be fixed this week\",\"Blocking revenue right now\"],\"instructions\":\"How urgent is this ticket?\",\"type\":\"score\"}},\"state\":{\"customer_tier\":\"enterprise\",\"ticket\":\"My checkout page shows a blank screen after I click Pay. I have tried two browsers.\"}}\n\n@endgroup\n\n@group vault\n@endpoint GET /vault/interns/{internId}/secrets\n@desc List intern secrets\n@required {internId: str(uuid) # UUID of an intern in the workspace selected by the API key.}\n@optional {limit: int=100 # Page size, 1 to 100. Defaults to 100., offset: int=0 # Number of secrets to skip, 0 to 10000. Defaults to 0.}\n@returns(200) {data: [map], has_more: bool} # One page of secret metadata.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n\n@endpoint DELETE /vault/interns/{internId}/secrets/{name}\n@desc Delete an intern secret\n@required {internId: str(uuid) # UUID of an intern in the workspace selected by the API key., name: str # Secret name. Lowercase letters, digits and single underscores, starting with a letter and not ending with an underscore, 1 to 255 characters.}\n@returns(204) Secret deleted. The response has no body.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n\n@endpoint PUT /vault/interns/{internId}/secrets/{name}\n@desc Store an intern secret\n@required {internId: str(uuid) # UUID of an intern in the workspace selected by the API key., name: str # Secret name. Lowercase letters, digits and single underscores, starting with a letter and not ending with an underscore, 1 to 255 characters., hosts: [str] # Exact DNS hostnames the secret may be sent to, 1 to 100 entries. Each entry is lowercased and a trailing dot is removed, so `API.Example.com.` is stored as `api.example.com`. Schemes, ports, paths, wildcards and empty values are rejected. Duplicates after normalization are collapsed. Matching is exact: a secret bound to `api.example.com` is never released to `example.com` or any other hostname., value: str # Secret value, 1 to 65536 characters. It is encrypted at rest and never returned.}\n@returns(200) {data: map{created_at: str(date-time), fingerprint: str?, hosts: [str]?, name: str}} # Metadata for the stored secret.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 409: Conflict - The intern is being transferred to another workspace and its vault has not moved yet. Retry once the transfer finishes., 413: Payload Too Large - The JSON body exceeds 425000 bytes., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n@example_request {\"hosts\":[\"api.github.com\"],\"value\":\"ghp_exampleTokenValue\"}\n\n@endpoint POST /vault/interns/{internId}/secrets/copy\n@desc Copy workspace secrets to an intern\n@required {internId: str(uuid) # UUID of an intern in the workspace selected by the API key., names: [str] # Names of workspace secrets to copy, 1 to 100 unique entries. Every name must exist in the workspace scope.}\n@returns(200) {data: [map]} # Metadata for the copied secrets.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 409: Conflict - A named workspace secret has no hosts yet, or the intern is being transferred to another workspace. Nothing is copied., 413: Payload Too Large - The JSON body exceeds 425000 bytes., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n@example_request {\"names\":[\"github_token\"]}\n\n@endpoint GET /vault/secrets\n@desc List workspace secrets\n@optional {limit: int=100 # Page size, 1 to 100. Defaults to 100., offset: int=0 # Number of secrets to skip, 0 to 10000. Defaults to 0.}\n@returns(200) {data: [map], has_more: bool} # One page of secret metadata.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n\n@endpoint DELETE /vault/secrets/{name}\n@desc Delete a workspace secret\n@required {name: str # Secret name. Lowercase letters, digits and single underscores, starting with a letter and not ending with an underscore, 1 to 255 characters.}\n@returns(204) Secret deleted. The response has no body.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n\n@endpoint PUT /vault/secrets/{name}\n@desc Store a workspace secret\n@required {name: str # Secret name. Lowercase letters, digits and single underscores, starting with a letter and not ending with an underscore, 1 to 255 characters., hosts: [str] # Exact DNS hostnames the secret may be sent to, 1 to 100 entries. Each entry is lowercased and a trailing dot is removed, so `API.Example.com.` is stored as `api.example.com`. Schemes, ports, paths, wildcards and empty values are rejected. Duplicates after normalization are collapsed. Matching is exact: a secret bound to `api.example.com` is never released to `example.com` or any other hostname., value: str # Secret value, 1 to 65536 characters. It is encrypted at rest and never returned.}\n@returns(200) {data: map{created_at: str(date-time), fingerprint: str?, hosts: [str]?, name: str}} # Metadata for the stored secret.\n@errors {400: Bad Request - The secret name, path, query or JSON body failed validation. The vault returns 400 for a malformed request as well., 401: Unauthorized - Missing or unknown API key. Provisioning keys cannot call vault routes., 403: Forbidden - The key has no usable workspace scope, or the request arrived on a regional hostname., 404: Not Found - The intern is not in the selected workspace, the secret does not exist in the selected scope, or the caller is outside the intern programme., 408: Request Timeout - The route deadline passed before the request completed, or the request body stopped arriving., 413: Payload Too Large - The JSON body exceeds 425000 bytes., 429: Too Many Requests - The vault rate limit was reached., 500: Internal Server Error - Scope lookup failed., 502: Bad Gateway - The vault could not be reached or returned an unexpected response., 503: Service Unavailable - Vault writes are disabled for the caller, or the vault is not configured., 504: Gateway Timeout - The vault did not answer in time.}\n@example_request {\"hosts\":[\"api.github.com\"],\"value\":\"ghp_exampleTokenValue\"}\n\n@endgroup\n\n@group videos\n@endpoint POST /videos\n@desc Submit a video generation request\n@required {model: str}\n@optional {aspect_ratio: str(16:9/9:16/1:1/4:3/3:4/3:2/2:3/21:9/9:21) # Aspect ratio of the generated video, callback_url: str(uri) # URL to receive a webhook notification when the video generation job completes. Overrides the workspace-level default callback URL if set. Must be HTTPS., creativity: int # Creativity level for video upscaling models only. This parameter is not supported by video generation models., duration: int # Duration of the generated video in seconds, frame_images: [any] # Images to use as the first and/or last frame of the generated video. Each image must specify a frame_type of first_frame or last_frame., generate_audio: bool # Whether to generate audio alongside the video. Defaults to the endpoint's generate_audio capability flag, false if not set., input_references: [any] # Reference assets to guide video generation. Accepts image, audio, and video references. Audio and video references are only honored by providers that support them (including BytePlus Seedance generation 2 and newer); other providers use image references and ignore the rest., previous_job_id: str # ID of a completed video job to edit or extend, as returned by the submit response. The new job runs on the same model and endpoint that produced the previous one. Only models that support continuation accept this field., prompt: str # Text prompt describing the video to generate. Optional for models that support generating a video from image input alone; required by all other models., provider: map{options: any} # Provider-specific passthrough configuration, resolution: str(480p/720p/768p/1080p/1K/2K/4K) # Resolution of the generated video, seed: int # If specified, the generation will sample deterministically, such that repeated requests with the same seed and parameters should return the same result. Determinism is not guaranteed for all providers., session_id: str # A unique identifier for grouping related requests (e.g., a conversation or agent workflow). Used for observability grouping in Broadcast and private logging; never sent to the provider. If provided in both the request body and the x-session-id header, the body value takes precedence. Maximum of 256 characters., size: str # Exact pixel dimensions of the generated video in \"WIDTHxHEIGHT\" format (e.g. \"1280x720\"). Interchangeable with resolution + aspect_ratio., trace: map{generation_name: str, parent_span_id: str, span_name: str, trace_id: str, trace_name: str} # Metadata for observability and tracing. Known keys (trace_id, trace_name, span_name, generation_name, parent_span_id) have special handling. Additional keys are passed through as custom metadata to configured broadcast destinations., upscale_factor: num # Upscale factor for video upscaling models only. This parameter is not supported by video generation models., user: str # A unique identifier representing your end-user. Forwarded to Broadcast and private logging as the end-user id; never sent to the provider.}\n@returns(202) {error: str, generation_id: str, id: str, polling_url: str, status: str, unsigned_urls: [str], usage: map{cost: num(double)?, is_byok: bool}} # Video generation request accepted\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 402: Payment Required - Insufficient credits or quota to complete request, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 413: Payload Too Large - Request payload exceeds size limits, 429: Too Many Requests - Rate limit exceeded, 500: Internal Server Error - Unexpected server error}\n@example_request {\"aspect_ratio\":\"16:9\",\"duration\":8,\"model\":\"google/veo-3.1\",\"prompt\":\"A serene mountain landscape at sunset\",\"resolution\":\"720p\"}\n\n@endpoint GET /videos/{jobId}\n@desc Poll video generation status\n@required {jobId: str}\n@returns(200) {error: str, generation_id: str, id: str, polling_url: str, status: str, unsigned_urls: [str], usage: map{cost: num(double)?, is_byok: bool}} # Video generation status\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /videos/{jobId}/content\n@desc Download generated video content\n@required {jobId: str}\n@optional {index: int=0}\n@returns(200) Video content stream. The body is the raw video bytes proxied from the upstream provider, and the Content-Type reflects the provider media type (video/mp4).\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 409: Conflict - Resource conflict or concurrent modification, 410: Gone - Endpoint has been permanently removed or deprecated, 500: Internal Server Error - Unexpected server error, 502: Bad Gateway - Provider/upstream API failure}\n\n@endpoint GET /videos/models\n@desc List all video generation models\n@returns(200) {data: [map]} # Returns a list of video generation models\n@errors {400: Bad Request - Invalid request parameters or malformed input, 500: Internal Server Error - Unexpected server error}\n\n@endgroup\n\n@group workspaces\n@endpoint GET /workspaces\n@desc List workspaces\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of workspaces\n@errors {401: Unauthorized - Authentication required or invalid credentials, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /workspaces\n@desc Create a workspace\n@required {name: str # Name for the new workspace, slug: str # URL-friendly slug (lowercase alphanumeric segments separated by single hyphens, no leading/trailing hyphens)}\n@optional {default_image_model: str # Default image model for this workspace, default_provider_sort: str # Default provider sort preference (price, throughput, latency, exacto), default_text_model: str # Default text model for this workspace, description: str # Description of the workspace, io_logging_api_key_ids: [int] # Optional array of API key IDs to filter I/O logging, io_logging_sampling_rate: num(double) # Sampling rate for I/O logging (0.0001-1), is_data_discount_logging_enabled: bool # Whether data discount logging is enabled, is_observability_broadcast_enabled: bool # Whether broadcast is enabled, is_observability_io_logging_enabled: bool # Whether private logging is enabled}\n@returns(201) {data: any} # Workspace created successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 500: Internal Server Error - Unexpected server error}\n@example_request {\"default_image_model\":\"openai/dall-e-3\",\"default_provider_sort\":\"price\",\"default_text_model\":\"openai/gpt-4o\",\"description\":\"Production environment workspace\",\"name\":\"Production\",\"slug\":\"production\"}\n\n@endpoint DELETE /workspaces/{id}\n@desc Delete a workspace\n@required {id: str # The workspace ID (UUID) or slug}\n@optional {confirm_default_workspace_deletion: bool(true/false) # Required to delete the default workspace. Deleting it permanently disables the account’s unscoped inference API keys (management/provisioning keys are retained) and its budgets, guardrails, classifiers, and broadcast destinations. Ignored for non-default workspaces.}\n@returns(200) {deleted: bool} # Workspace deleted successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /workspaces/{id}\n@desc Get a workspace\n@required {id: str # The workspace ID (UUID) or slug}\n@returns(200) {data: any} # Workspace details\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint PATCH /workspaces/{id}\n@desc Update a workspace\n@required {id: str # The workspace ID (UUID) or slug}\n@optional {default_image_model: str # Default image model for this workspace, default_provider_sort: str # Default provider sort preference (price, throughput, latency, exacto), default_text_model: str # Default text model for this workspace, description: str # New description for the workspace, io_logging_api_key_ids: [int] # Optional array of API key IDs to filter I/O logging, io_logging_sampling_rate: num(double) # Sampling rate for I/O logging (0.0001-1), is_data_discount_logging_enabled: bool # Whether data discount logging is enabled, is_observability_broadcast_enabled: bool # Whether broadcast is enabled, is_observability_io_logging_enabled: bool # Whether private logging is enabled, name: str # New name for the workspace, slug: str # New URL-friendly slug (lowercase alphanumeric segments separated by single hyphens, no leading/trailing hyphens)}\n@returns(200) {data: any} # Workspace updated successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"name\":\"Updated Workspace\",\"slug\":\"updated-workspace\"}\n\n@endpoint GET /workspaces/{id}/members\n@desc List workspace members\n@required {id: str # The workspace ID (UUID) or slug}\n@optional {offset: int=0 # Number of records to skip for pagination, limit: int=50 # Maximum number of records to return (max 100)}\n@returns(200) {data: [map], total_count: int} # List of workspace members\n@errors {401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint POST /workspaces/{id}/members/add\n@desc Bulk add members to a workspace\n@required {id: str # The workspace ID (UUID) or slug, user_ids: [str] # List of user IDs to add to the workspace. Members are assigned the same role they hold in the organization.}\n@returns(200) {added_count: int, data: [map]} # Members added successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"user_ids\":[\"user_abc123\",\"user_def456\"]}\n\n@endpoint POST /workspaces/{id}/members/remove\n@desc Bulk remove members from a workspace\n@required {id: str # The workspace ID (UUID) or slug, user_ids: [str] # List of user IDs to remove from the workspace}\n@returns(200) {removed_count: int} # Members removed successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 403: Forbidden - Authentication successful but insufficient permissions, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"user_ids\":[\"user_abc123\",\"user_def456\"]}\n\n@endpoint GET /workspaces/{workspace_ref}/budgets\n@desc List workspace budgets\n@required {workspace_ref: str # The workspace ID (UUID) or slug}\n@returns(200) {data: [map], include_byok_in_budgets: bool} # Budgets retrieved successfully\n@errors {401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint DELETE /workspaces/{workspace_ref}/budgets/{interval}\n@desc Delete a workspace budget\n@required {workspace_ref: str # The workspace ID (UUID) or slug, interval: str # Budget reset interval. Use \"lifetime\" for a one-time budget that never resets.}\n@returns(200) {deleted: bool} # Budget deleted successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint GET /workspaces/{workspace_ref}/budgets/{interval}\n@desc Get a workspace budget\n@required {workspace_ref: str # The workspace ID (UUID) or slug, interval: str # Budget reset interval. Use \"lifetime\" for a one-time budget that never resets.}\n@returns(200) {data: any, include_byok_in_budgets: bool} # Budget retrieved successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n\n@endpoint PUT /workspaces/{workspace_ref}/budgets/{interval}\n@desc Create or update a workspace budget\n@required {workspace_ref: str # The workspace ID (UUID) or slug, interval: str # Budget reset interval. Use \"lifetime\" for a one-time budget that never resets., limit_usd: num(double) # Spending limit in USD. Must be greater than 0.}\n@optional {include_byok_in_budgets: bool # Whether to include BYOK (bring-your-own-key) spend when enforcing the workspace's budgets. This is a workspace-wide setting: it applies to every budget interval (daily, weekly, monthly, and lifetime), not just the interval being upserted in this request. Omit to leave the current setting unchanged.}\n@returns(200) {data: any, include_byok_in_budgets: bool} # Budget created or updated successfully\n@errors {400: Bad Request - Invalid request parameters or malformed input, 401: Unauthorized - Authentication required or invalid credentials, 404: Not Found - Resource does not exist, 500: Internal Server Error - Unexpected server error}\n@example_request {\"include_byok_in_budgets\":true,\"limit_usd\":100}\n\n@endgroup\n\n@end\n"}}