Authentication
Wallet-backed, OpenAI- and Anthropic-compatible inference. Authenticate with Authorization: Bearer ci_live_... or x-api-key: ci_live_... — both are accepted on every endpoint, and Authorization wins if both are present.
Every successful response carries a cheaper_inference object with the request id and what the request was billed. billed_cost_usd is a fixed 6-decimal string, not a number: a JSON float cannot round-trip a micro-dollar amount.
This document covers the customer-facing /v1 surface only.
Base URL
https://api.cheaperinference.com
Version 1.0.0 of the document. Paths below are relative to this base.
- BearerAuth — HTTP bearer: send `Authorization: Bearer <key>`.
- AnthropicApiKey — API key in the `x-api-key` request header.
Both schemes are accepted on every endpoint, and Authorization wins if both are present.
Chat
OpenAI-compatible chat and text completion.
/v1/chat/completionsstreamsCreate a chat completion
OpenAI-compatible. The request is optimized, served from the exact-match cache when possible, and billed against the wallet.
Query parameters
| Field | Type | Notes |
|---|---|---|
x-ci-prompt-cache | string | Prompt-cache knob. `passthrough` (default, or the API key's `prompt_cache_mode`) forwards the request unchanged; `on` additionally adds provider cache breakpoints for supported models. For Claude, unmarked requests cache the shared system/tools prefix and growing conversation; caller-supplied cache controls and lifetimes are preserved. `off` removes explicit cache controls and disables sticky affinity for this request; it does not disable a provider's implicit caching.on, off, passthrough |
x-ci-prompt-cache-scope | string | Sticky-affinity scope: `session` (default), `user`, or `org`. Scopes the affinity key that keeps a repeated prompt prefix on the same upstream provider so its cache stays warm.session, user, org |
x-ci-prompt-cache-session | string | Session id read when the scope is `session`. Send one stable value per conversation or agent run. When absent, a string prompt_cache_key in the request body is used. Without either identifier, the tools, opening system instructions and first conversation message identify the session. Affinity remains isolated to the API key. |
Request body ChatCompletionRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
messagesrequired | object[] | |
stream | boolean | |
max_tokens | integer | |
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
temperature | number | |
top_p | number | |
tools | object[] | |
tool_choice | any | |
reasoning_effort | string | Provider-normalized reasoning level. Gemini 3 does not support `none`.none, minimal, low, medium, high |
reasoning | object | null |
Additional properties are forwarded to the serving provider rather than rejected.
Response ChatCompletionResponse
Successful response
x-ci-zdr— Whether zero data retention applied to this request. Absent when no policy was recorded.x-ci-discount-percent— Quoted customer rate discount versus list, not the final effective savings after usage and optimizations. See usage history for the settled effective discount.X-Cheaper-Inference-Request-Id— Request identifier. Legacy name, still emitted; identical to x-ci-request-id.x-ci-request-id— Request identifier. Canonical going forward.x-ci-tokens-saved— Input tokens removed by the optimizer.x-ci-saved-usd— Total saved against the provider's list price, in USD.x-ci-techniques— Comma-separated ids of the optimization techniques applied. Empty when none were.x-ci-cache— `hit` or `miss` for the exact-match cache.x-ci-prompt-cache-affinity— Sticky prompt-cache outcome (KEA-5164). One of `hit`, `miss`, `new`, `stale`. Present only when the request carried a cacheable prefix and the affinity mode was not off; the exact-match `cache` header covers the separate response cache.x-ci-experiment-variant— Name of the assigned experiment variant. Present only when the request included X-CI-Experiment and matched a running experiment.x-ci-routing-overhead-ms— Elapsed milliseconds from proxy request start to dispatch of the successful provider attempt, including routing and prior attempts. On an exact-match cache hit, measures elapsed proxy processing time before returning the cached response. Present on successful buffered, streaming, and cached responses.x-ci-model-response-ms— Elapsed milliseconds from dispatch of the successful provider attempt until its complete JSON response has been read, before wallet settlement. Present only on successful buffered responses that reached a provider; absent on streams and exact-match cache hits. Measures full response time, not time to first token.
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/completionsstreamsCreate a text completion
OpenAI-compatible legacy completions.
Request body CompletionRequest
| Field | Type | Notes |
|---|---|---|
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
modelrequired | string | |
promptrequired | string | array | |
stream | boolean | |
max_tokens | integer |
Additional properties are forwarded to the serving provider rather than rejected.
Response CompletionResponse
Successful response
x-ci-zdr— Whether zero data retention applied to this request. Absent when no policy was recorded.x-ci-discount-percent— Quoted customer rate discount versus list, not the final effective savings after usage and optimizations. See usage history for the settled effective discount.X-Cheaper-Inference-Request-Id— Request identifier. Legacy name, still emitted; identical to x-ci-request-id.x-ci-request-id— Request identifier. Canonical going forward.x-ci-tokens-saved— Input tokens removed by the optimizer.x-ci-saved-usd— Total saved against the provider's list price, in USD.x-ci-techniques— Comma-separated ids of the optimization techniques applied. Empty when none were.x-ci-cache— `hit` or `miss` for the exact-match cache.x-ci-prompt-cache-affinity— Sticky prompt-cache outcome (KEA-5164). One of `hit`, `miss`, `new`, `stale`. Present only when the request carried a cacheable prefix and the affinity mode was not off; the exact-match `cache` header covers the separate response cache.x-ci-experiment-variant— Name of the assigned experiment variant. Present only when the request included X-CI-Experiment and matched a running experiment.x-ci-routing-overhead-ms— Elapsed milliseconds from proxy request start to dispatch of the successful provider attempt, including routing and prior attempts. On an exact-match cache hit, measures elapsed proxy processing time before returning the cached response. Present on successful buffered, streaming, and cached responses.x-ci-model-response-ms— Elapsed milliseconds from dispatch of the successful provider attempt until its complete JSON response has been read, before wallet settlement. Present only on successful buffered responses that reached a provider; absent on streams and exact-match cache hits. Measures full response time, not time to first token.
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Images
OpenAI-compatible image generation and canary-gated image editing.
/v1/images/generationsGenerate images
Generate one or more images. Streaming is not supported on this endpoint.
Request body ImageGenerationRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
promptrequired | string | length 1–∞ |
n | integer | 1–10 |
size | string | |
quality | string | |
response_format | string |
Additional properties are forwarded to the serving provider rather than rejected.
Response ImageResponse
Successful response
x-ci-zdr— Whether zero data retention applied to this request. Absent when no policy was recorded.x-ci-discount-percent— Quoted customer rate discount versus list, not the final effective savings after usage and optimizations. See usage history for the settled effective discount.X-Cheaper-Inference-Request-Id— Request identifier. Legacy name, still emitted; identical to x-ci-request-id.x-ci-request-id— Request identifier. Canonical going forward.x-ci-tokens-saved— Input tokens removed by the optimizer.x-ci-saved-usd— Total saved against the provider's list price, in USD.x-ci-techniques— Comma-separated ids of the optimization techniques applied. Empty when none were.x-ci-cache— `hit` or `miss` for the exact-match cache.x-ci-prompt-cache-affinity— Sticky prompt-cache outcome (KEA-5164). One of `hit`, `miss`, `new`, `stale`. Present only when the request carried a cacheable prefix and the affinity mode was not off; the exact-match `cache` header covers the separate response cache.x-ci-experiment-variant— Name of the assigned experiment variant. Present only when the request included X-CI-Experiment and matched a running experiment.x-ci-routing-overhead-ms— Elapsed milliseconds from proxy request start to dispatch of the successful provider attempt, including routing and prior attempts. On an exact-match cache hit, measures elapsed proxy processing time before returning the cached response. Present on successful buffered, streaming, and cached responses.x-ci-model-response-ms— Elapsed milliseconds from dispatch of the successful provider attempt until its complete JSON response has been read, before wallet settlement. Present only on successful buffered responses that reached a provider; absent on streams and exact-match cache hits. Measures full response time, not time to first token.
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/images/editsEdit images
Edit up to 10 source images with a 20 MiB decoded aggregate limit across the sources and optional mask. The OpenAI-compatible multipart form accepts `image` uploads and an optional PNG `mask`. The JSON extension accepts `input_references` containing HTTP(S) URLs or image data URLs; external URLs are passed only to compatible providers and are never fetched or stored by CheaperInference. Models are eligible only after a live edit canary; discover them through `capabilities.image_edit` on GET /v1/models.
Request body ImageEditJsonRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
promptrequired | string | length 1–32000 |
input_referencesrequired | string[] | |
mask_reference | string | Optional PNG data URL. External mask URLs are not accepted. |
n | integer | 1–10 |
size | string | |
quality | string | |
background | string | |
input_fidelity | string | |
output_format | string | |
output_compression | integer | 0–100 |
response_format | string | |
user | string | |
stream | boolean | false |
Response ImageResponse
Successful response
x-ci-zdr— Whether zero data retention applied to this request. Absent when no policy was recorded.x-ci-discount-percent— Quoted customer rate discount versus list, not the final effective savings after usage and optimizations. See usage history for the settled effective discount.X-Cheaper-Inference-Request-Id— Request identifier. Legacy name, still emitted; identical to x-ci-request-id.x-ci-request-id— Request identifier. Canonical going forward.x-ci-tokens-saved— Input tokens removed by the optimizer.x-ci-saved-usd— Total saved against the provider's list price, in USD.x-ci-techniques— Comma-separated ids of the optimization techniques applied. Empty when none were.x-ci-cache— `hit` or `miss` for the exact-match cache.x-ci-prompt-cache-affinity— Sticky prompt-cache outcome (KEA-5164). One of `hit`, `miss`, `new`, `stale`. Present only when the request carried a cacheable prefix and the affinity mode was not off; the exact-match `cache` header covers the separate response cache.x-ci-experiment-variant— Name of the assigned experiment variant. Present only when the request included X-CI-Experiment and matched a running experiment.x-ci-routing-overhead-ms— Elapsed milliseconds from proxy request start to dispatch of the successful provider attempt, including routing and prior attempts. On an exact-match cache hit, measures elapsed proxy processing time before returning the cached response. Present on successful buffered, streaming, and cached responses.x-ci-model-response-ms— Elapsed milliseconds from dispatch of the successful provider attempt until its complete JSON response has been read, before wallet settlement. Present only on successful buffered responses that reached a provider; absent on streams and exact-match cache hits. Measures full response time, not time to first token.
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Messages
Anthropic Messages. Claude Code integrates here.
/v1/messagesstreamsCreate a message
Anthropic Messages. `max_tokens` is required. Errors use Anthropic's envelope, which carries no `code` or `param`.
Query parameters
| Field | Type | Notes |
|---|---|---|
x-ci-prompt-cache | string | Prompt-cache knob. `passthrough` (default, or the API key's `prompt_cache_mode`) forwards the request unchanged; `on` additionally adds provider cache breakpoints for supported models. For Claude, unmarked requests cache the shared system/tools prefix and growing conversation; caller-supplied cache controls and lifetimes are preserved. `off` removes explicit cache controls and disables sticky affinity for this request; it does not disable a provider's implicit caching.on, off, passthrough |
x-ci-prompt-cache-scope | string | Sticky-affinity scope: `session` (default), `user`, or `org`. Scopes the affinity key that keeps a repeated prompt prefix on the same upstream provider so its cache stays warm.session, user, org |
x-ci-prompt-cache-session | string | Session id read when the scope is `session`. Send one stable value per conversation or agent run. When absent, a string prompt_cache_key in the request body is used. Without either identifier, the tools, opening system instructions and first conversation message identify the session. Affinity remains isolated to the API key. |
Request body AnthropicMessagesRequest
| Field | Type | Notes |
|---|---|---|
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
modelrequired | string | |
max_tokensrequired | integer | Required on this endpoint. |
messagesrequired | object[] | |
system | string | array | |
stream | boolean | |
stop_sequences | string[] | |
temperature | number | |
top_p | number | |
tools | object[] | |
tool_choice | object | |
thinking | object |
Additional properties are forwarded to the serving provider rather than rejected.
Response AnthropicMessagesResponse
Successful response
x-ci-zdr— Whether zero data retention applied to this request. Absent when no policy was recorded.x-ci-discount-percent— Quoted customer rate discount versus list, not the final effective savings after usage and optimizations. See usage history for the settled effective discount.X-Cheaper-Inference-Request-Id— Request identifier. Legacy name, still emitted; identical to x-ci-request-id.x-ci-request-id— Request identifier. Canonical going forward.x-ci-tokens-saved— Input tokens removed by the optimizer.x-ci-saved-usd— Total saved against the provider's list price, in USD.x-ci-techniques— Comma-separated ids of the optimization techniques applied. Empty when none were.x-ci-cache— `hit` or `miss` for the exact-match cache.x-ci-prompt-cache-affinity— Sticky prompt-cache outcome (KEA-5164). One of `hit`, `miss`, `new`, `stale`. Present only when the request carried a cacheable prefix and the affinity mode was not off; the exact-match `cache` header covers the separate response cache.x-ci-experiment-variant— Name of the assigned experiment variant. Present only when the request included X-CI-Experiment and matched a running experiment.x-ci-routing-overhead-ms— Elapsed milliseconds from proxy request start to dispatch of the successful provider attempt, including routing and prior attempts. On an exact-match cache hit, measures elapsed proxy processing time before returning the cached response. Present on successful buffered, streaming, and cached responses.x-ci-model-response-ms— Elapsed milliseconds from dispatch of the successful provider attempt until its complete JSON response has been read, before wallet settlement. Present only on successful buffered responses that reached a provider; absent on streams and exact-match cache hits. Measures full response time, not time to first token.
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/messages/count_tokensCount input tokens
Estimate the input tokens for a Messages request. Makes no upstream call and moves no money, so `max_tokens` is not required.
Request body CountTokensRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
messagesrequired | object[] | |
system | string | array | |
tools | object[] |
Additional properties are forwarded to the serving provider rather than rejected.
Response CountTokensResponse
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Responses
OpenAI Responses. Codex integrates here.
/v1/responsesstreamsCreate a response
OpenAI Responses, the surface Codex uses. Stateless: `store` must be `false`, and `previous_response_id` and `conversation` are refused. Replay prior output items in `input` instead. Namespace tools may mix function and custom/freeform entries, including inside `input[].additional_tools`; namespace and call metadata are preserved in buffered and streamed output. Gemini 3 requests using `reasoning_effort: none` fail with code `unsupported_reasoning_effort`.
Query parameters
| Field | Type | Notes |
|---|---|---|
x-ci-prompt-cache | string | Prompt-cache knob. `passthrough` (default, or the API key's `prompt_cache_mode`) forwards the request unchanged; `on` additionally adds provider cache breakpoints for supported models. For Claude, unmarked requests cache the shared system/tools prefix and growing conversation; caller-supplied cache controls and lifetimes are preserved. `off` removes explicit cache controls and disables sticky affinity for this request; it does not disable a provider's implicit caching.on, off, passthrough |
x-ci-prompt-cache-scope | string | Sticky-affinity scope: `session` (default), `user`, or `org`. Scopes the affinity key that keeps a repeated prompt prefix on the same upstream provider so its cache stays warm.session, user, org |
x-ci-prompt-cache-session | string | Session id read when the scope is `session`. Send one stable value per conversation or agent run. When absent, a string prompt_cache_key in the request body is used. Without either identifier, the tools, opening system instructions and first conversation message identify the session. Affinity remains isolated to the API key. |
Request body ResponsesRequest
| Field | Type | Notes |
|---|---|---|
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
modelrequired | string | |
storerequired | boolean | Must be false. This endpoint is stateless.false |
inputrequired | any | |
instructions | string | null | |
stream | boolean | |
max_output_tokens | integer | null | |
tools | ResponsesTool[] | |
tool_choice | any | |
parallel_tool_calls | boolean | |
reasoning_effort | string | Alias for reasoning.effort. Supplying conflicting values is a 400. Gemini 3 does not support `none` and returns `unsupported_reasoning_effort`.none, minimal, low, medium, high |
reasoning | object | null | |
text | object |
Additional properties are forwarded to the serving provider rather than rejected.
Response ResponsesResponse
Successful response
x-ci-zdr— Whether zero data retention applied to this request. Absent when no policy was recorded.x-ci-discount-percent— Quoted customer rate discount versus list, not the final effective savings after usage and optimizations. See usage history for the settled effective discount.X-Cheaper-Inference-Request-Id— Request identifier. Legacy name, still emitted; identical to x-ci-request-id.x-ci-request-id— Request identifier. Canonical going forward.x-ci-tokens-saved— Input tokens removed by the optimizer.x-ci-saved-usd— Total saved against the provider's list price, in USD.x-ci-techniques— Comma-separated ids of the optimization techniques applied. Empty when none were.x-ci-cache— `hit` or `miss` for the exact-match cache.x-ci-prompt-cache-affinity— Sticky prompt-cache outcome (KEA-5164). One of `hit`, `miss`, `new`, `stale`. Present only when the request carried a cacheable prefix and the affinity mode was not off; the exact-match `cache` header covers the separate response cache.x-ci-experiment-variant— Name of the assigned experiment variant. Present only when the request included X-CI-Experiment and matched a running experiment.x-ci-routing-overhead-ms— Elapsed milliseconds from proxy request start to dispatch of the successful provider attempt, including routing and prior attempts. On an exact-match cache hit, measures elapsed proxy processing time before returning the cached response. Present on successful buffered, streaming, and cached responses.x-ci-model-response-ms— Elapsed milliseconds from dispatch of the successful provider attempt until its complete JSON response has been read, before wallet settlement. Present only on successful buffered responses that reached a provider; absent on streams and exact-match cache hits. Measures full response time, not time to first token.
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Models
The catalog, its capabilities and its prices.
/v1/modelsList models
Every model this platform serves, with capabilities and prices. `pricing_version` is a SHA-256 over the list that was returned, so a filtered response validates its own cache and not the unfiltered one.
Query parameters
| Field | Type | Notes |
|---|---|---|
type | string | `text` for chat models, `image` for models that generate something other than text.text, image |
vision | boolean | Select models that do or do not accept image input. Accepts 1/true/t/yes/y/on and 0/false/f/no/n/off. |
video | boolean | Select models that do or do not accept video input. Accepts 1/true/t/yes/y/on and 0/false/f/no/n/off. |
reasoning | boolean | Select models that do or do not reason. Accepts 1/true/t/yes/y/on and 0/false/f/no/n/off. |
streaming | boolean | Select models that do or do not stream. Accepts 1/true/t/yes/y/on and 0/false/f/no/n/off. |
zdr | boolean | `true` switches to the zero-data-retention view: only models a `zdr: true` request can be served for, priced at what that request pays. `false` (the default) is the standard view, not a filter for models without ZDR supply. |
provider | string | Exact provider name, compared trimmed and case-insensitively. A prefix does not match.length 1–80 |
Response ModelList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/public/modelsList models (public)
The advertised catalog, with live prices, and NO API KEY. This is what the marketing pages and any other surface that cannot hold a key read. Prices are resolved by the same rule that bills a request, so a quote here and the charge cannot disagree. `/v1/models` covers the same catalog for authenticated clients and adds marketplace-only models.
Response PublicModelCatalog
The catalog.
Error statuses (1)
503The catalog could not be read. No prices are served rather than stale ones.
/public/models/{model_id}Get one model (public)
One catalog entry. The id may contain slashes (`google/gemini-3.5-flash-lite`) and is matched exactly, including case.
Query parameters
| Field | Type | Notes |
|---|---|---|
model_idrequired | string | Model id. May contain `/`. |
Response PublicModel
The model.
Error statuses (2)
404No such model, or it is not currently advertised.503The catalog could not be read. No prices are served rather than stale ones.
/v1/pricing/changesPrice changes
Price moves at or after `since`, oldest first, so a client can detect changes without re-diffing the catalogue. Store the `changed_at` of the last change you processed and pass it as `since` on the next poll, then follow `next_cursor` to the end. Requires the `usage:read` scope.
Query parameters
| Field | Type | Notes |
|---|---|---|
sincerequired | string (date-time) | Return changes at or after this time. Required: there is no default window, and an unbounded feed would return the whole price history. |
limit | integer | Maximum changes to return.1–100 |
cursor | string | Opaque cursor from the previous page's `next_cursor`. |
Response PricingChangeList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/models/supplyCount supply under a price ceiling
How many supply sources would currently serve a chat request carrying `min_discount_percent` and/or `zdr=true` for this model, using the same filter the request path applies. At least one of the two is required. Candidates are priced under the ceiling now; health and fill are not guaranteed.
Query parameters
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
min_discount_percent | number | 0–99.99 |
zdr | boolean | Count only zero-data-retention suppliers. |
Response ModelSupply
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/models/comparePrice a workload across models
What a given number of prompt and completion tokens would cost on each of up to ten models, cheapest first. Needs usage:read only — it discloses catalog pricing, nothing about the account.
Query parameters
| Field | Type | Notes |
|---|---|---|
modelsrequired | string | Comma-separated model ids. At most 10. |
prompt_tokens | integer | 0–10000000 |
completion_tokens | integer | 0–10000000 |
requests | integer | Multiply the per-request cost by this. Defaults to 1.min 1 |
Response ModelComparison
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Usage
What the workspace spent. Requires the usage:read scope.
/v1/usage/requestsList requests
Per-request history for the calling workspace, newest first. Requires the `usage:read` scope. `cursor` is opaque and comes from the previous page's `next_cursor`; do not parse it.
Query parameters
| Field | Type | Notes |
|---|---|---|
limit | integer | 1–100 |
cursor | string | Opaque cursor from the previous page. |
start_at | string (date-time) | Inclusive lower bound. A value with no offset is read as UTC. |
end_at | string (date-time) | Exclusive upper bound. |
api_key_id | string (uuid) | Limit to one key in the calling workspace. A key outside it is a 404, not an empty list. |
Response UsageRequestList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/usage/dailyDaily spend
Daily spend for the calling workspace, defaulting to the last 30 days and zero-filled across the range so a chart does not close gaps. Requires the `usage:read` scope. Only settled requests contribute to spend.
Query parameters
| Field | Type | Notes |
|---|---|---|
start_at | string (date-time) | Inclusive lower bound. A value with no offset is read as UTC. |
end_at | string (date-time) | Exclusive upper bound. |
api_key_id | string (uuid) | Limit to one key in the calling workspace. A key outside it is a 404, not an empty list. |
timezone_offset_minutes | integer | Minutes east of UTC, deciding which calendar day a request falls on.-840–840 |
Response UsageDaily
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Feedback
Score a completed request.
/v1/feedbackScore a request
Rate a completed request 1-5. Not present on the legacy service.
Request body FeedbackRequest
| Field | Type | Notes |
|---|---|---|
request_idrequired | string (uuid) | |
scorerequired | integer | 1–5 |
comment | string | null |
Response FeedbackResponse
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Account
Wallet, savings, experiments, techniques, keys and connected chat channels. Reads need the account:read scope and changes need account:write; neither is on a key by default. This is the surface the MCP server drives.
/v1/accountGet the account
Email, workspace and role, how many keys are live and when one was last used, and how many optimization techniques are actually on.
Response Account
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/account/balanceGet the wallet balance
Balance, what is reserved against requests in flight, and auto-recharge state. Spend against `available_usd`, not `balance_usd`.
Response AccountBalance
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/account/usageSummarize usage over a window
Requests, billed, saved versus list price and the top models. The rolled-up counterpart to /v1/usage/daily's per-day series.
Query parameters
| Field | Type | Notes |
|---|---|---|
days | integer | Window in days. Defaults to 7, maximum 90.1–90 |
Response AccountUsage
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/account/savingsGet the savings snapshot
Savings over 24 hours, 7 days and 30 days, every experiment's per-request economics, and the technique catalog with this account's state on each.
Response AccountSavings
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/experimentsList experiments
Every experiment on the account with its cost, savings and feedback.
Response ExperimentList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/experiments/{experiment_id}Get an experiment
One experiment broken down per variant, so arms can be compared.
Query parameters
| Field | Type | Notes |
|---|---|---|
experiment_idrequired | string (uuid) |
Response Experiment
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/techniquesList optimization techniques
The catalog with this account's state on each entry. Preview and unimplemented techniques are included and flagged, not hidden.
Response TechniqueList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/techniques/{technique_id}Enable or disable a technique
Requires account:write. A technique that is not implemented, or is deprecated, is refused with a 404.
Query parameters
| Field | Type | Notes |
|---|---|---|
technique_idrequired | string |
Request body TechniqueUpdateRequest
| Field | Type | Notes |
|---|---|---|
enabledrequired | boolean |
Response TechniqueUpdateResponse
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/keysList API keys
Prefixes only. Saved full keys can be copied by their owner in the dashboard.
Query parameters
| Field | Type | Notes |
|---|---|---|
include_revoked | boolean | Include revoked keys. Defaults to false. Accepts 1/true/t/yes/y/on and 0/false/f/no/n/off. |
Response ApiKeyList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/keysCreate an API key
Requires account:write, and refuses a caller authenticated through a chat integration: a short-lived internal token must not be able to mint a permanent credential. The plaintext key is returned in the response. Its owner can also copy the saved key in the dashboard.
Request body ApiKeyCreateRequest
| Field | Type | Notes |
|---|---|---|
name | string | length 0–64 |
organization_id | string | null | |
scopes | string[] | Defaults to inference and usage:read. |
allowed_models | string[] | |
allowed_ip_cidrs | string[] | |
expires_at | string | null | |
rate_limit_per_minute | integer | null | |
daily_request_limit | integer | null | |
concurrency_limit | integer | null | |
monthly_spend_limit_usd | number | null |
Response ApiKeyCreated
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/keys/{key_id}Revoke an API key
Requires account:write. Revoking the key you are authenticating with is allowed — the next request simply fails to authenticate.
Query parameters
| Field | Type | Notes |
|---|---|---|
key_idrequired | string (uuid) |
Response ApiKeyRevoked
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/channelsList connected chat channels
Every Slack, Discord, Telegram and email channel this account has connected, plus the event catalog PATCH accepts.
Response ChannelList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/channels/{channel_id}Get a channel
One channel's subscriptions and digest schedule.
Query parameters
| Field | Type | Notes |
|---|---|---|
channel_idrequired | string (uuid) |
Response Channel
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/channels/{channel_id}Change a channel's schedule or subscriptions
Requires account:write. An events list containing an unknown id is refused whole rather than partially applied.
Query parameters
| Field | Type | Notes |
|---|---|---|
channel_idrequired | string (uuid) |
Request body ChannelUpdateRequest
| Field | Type | Notes |
|---|---|---|
report_frequency | string | daily, weekly, monthly, off |
events | string[] |
Response Channel
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/channels/{channel_id}/send-reportPost the savings digest now
Requires account:write. Throttled to one send per channel per minute, and does not consume the next scheduled digest.
Query parameters
| Field | Type | Notes |
|---|---|---|
channel_idrequired | string (uuid) |
Response ChannelReportResponse
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/security/strikesRecord a refused request against the calling account
Reported by the MCP server when it refuses a call. `injection`, `escalation` and `policy` describe hostile ARGUMENTS and ban the account on the first one — permanently, across every surface, not only the account API. `unauthorized` and `forbidden` describe a credential rather than an intent (a rotated key, a missing scope), so they are accepted and have no consequence. There is no rolling window, no warning tier and no escalation ladder. No scope is required. Returns the account's standing, and files a support ticket on the account's behalf so a block has somewhere to be contested.
Request body SecurityStrikeRequest
| Field | Type | Notes |
|---|---|---|
toolrequired | string | The MCP tool that was called.length 0–80 |
kindrequired | string | What was refused. `injection`, `escalation` and `policy` are refusals the MCP server issued itself and each count as a strike; `unauthorized` (401) and `forbidden` (403) are API denials and count once per distinct `detail`.injection, escalation, policy, unauthorized, forbidden |
detailrequired | string | A short stable code for the reason — never the offending text.length 0–200 |
Response SecurityStanding
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/security/standingGet the calling account's standing
Whether the account is blocked, and where to appeal. A block is a ban: it has no expiry, so `blocked_until` is always null and `permanent` is true whenever `tier` is `blocked`. The counting fields (`strikes`, `attempts`, `remaining`, `warn_after`, `block_after`, `window_hours`) are retained for compatibility with deployed MCP clients and now describe a one-strike policy rather than a tally. No scope is required. A banned account is refused at authentication, so this route answers for accounts that are not blocked — which is what lets a client notice a lift.
Response SecurityStanding
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/billing/topupStart a wallet top-up
Requires account:write. Creates a Stripe Checkout session and returns its link. Nothing is charged here — the customer completes the payment on Stripe's own page, with the amount in front of them.
Request body TopupRequest
| Field | Type | Notes |
|---|---|---|
amount_usdrequired | number | 5–1000 |
Response TopupResponse
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Docs
The product documentation, searchable. Public content, so any valid key reads it — no scope. It exists as an endpoint so an assistant can answer 'how do I…' from the shipped text rather than from memory.
/v1/docsSearch the documentation
With `q`, the matching sections in full, best match first. Without it, the table of contents — every section's id, title, category and link, no bodies — so a client can see what exists before choosing what to read. Needs a valid key and no scope: this is the same text served at /docs.
Query parameters
| Field | Type | Notes |
|---|---|---|
q | string | What to look up. Keywords beat sentences: the corpus is a couple of dozen sections and matching is on titles, keywords and body text. |
limit | integer | Maximum sections to return. Ignored without `q`.1–10 |
Response DocSectionList
Successful response
Error statuses (15)
400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Uploads
/v1/uploadsUpload a temporary image
Store an image for a short time and receive a `file_id`. Send that id in a chat message and it is swapped for a signed URL on the way to the provider. Rejected for an account with zero data retention.
Error statuses (16)
201The upload was stored400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
/v1/uploads/{upload_id}Delete a temporary image
Remove an upload before it expires. An id belonging to another account answers 404, exactly as an unknown one does.
Query parameters
| Field | Type | Notes |
|---|---|---|
upload_idrequired | string |
Error statuses (16)
204The upload was deleted400Malformed request (`type: invalid_request_error`, `code: invalid_request`)401Invalid or missing API key (`type: authentication_error`, `code: invalid_api_key`)402Insufficient wallet balance (`type: invalid_request_error`, `code: insufficient_balance`)403The API key lacks the scope this endpoint requires (`type: permission_denied_error`, `code: permission_denied`)404Not found (`type: invalid_request_error`, `code: not_found`)408Request timed out (`type: invalid_request_error`, `code: request_failed`)409Conflict (`type: invalid_request_error`, `code: conflict`)413Request too large (`type: invalid_request_error`, `code: request_too_large`)422A parameter failed validation (`type: invalid_request_error`, `code: invalid_request`)425Too early (`type: invalid_request_error`, `code: request_failed`)429Rate limited (`type: rate_limit_error`, `code: rate_limit_exceeded`)500Server error (`type: api_error`, `code: server_error`)502The upstream provider returned an unusable response (`type: api_error`, `code: upstream_error`)503Service unavailable (`type: api_error`, `code: service_unavailable`)504Upstream timeout (`type: api_error`, `code: upstream_timeout`)
Schemas
Every object named above, with the fields the API declares. Objects marked as forwarding additional properties accept fields not listed here and pass them to the serving provider.
OpenAIError
Every `/v1/*` path except `/v1/messages*`.
| Field | Type | Notes |
|---|---|---|
errorrequired | object |
AnthropicError
`/v1/messages` and `/v1/messages/count_tokens`. No `code`, no `param`.
| Field | Type | Notes |
|---|---|---|
typerequired | string | error |
errorrequired | object |
ChatCompletionRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
messagesrequired | object[] | |
stream | boolean | |
max_tokens | integer | |
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
temperature | number | |
top_p | number | |
tools | object[] | |
tool_choice | any | |
reasoning_effort | string | Provider-normalized reasoning level. Gemini 3 does not support `none`.none, minimal, low, medium, high |
reasoning | object | null |
Additional properties are forwarded rather than rejected.
ChatCompletionResponse
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
object | string | |
created | integer | |
model | string | |
choicesrequired | object[] | |
usage | object | |
cheaper_inference | object | What this request was billed. Present on every successful response. |
Additional properties are forwarded rather than rejected.
CompletionRequest
| Field | Type | Notes |
|---|---|---|
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
modelrequired | string | |
promptrequired | string | array | |
stream | boolean | |
max_tokens | integer |
Additional properties are forwarded rather than rejected.
CompletionResponse
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
choicesrequired | object[] | |
usage | object | |
cheaper_inference | object | What this request was billed. Present on every successful response. |
Additional properties are forwarded rather than rejected.
ImageGenerationRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
promptrequired | string | length 1–∞ |
n | integer | 1–10 |
size | string | |
quality | string | |
response_format | string |
Additional properties are forwarded rather than rejected.
ImageEditJsonRequest
CheaperInference JSON extension. URL references are never fetched or stored by CheaperInference and are eligible only on provider routes that accept URLs.
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
promptrequired | string | length 1–32000 |
input_referencesrequired | string[] | |
mask_reference | string | Optional PNG data URL. External mask URLs are not accepted. |
n | integer | 1–10 |
size | string | |
quality | string | |
background | string | |
input_fidelity | string | |
output_format | string | |
output_compression | integer | 0–100 |
response_format | string | |
user | string | |
stream | boolean | false |
ImageEditMultipartRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
promptrequired | string | length 1–32000 |
imagerequired | any | One to 10 PNG, JPEG, or WebP uploads. Decoded sources plus the optional mask must total at most 20 MiB. |
mask | string (binary) | Optional PNG mask upload. |
n | integer | 1–10 |
size | string | |
quality | string | |
background | string | |
input_fidelity | string | |
output_format | string | |
output_compression | integer | 0–100 |
response_format | string | |
user | string | |
stream | boolean | false |
ImageResponse
| Field | Type | Notes |
|---|---|---|
created | integer | |
datarequired | object[] | |
cheaper_inference | object | What this request was billed. Present on every successful response. |
Additional properties are forwarded rather than rejected.
AnthropicMessagesRequest
| Field | Type | Notes |
|---|---|---|
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
modelrequired | string | |
max_tokensrequired | integer | Required on this endpoint. |
messagesrequired | object[] | |
system | string | array | |
stream | boolean | |
stop_sequences | string[] | |
temperature | number | |
top_p | number | |
tools | object[] | |
tool_choice | object | |
thinking | object |
Additional properties are forwarded rather than rejected.
AnthropicMessagesResponse
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
typerequired | string | message |
rolerequired | string | assistant |
model | string | |
contentrequired | object[] | |
stop_reason | string | null | |
stop_sequence | string | null | |
usage | object | |
cheaper_inference | object | What this request was billed. Present on every successful response. |
CountTokensRequest
| Field | Type | Notes |
|---|---|---|
modelrequired | string | |
messagesrequired | object[] | |
system | string | array | |
tools | object[] |
Additional properties are forwarded rather than rejected.
CountTokensResponse
| Field | Type | Notes |
|---|---|---|
input_tokensrequired | integer |
ResponsesRequest
| Field | Type | Notes |
|---|---|---|
min_discount_percent | number | Price ceiling for this request as a minimum discount off the model's list price (see GET /v1/models pricing.list_*). Only supply priced under list × (1 − d) serves the request, and the bill is capped at that rate. With no qualifying supply the request fails with 503 `min_discount_unavailable` instead of falling back. Stripped before forwarding.0–99.99 |
zdr | boolean | Route this request only through providers that support a zero-data-retention policy. A zero-data-retention provider does not keep your prompts or responses and does not train on them. The marketplace and every unverified provider are excluded, so the price is the ZDR price shown by `GET /v1/models?zdr=true`. Adds to the account's Data Protection setting; it cannot lift it. With no qualifying supply the request fails with 503 `zdr_capacity_unavailable`. Stripped before forwarding. |
ranking | string | How the gateway orders the discounted sources that can serve this request. `discount`: cheapest first. `speed`: highest recent speed first, measured on this model from the gateway's own traffic (time to first visible output and output tokens per second, weighted towards the last hour); cost breaks ties. `balance` (default): speed score × discount. Speed and discount are NOT a trade-off: the fastest source is often also a cheap one, so `speed` can return the same route as `discount`. The reference rails (OpenRouter, Vercel AI Gateway) are not ranked; they are tried only when no discounted source can serve the request in time. The mode changes the order only, never which sources are eligible. Stripped before forwarding.speed, discount, balance |
modelrequired | string | |
storerequired | boolean | Must be false. This endpoint is stateless.false |
inputrequired | any | |
instructions | string | null | |
stream | boolean | |
max_output_tokens | integer | null | |
tools | ResponsesTool[] | |
tool_choice | any | |
parallel_tool_calls | boolean | |
reasoning_effort | string | Alias for reasoning.effort. Supplying conflicting values is a 400. Gemini 3 does not support `none` and returns `unsupported_reasoning_effort`.none, minimal, low, medium, high |
reasoning | object | null | |
text | object |
Additional properties are forwarded rather than rejected.
ResponsesFunctionTool
| Field | Type | Notes |
|---|---|---|
typerequired | string | function |
namerequired | string | length 1–∞ |
description | string | |
parameters | object | |
strict | boolean |
Additional properties are forwarded rather than rejected.
ResponsesCustomTool
A freeform/custom tool. Providers without native custom tools receive a function wrapper whose sole input is the raw custom-tool string.
| Field | Type | Notes |
|---|---|---|
typerequired | string | custom |
namerequired | string | length 1–∞ |
description | string | |
format | object |
Additional properties are forwarded rather than rejected.
ResponsesNamespaceTool
Responses Lite namespace. Function and custom entries may be mixed in one namespace.
| Field | Type | Notes |
|---|---|---|
typerequired | string | namespace |
namerequired | string | length 1–∞ |
description | string | |
toolsrequired | array |
Additional properties are forwarded rather than rejected.
ResponsesHostedTool
An optional hosted tool. Offering one is tolerated, but selecting it with tool_choice is rejected because CheaperInference cannot execute it.
| Field | Type | Notes |
|---|---|---|
typerequired | string | file_search, tool_search, web_search, web_search_preview |
Additional properties are forwarded rather than rejected.
ResponsesTool
A passthrough object: the API does not constrain its shape.
ResponsesAdditionalToolsItem
| Field | Type | Notes |
|---|---|---|
typerequired | string | additional_tools |
toolsrequired | ResponsesTool[] |
Additional properties are forwarded rather than rejected.
ResponsesInputItem
A message, reasoning item, replayed function/custom call or output, agent message, or Responses Lite additional-tools declaration.
A passthrough object: the API does not constrain its shape.
ResponsesResponse
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
objectrequired | string | response |
created_at | integer | |
statusrequired | string | completed, incomplete, failed, in_progress |
outputrequired | object[] | |
usage | object | null | |
cheaper_inference | object | What this request was billed. Present on every successful response. |
Additional properties are forwarded rather than rejected.
ModelList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
datarequired | Model[] | |
pricing_versionrequired | string | |
pricing_checked_at | string | null | |
pricing_updated_at | string | null |
Model
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
context_length | integer | null | Total context window in tokens; null when the provider does not publish it. |
max_output_tokens | integer | null | Published maximum output tokens; null when unknown. |
objectrequired | string | model |
owned_by | string | |
provider | string | null | |
typerequired | string | text, image, video |
endpoint | string | |
capabilitiesrequired | object | |
is_free | boolean | |
available_until | string | null | |
pricingrequired | object |
PublicModelCatalog
| Field | Type | Notes |
|---|---|---|
modelsrequired | PublicModel[] |
PublicModel
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
context_length | integer | null | |
max_output_tokens | integer | null | |
aliases | string[] | Vendor-qualified ids that also resolve to this model. |
model_typerequired | string | text, image, video |
input_per_millionrequired | string | |
output_per_millionrequired | string | |
cache_read_per_million | string | null | |
cache_write_per_million | string | null | |
image_output_per_million | string | null | |
media_input_unit_price | string | null | |
media_unit_price | string | null | Price per picture, for models billed per unit. Their token rates are not the price. |
media_unit | string | null | |
media_prices | map<string, string> | |
image_pricing_unit | string | token, image |
reference_input_per_million | string | null | |
reference_output_per_million | string | null | |
reference_cache_read_per_million | string | null | |
reference_cache_write_per_million | string | null | |
reference_image_output_per_million | string | null | |
reference_media_input_unit_price | string | null | |
reference_media_unit_price | string | null | |
reference_media_prices | map<string, string> | |
discount_percentrequired | string | Measured from the price actually charged against the list price, on whichever basis bills the model. `0.00` means no list price is published to compare with. |
logo_url | string | null | |
provider_name | string | null | |
primary_model_id | string | null | |
is_visible | boolean | |
supports_vision | boolean | |
supports_video | boolean | |
supports_reasoning | boolean | |
reasoning_capability_mode | string | auto, manual |
supports_streaming | boolean | |
supports_image_edit | boolean | True only after this model passes a live image-edit canary. |
is_free | boolean | |
available_until | string | null | |
input_token_price_threshold | integer | null | |
input_per_million_above_threshold | string | null | |
output_per_million_above_threshold | string | null | |
above_threshold | object | null | Conditional rates for the whole request when total prompt tokens, including cached tokens, exceed the threshold and the serving supplier charges a long-context premium. Flat-rate supply retains base prices. Customer price caps still apply. |
zero_data_retention | boolean | |
zero_data_retention_route | string | null | Which supply class set the ZDR price: `seller` (a verified seller network) or `rail`. Null outside the `?zdr=true` view.seller, rail, null |
DetailError
The error body the /public routes answer with.
| Field | Type | Notes |
|---|---|---|
detailrequired | string |
UsageRequestList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
scoperequired | string | workspace |
datarequired | UsageRequest[] | |
has_morerequired | boolean | |
next_cursor | string | null | Opaque. Pass back as `cursor`; do not parse. |
UsageRequest
| Field | Type | Notes |
|---|---|---|
request_idrequired | string (uuid) | |
api_key_id | string | null | |
api_key_name | string | null | |
modelrequired | string | |
endpointrequired | string | |
statusrequired | string | settled, cached, failed |
prompt_tokens | integer | |
completion_tokens | integer | |
total_tokens | integer | |
billed_cost_usd | string | null | Null unless the request settled. |
provider_list_price_usd | string | null | Request-time maker/provider list-price comparison amount. |
paid_amount_usd | string | null | Customer amount paid; null unless the request settled. |
savings_usd | string | null | Customer-visible savings, always non-negative when present. |
route | string | null | Always null. Identified the supply route that served the request; withdrawn because it names our supplier. The key remains so existing clients keep a stable shape. |
serving_provider | string | null | Always null. Identified the serving provider; withdrawn for the same reason as `route`. |
retention | string | Recorded request-time retention policy; unknown for historical requests without evidence.zdr, standard, unknown |
effective_discount_percent | number | null | Effective discount against request-time list cost, including optimizations; null without comparable settled costs. |
pricing_basis | string | null | |
pricing_snapshot | object | null | Immutable customer and maker-list rates resolved at admission. |
pricing_version | string | null | |
customer_price_ceiling_usd | string | null | |
maker_list_ceiling_usd | string | null | |
requested_reasoning_effort | string | null | |
effective_reasoning_effort | string | null | |
time_to_response_headers_ms | integer | null | |
model_time_to_response_headers_ms | integer | null | |
time_to_first_visible_output_ms | integer | null | Excludes hidden reasoning-only deltas. |
model_time_to_first_visible_output_ms | integer | null | |
routing_overhead_ms | integer | null | |
provider_attempt_count | integer | null | |
cache_reporting_state | string | null | hit, zero, unknown, not_applicable, null |
currencyrequired | string | USD |
total_latency_ms | integer | null | |
created_atrequired | string (date-time) | |
cache_read_input_tokens | integer | null | Not recorded yet. |
cache_write_input_tokens | integer | null | Not recorded yet. |
image_output_tokens | integer | null | Not recorded yet. |
time_to_first_token_ms | integer | null | Not recorded yet. |
model_latency_ms | integer | null | Not recorded yet. |
model_time_to_first_token_ms | integer | null | Not recorded yet. |
generation_duration_ms | integer | null | Not recorded yet. |
output_tokens_per_second | string | null | Not recorded yet. |
completed_at | string | null | Not recorded yet. |
DocSectionList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
queryrequired | string | |
datarequired | object[] |
PricingChangeList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
pricing_versionrequired | string | |
pricing_checked_at | string (date-time) | |
pricing_updated_at | string (date-time) | |
datarequired | object[] | |
has_morerequired | boolean | |
next_cursor | string |
PricingChangeRates
Customer-facing rates on one side of a change. Null means the rate was not quoted at that point, which is different from zero.
| Field | Type | Notes |
|---|---|---|
input_per_million | string | |
output_per_million | string | |
media_unit_price | string |
UsageDaily
| Field | Type | Notes |
|---|---|---|
objectrequired | string | usage.daily |
scoperequired | string | workspace |
currencyrequired | string | USD |
start_at | string (date-time) | |
end_at | string (date-time) | |
timezone_offset_minutes | integer | |
total_requests | integer | |
settled_requests | integer | |
spend_usdrequired | string | |
prompt_tokensrequired | integer | Settled prompt tokens. Already includes any tokens served from the prompt cache. |
cached_tokensrequired | integer | The share of prompt_tokens the upstream served from its prompt cache. |
cache_reported_request_countrequired | integer | Settled requests whose upstream reported cache usage at all. Compare with settled_requests to see how much of the window cache_hit_pct speaks for. |
cache_hit_pctrequired | number | null | Percent of prompt tokens served from cache, over the cache-reporting requests only. Null when no upstream reported cache usage — an unknown rate, which is not the same as a reported 0%. |
daily_spendrequired | object[] |
FeedbackRequest
| Field | Type | Notes |
|---|---|---|
request_idrequired | string (uuid) | |
scorerequired | integer | 1–5 |
comment | string | null |
FeedbackResponse
| Field | Type | Notes |
|---|---|---|
okrequired | boolean |
Account
| Field | Type | Notes |
|---|---|---|
objectrequired | string | account |
email | string | null | |
workspace_name | string | null | Null for a personal account. |
role | string | null | |
funded_by_owner | boolean | True when this member's usage is paid from the workspace owner's wallet. |
active_key_countrequired | integer | |
last_key_use_at | string | null | |
auto_recharge_enabled | boolean | |
enabled_technique_countrequired | integer |
SecurityStrikeRequest
| Field | Type | Notes |
|---|---|---|
toolrequired | string | The MCP tool that was called.length 0–80 |
kindrequired | string | What was refused. `injection`, `escalation` and `policy` are refusals the MCP server issued itself and each count as a strike; `unauthorized` (401) and `forbidden` (403) are API denials and count once per distinct `detail`.injection, escalation, policy, unauthorized, forbidden |
detailrequired | string | A short stable code for the reason — never the offending text.length 0–200 |
SecurityStanding
| Field | Type | Notes |
|---|---|---|
objectrequired | string | security.standing |
tierrequired | string | clear, warn, blocked |
strikesrequired | integer | Distinct strikes in the current window. This is what the tiers compare against. |
attemptsrequired | integer | Every denied call in the window, duplicates included. |
remainingrequired | integer | Strikes left before the block. 0 while blocked. |
warn_afterrequired | integer | |
block_afterrequired | integer | The daily limit. |
window_hoursrequired | integer | |
blocked_untilrequired | string | null | When a timed block lifts. Null when not blocked, and null when the block is permanent — see `permanent`. |
permanentrequired | boolean | True for a block with no expiry: the daily limit was reached again within the repeat window of an earlier block. Only an admin lifts it. |
prior_blocksrequired | integer | Earlier blocks on record that ran their course. One or more means the next block is permanent. A block an admin lifted does not count. |
ban_idrequired | string | null | |
suspension_idrequired | string | null | |
report_urlrequired | string (uri) | Where to appeal. |
reportedrequired | boolean | True when this call filed the automatic support report for the account. |
AccountBalance
| Field | Type | Notes |
|---|---|---|
objectrequired | string | account.balance |
currencyrequired | string | USD |
balance_usdrequired | number | |
available_usdrequired | number | Balance minus what is held against requests in flight. This, not balance_usd, is what can be spent right now. |
reserved_usdrequired | number | |
auto_recharge_enabled | boolean | |
threshold_usd | number | null | |
recharge_amount_usd | number | null | |
card | string | null | |
workspace_name | string | null | |
funded_by_owner | boolean |
AccountUsage
Rolled up over a window. Distinct from /v1/usage/daily, which is the per-day series.
| Field | Type | Notes |
|---|---|---|
objectrequired | string | account.usage |
currencyrequired | string | USD |
daysrequired | integer | |
request_countrequired | integer | |
billed_usdrequired | number | |
saved_usdrequired | number | List price minus what was billed. |
list_usd | number | |
savings_percent | number | null | |
top_models | object[] |
AccountSavings
| Field | Type | Notes |
|---|---|---|
objectrequired | string | account.savings |
currencyrequired | string | USD |
windowsrequired | object[] | One entry each for the last 24 hours, 7 days and 30 days. |
experimentsrequired | ExperimentSummary[] | |
techniquesrequired | Technique[] |
ExperimentSummary
| Field | Type | Notes |
|---|---|---|
idrequired | string (uuid) | |
namerequired | string | |
statusrequired | string | |
dimension | string | What the experiment varies: prompt, model or technique. |
request_countrequired | integer | |
avg_cost_usd | number | |
avg_saved_usd | number | |
feedback_avg | number | null | |
feedback_count | integer |
ExperimentList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
datarequired | ExperimentSummary[] |
Experiment
| Field | Type | Notes |
|---|---|---|
objectrequired | string | experiment |
idrequired | string (uuid) | |
namerequired | string | |
statusrequired | string | |
dimension | string | |
created_at | string | null | |
request_count | integer | |
avg_cost_usd | number | |
avg_saved_usd | number | |
feedback_avg | number | null | |
feedback_count | integer | |
variantsrequired | object[] |
Technique
| Field | Type | Notes |
|---|---|---|
idrequired | string | |
namerequired | string | |
category | string | |
tier | integer | 1 deterministic, 2 statistical, 3 model-touching. |
status | string | enabled, preview, deprecated |
available | boolean | Whether PATCH will accept it. False for preview and deprecated entries. |
enabledrequired | boolean | What the proxy will actually do for this account. Every implemented technique is off by default, so this is false until the account opts in. |
explicitly_enabled | boolean | null | The stored choice, or null when the account has never set one. |
savings_summary | string | |
savings_min_pct | number | null | |
savings_max_pct | number | null | |
quality_risk | string | null |
TechniqueList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
datarequired | Technique[] |
TechniqueUpdateRequest
| Field | Type | Notes |
|---|---|---|
enabledrequired | boolean |
TechniqueUpdateResponse
| Field | Type | Notes |
|---|---|---|
objectrequired | string | technique |
idrequired | string | |
name | string | |
enabledrequired | boolean | |
changedrequired | boolean | False when it was already in the requested state. |
ApiKeySummary
| Field | Type | Notes |
|---|---|---|
idrequired | string (uuid) | |
namerequired | string | |
prefixrequired | string | The first 18 characters. The rest is never recoverable. |
scopesrequired | string[] | |
organization_id | string | null | |
created_at | string | null | |
last_used_at | string | null | |
expires_at | string | null | |
revoked_at | string | null |
ApiKeyList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
datarequired | ApiKeySummary[] |
ApiKeyCreateRequest
| Field | Type | Notes |
|---|---|---|
name | string | length 0–64 |
organization_id | string | null | |
scopes | string[] | Defaults to inference and usage:read. |
allowed_models | string[] | |
allowed_ip_cidrs | string[] | |
expires_at | string | null | |
rate_limit_per_minute | integer | null | |
daily_request_limit | integer | null | |
concurrency_limit | integer | null | |
monthly_spend_limit_usd | number | null |
ApiKeyCreated
| Field | Type | Notes |
|---|---|---|
objectrequired | string | api_key |
id | string | null | |
namerequired | string | |
prefixrequired | string | |
scopes | string[] | |
keyrequired | string | The plaintext key. Also available to its owner through the dashboard's copy action. |
ApiKeyRevoked
| Field | Type | Notes |
|---|---|---|
objectrequired | string | api_key.revoked |
idrequired | string (uuid) | |
name | string | |
prefix | string |
Channel
| Field | Type | Notes |
|---|---|---|
object | string | channel |
idrequired | string (uuid) | |
platformrequired | string | |
workspace_name | string | null | |
integration_active | boolean | |
eventsrequired | string[] | |
report_frequency | string | null | daily, weekly, monthly, off, null |
report_hour | integer | null | Hour of day, UTC. |
ChannelList
| Field | Type | Notes |
|---|---|---|
objectrequired | string | list |
datarequired | Channel[] | |
available_eventsrequired | object[] | The valid ids for the `events` field on PATCH, with their labels. |
ChannelUpdateRequest
Both fields are optional; an absent one is left alone. `events: []` unsubscribes from everything, which is different from omitting the field.
| Field | Type | Notes |
|---|---|---|
report_frequency | string | daily, weekly, monthly, off |
events | string[] |
ChannelReportResponse
| Field | Type | Notes |
|---|---|---|
objectrequired | string | channel.report |
sentrequired | boolean | False with a `message` when there was no activity in the window — the request succeeded, there was simply nothing to send. |
cadence | string | |
window_label | string | |
message | string |
ModelSupply
| Field | Type | Notes |
|---|---|---|
object | string | model.supply |
model | string | |
min_discount_percent | number | null | |
zdr | boolean | |
list_input_per_million | string | null | |
list_output_per_million | string | null | |
max_input_per_million | string | null | |
max_output_per_million | string | null | |
supply_buffer_percent | number | |
candidate_count | integer | |
candidates | string[] | Opaque per-response aliases: `primary` for the marketplace, `network_a`, `network_b`, ... for the others. Suppliers are never named. |
primary_market_offers | integer | |
primary_market_min_discount_percent | integer | |
note | string |
ModelComparison
| Field | Type | Notes |
|---|---|---|
objectrequired | string | model.comparison |
currencyrequired | string | USD |
prompt_tokens | integer | |
completion_tokens | integer | |
requests | integer | |
datarequired | object[] | Cheapest first. Ids that could not be resolved sort last with found:false. |
TopupRequest
| Field | Type | Notes |
|---|---|---|
amount_usdrequired | number | 5–1000 |
TopupResponse
Creates a Stripe Checkout session and returns its link. Nothing is charged here — the customer completes the payment on Stripe's own page.
| Field | Type | Notes |
|---|---|---|
objectrequired | string | billing.topup |
amount_usdrequired | number | |
checkout_urlrequired | string (uri) | |
session_id | string | |
min_usd | number | |
max_usd | number |