Every endpoint, generated from the same OpenAPI description the API publishes at /openapi.json, so it cannot list an endpoint the API lacks or miss one it has. Load that file into Postman, Insomnia or any OpenAPI code generator to build a client.
92 endpoints in 17 groups.
Inference
Model requests.
Create a chat completion
OpenAI-compatible. Routes to an endpoint your guardrails and preferences allow, dispatches on your own provider credential, and fails over to the next candidate before the first byte ships -- walking models[] to exhaustion.
With stream: true the response is server-sent events: one data: line per ChatCompletionChunk, SSE comments (lines starting with :) as keepalives, a final chunk carrying usage, then data: [DONE].
Authentication
Inference key (ar-v1-…) · Dashboard session
Parameters
- X-AgentRouter-Metadata enum · header
enabledaddsagentrouter_metadata: on the final chunk when streaming, and besideerroron an error once routing has begun.X-Metadatais accepted too.- X-Session-Id string · header
A sticky-routing key, used when the body has no
session_id.- X-Anthropic-Beta string · header
Forwarded to Anthropic as
anthropic-beta.- HTTP-Referer string · header
Your app's URL, for attribution. The app listing keeps its path; each request row keeps only the scheme and host.
- X-AgentsRouter-Agent string · header
The agent this request is for: 1 to 64 letters, digits,
.,_,:or-, starting with a letter or digit. Recorded on the request, and bound by that agent's budgets (PUT /v1/agents/{agent}/budgets/{interval}) across every key it uses. A malformed value is a 400 before anything is spent.- X-Title string · header
Your app's name.
X-App-TitleandX-OpenRouter-Titleare accepted too.- X-App-Visibility enum · header
hiddenkeeps the app out of public listings. Read on the app's first request only.- X-App-Categories string · header
Up to two comma-separated categories.
Request body
- model string
A catalog id,
author/slug, optionally with a variant (:free,:nitro,:floor,:exacto), or a~author/familyalias, which resolves to theauthor/family-latestrow when the catalog publishes one and otherwise resolves to nothing -- it never picks a model for you by guessing at the name. An id listed in/v1/modelsalways means that listing: some free tiers are catalog rows of their own, namedauthor/slug:free, and a suffix is only split off the id when no such row can serve the request. It always applies as a variant either way.- models string[]
A fallback chain, tried in order. At most three are attempted.
- messages ChatMessage[]
- prompt string
Legacy: sent as a single user message when
messagesis absent.- stream boolean
- Default: false
- max_tokens integer
- max_completion_tokens integer
- temperature number
- top_p number
- top_k integer
- stop string | string[]
- seed integer
- tools object[]
- tool_choice any
none,auto,required, or{"type": "function", "function": {"name": …}}.- response_format object
- reasoning object
{ effort: low|medium|high }or{ max_tokens: n }. On Anthropic this becomes extended thinking with that budget (floor 1024) and the thinking text is returned asmessage.reasoning(ordelta.reasoningwhen streaming);temperature,top_pandtop_kare dropped there because the provider refuses them alongside thinking.- provider ProviderPreferences
Routing preferences (§6.2). Preferences reorder; constraints reject. Guardrails outrank everything here.
- session_id string
Keeps a conversation on one endpoint so its prompt cache stays warm (§6.6).
- prompt_cache_key string
Used as the sticky-routing key when there is no
session_id.- routing_stability enum
Defaults to
stickywhen the request has a pin key,adaptiveotherwise (§17.2).One of: adaptive, sticky, pinned
Responses
- id stringrequired
gen-…. Pass it toGET /v1/generationfor the full record.- object anyrequired
- created integerrequired
Unix seconds.
- model stringrequired
The model that served, which differs from the one requested when a fallback fired.
- provider string
- choices object[]required
- usage Usagerequired
- agentrouter_metadata RouterMetadata
Why this model, this provider, this price (§7.5). Present only when
X-AgentRouter-Metadata: enabledwas sent.
Preview how a request would route
Answers "why would I get that model, from that provider?" before the money is spent. Router metadata answers it afterwards; this runs the same gates, the same filters and the same ranking against a request that is never dispatched.
It mirrors POST /v1/chat/completions gate for gate and in order: the same auth, the same budget checks in the same precedence, the same content filter applied before routing, the same per-model candidate load, filter and rank, the same fallback depth, and the same sticky hoist.
It has no side effects. No ledger hold, no run reservation, no request row, no sticky pin written, no provider contacted. Rate limited in its own bucket, so debugging a routing problem never eats the quota needed to fix it.
Read ordering before trusting cascade as a prediction: the default ranking is a weighted random draw, and sampled means a real request draws again.
Authentication
Inference key (ar-v1-…) · Dashboard session
Parameters
- X-Session-Id string · header
A sticky-routing key, used when the body has no
session_id.
Request body
- model string
The model to route, exactly as
/v1/chat/completionstakes it --:free,:nitro,:floor,:exactosuffixes and~author/family-latestaliases included.- models string[]
A fallback chain, previewed in order. Walked to the same depth a real request would walk it.
- provider ProviderPreferences
Routing preferences (§6.2). Preferences reorder; constraints reject. Guardrails outrank everything here.
- tools object[]
Only the COUNT matters here: a non-empty list makes
toolsa required parameter, which is a hard filter underrequire_parameters.- messages ChatMessage[]
Optional. Supplied only so content filters and the sticky prefix hash can be evaluated; nothing is sent to a provider. Omit them and
content_filtercomes back null rather than a fabricatedallow.- session_id string
Sticky-routing key, as on the chat route.
- prompt_cache_key string
- routing_stability enum
- One of: adaptive, sticky, pinned
- routing_seed string
Seeds the weighted draw so a preview is reproducible and quotable in a bug report. Named
routing_seed, notseed: the latter is OpenAI's sampling seed on the chat route, and one name for two knobs on sibling endpoints is a trap.
Responses
- requested stringrequired
- strategy string
direct,fallbackfor amodels[]chain, orlatestfor a~alias.- would_dispatch booleanrequired
Whether a real request with this body would reach a provider at all.
- limit_warning string | null
Set when the key is at or past a SOFT ceiling: the request would be served, with this sentence in its
x-agentsrouter-limit-warningheader.- refusal object | null
Why not, in the order the pipeline refuses: a budget binds before a filter runs, and both before routing is consulted. Null when
would_dispatchis true.- ordering enum
Whether
cascadeis the order or one draw from it.§8.9.1's default ranking is a weighted random shuffle, deliberately: a deterministic cheapest-first router starves every provider but one. So
sampledmeans the real request draws again and may order the platform attempts differently — reproduce this draw with the samerouting_seed.deterministicmeans the order is fixed (an explicitsort, a:floor/:nitrovariant, or too few platform attempts to shuffle) and a real request will match it.One of: deterministic, sampled- routing_seed string
The seed this preview actually used, echoed so an unseeded call is still reproducible.
- winner RoutePreviewCandidate | null
- cascade RoutePreviewCandidate[]required
The endpoints a real request would try, in order, after the sticky hoist and cut to the same fallback depth.
- beyond_fallback_depth integer
Endpoints that survived every filter but sit past the fallback depth: eligible, and still unreachable.
- endpoints object
- refused object[]
One entry per excluded endpoint, carrying the FIRST constraint that removed it.
unsatisfied_filterssays which constraints emptied the set; this says which endpoints each one cost you.- unsatisfied_filters string[]
The same strings §7.7's 404 would carry.
- unresolved_models string[]
Slugs in the chain that named no model we have — a typo, or a model since withdrawn.
- guardrails object
- content_filter object | null
Null when no
messageswere supplied.labelsname the detectors that matched; the matched text never travels.- sticky object
Catalog
Models, their endpoints and providers. Public.
List models
Public. Rate limited per client address: 120 a minute, 20,000 a day.
Authentication
None: this endpoint is public.
Parameters
- limit integer · query
Page size.
- offset integer · query
Rows to skip.
- q string · query
A case-insensitive substring of the name or id.
- model_authors string · query
Comma-separated authors, e.g.
anthropic,openai.- context integer · query
Minimum context length, in tokens.
- sort enum · query
Anything else sorts by id.
Responses
- id stringrequired
author/slug.- canonical_slug string
- name stringrequired
- created integer | null
Unix seconds.
- description string | null
- context_length integer | null
- architecture object | null
Input and output modalities.
- supported_parameters string[] | null
- default_parameters object | null
- resale_permitted enum
- One of: yes, no, via_reseller, unknown
- byok_only boolean
- is_free boolean
- deprecation_date string | null
- pricing object
The cheapest endpoint's price. Present on the list only.
Get a model
Public and rate limited, as the list is. pricing is absent here; the endpoints route has every endpoint's prices.
Authentication
None: this endpoint is public.
Parameters
- author string · pathrequired
e.g.
anthropic.- slug string · pathrequired
e.g.
claude-sonnet-5.
Responses
- id stringrequired
author/slug.- canonical_slug string
- name stringrequired
- created integer | null
Unix seconds.
- description string | null
- context_length integer | null
- architecture object | null
Input and output modalities.
- supported_parameters string[] | null
- default_parameters object | null
- resale_permitted enum
- One of: yes, no, via_reseller, unknown
- byok_only boolean
- is_free boolean
- deprecation_date string | null
- pricing object
The cheapest endpoint's price. Present on the list only.
List a model's endpoints
Public and rate limited. Every provider serving the model, with its price, measured uptime and latency, and tool-call reliability.
Authentication
None: this endpoint is public.
Parameters
- author string · pathrequired
e.g.
anthropic.- slug string · pathrequired
e.g.
claude-sonnet-5.
Responses
List providers
Public and rate limited.
Authentication
None: this endpoint is public.
Responses
- slug stringrequired
- name stringrequired
- hq_country string | null
- datacenters string[] | null
- privacy_policy_url string | null
- tos_url string | null
- status_page_url string | null
Keys
API keys.
Inspect the calling key
For an inference key: its limit, what remains of it, and what it has spent plus what its in-flight requests have reserved.
Authentication
Inference key (ar-v1-…)
Responses
- label string | null
- limit number | null
The key's spend limit in USD, or null for none.
- limit_remaining number | null
Ceiling minus usage, measured exactly as the spend gate measures it: within the reset window, including spend on your own provider credential only when include_byok_in_limit is set, plus the worst-case reservation of every request on this key still in flight -- released or replaced by the actual amount at settlement, so this can go down. Not a billing total -- see /v1/credits for money.
- usage number
Spend counted against this key ceiling, measured exactly as the spend gate measures it: within the reset window, including spend on your own provider credential only when include_byok_in_limit is set, plus the worst-case reservation of every request on this key still in flight -- released or replaced by the actual amount at settlement, so this can go down. Not a billing total -- see /v1/credits for money.
- limit_reset string | null
- limit_mode enum
hard(the default) refuses a request once the key is at or past its ceiling, with 403budget_exceeded.softserves it and adds anx-agentsrouter-limit-warningheader carrying the same sentence.One of: hard, soft- include_byok_in_limit boolean
Count spend made on your own provider credential toward this ceiling, at IMPUTED LIST PRICE -- what the call would have cost on platform capacity, not the platform fee charged. Defaults to false, and while every model is BYOK-only that means the ceiling counts nothing and cannot bind.
- is_free_tier boolean
List keys
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- include_disabled boolean · query
Include revoked keys.
Responses
- hash string
Identifies the key in
DELETE /v1/keys/{hash}. Not the key itself.- prefix string
- name string | null
- label string | null
- class enum
- One of: inference, management
- disabled boolean
- limit number | null
USD.
- limit_nanodollars string | null
The same limit, raw.
- limit_reset string | null
- limit_mode enum
hard(the default) refuses a request once the key is at or past its ceiling, with 403budget_exceeded.softserves it and adds anx-agentsrouter-limit-warningheader carrying the same sentence.One of: hard, soft- include_byok_in_limit boolean
- workspace_id string | null
The workspace (client) the key belongs to.
- usage number | null
USD counted against the ceiling in its current window, measured exactly as the spend gate measures it (see KeyInfo.usage). Null for a key with no ceiling, or a revoked one.
- limit_remaining number | null
Ceiling minus usage. Negative when a soft ceiling has been passed. Null when there is no ceiling.
- limit_resets_at string | null
When the current window ends. Null for a lifetime ceiling or none.
- created_at string
- updated_at string
- expires_at string | null
- external_user string | null
Create a key
The plaintext key is in this response and never again: only a salted hash is stored.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- name string
- limit number
A spend limit in USD. Omit for none.
- limit_reset string | null
The window the ceiling covers, in UTC calendar terms. Null means lifetime: the ceiling never resets.
One of: daily, weekly, monthly, lifetime, null- limit_mode enum
hard(the default) refuses a request once the key is at or past its ceiling, with 403budget_exceeded.softserves it and adds anx-agentsrouter-limit-warningheader carrying the same sentence.One of: hard, softDefault: "hard"- workspace_id string
Put the key in this workspace (client). Omit for the caller's own workspace. Another organisation's id is a 404.
- class enum
- One of: inference, managementDefault: "inference"
Responses
- key stringrequired
The key. Store it now.
- hash stringrequired
- name string | null
- class enumrequired
- One of: inference, management
Change a key's spend limit, or pause and resume it
Changes the ceiling, its window, its mode, or whether BYOK spend counts. Only these: a key's class, name and secret are fixed at creation. At least one field is required. The new ceiling applies at once on the instance serving this call and within the auth cache's 10-second TTL everywhere else.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- hash string · pathrequired
The key's
hash, from the list.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- limit number | null
The new ceiling in USD; null removes it.
- limit_reset string | null
The window the ceiling covers, in UTC calendar terms. Null means lifetime: the ceiling never resets.
One of: daily, weekly, monthly, lifetime, null- limit_mode enum
hard(the default) refuses a request once the key is at or past its ceiling, with 403budget_exceeded.softserves it and adds anx-agentsrouter-limit-warningheader carrying the same sentence.One of: hard, soft- include_byok_in_limit boolean
- workspace_id string
Move the key to this workspace of the same organisation.
- paused boolean
false resumes a key paused by a runaway flag or by hand; true pauses it by hand. A paused key answers 403
key_paused.
Responses
- hash stringrequired
- name string | null
- class enum
- One of: inference, management
- limit number | null
USD.
- limit_reset string | null
- limit_mode enum
- One of: hard, soft
- include_byok_in_limit boolean
- paused boolean
- paused_reason enum
- One of: runaway, manual, null
Revoke a key
Disables the key and ends every dashboard session it created.
Propagation is bounded at 10 seconds (§17.4: "publish that TTL"). The instance serving this call stops accepting the key immediately; any other instance stops within the auth cache's TTL. That cache serves no stale window — past ten seconds the entry is refused and the caller waits on the database — so ten seconds is the real bound, not the point at which a refresh merely begins.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- hash string · pathrequired
The key's
hash, from the list.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- deleted anyrequired
Usage
What was requested, and what it cost.
List recent requests
Newest first, keyset-paginated. Cost is summed per row, over the window.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- limit integer · query
Page size.
- days integer · query
The window, ending now.
- cursor string · query
The
next_cursorof the previous page. Opaque; do not parse it.- model string · query
The model that served.
- provider string · query
A provider slug.
- workspace string · query
One client: a workspace id. A malformed id is a 400.
- agent string · query
One agent: the X-AgentsRouter-Agent value.
- status string · query
The request status, e.g.
complete.- byok boolean · query
BYOK requests only, or none.
- app string · query
An
app_id.
Responses
- id string
- created_at string
- requested_model string
- served_model string | null
Null until routing picks one; differs from
requested_modelwhen a fallback fired.- provider_slug string | null
- status string
- finish_reason string | null
Normalized to five values.
native_finish_reasoncarries the provider's own.One of: stop, length, tool_calls, content_filter, error, null- native_finish_reason string | null
- is_byok boolean
- is_cache_hit boolean
- cancelled boolean
- streamed boolean
- quantization string | null
- ttft_ms integer | null
- generation_ms integer | null
- routing_overhead_ms integer | null
Total time minus upstream provider time -- the latency this gateway added (§18). Null when nothing was dispatched, and on rows recorded before it was measured.
- error_code string | null
The provider's own code where a provider refused, or a
router.*reason code where this gateway is what failed -- a credential it could not open, a request it could not express. A stream that broke after it had committed is recorded on the upstream attempt, not here.- error_message string | null
The failure in English, for a developer. Where a provider refused, this names the provider, its HTTP status and its error code -- never the provider's own text, which can quote the prompt and is returned only in the response to the request itself. Where this gateway failed, its own sentence.
- total_cost number
US dollars.
- app_id string | null
- app_title string | null
- http_referer string | null
- workspace_id string | null
The client (workspace) of the key that made the request.
- agent string | null
The X-AgentsRouter-Agent the request named, if any.
Export a month of requests as CSV
One row per request in a UTC calendar month, for the account or one client (workspace). Columns: created_at, request_id, client, key, requested_model, served_model, provider, status, error_code, byok, prompt_tokens, completion_tokens, billed_usd (what this account was charged), list_price_usd (the tokens at catalogue list price: under BYOK, the number a client is re-billed on and the one budgets measure) and agent. Text cells that a spreadsheet would run as a formula are prefixed with a single quote. Capped at 200,000 rows, after which a # truncated line ends the file. At most 6 exports a minute per key.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- month string · query
YYYY-MM, UTC. Default: the current month.
- workspace string · query
One client: a workspace id. Another organisation's is a 404.
Responses
Get activity totals
The KPI cards (§14.9), with the prior period of equal length beside them and a daily series for the sparklines. Both periods are read in one pass, so they cannot disagree about where "now" was.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- days integer · query
The window, ending now. The prior period is the same length again.
- workspace string · query
One client: a workspace id. A malformed id is a 400.
Responses
- requests integer
- errors integer
Requests that ended with an error code. Counted zero on deployments older than the reason codes, where no code was recorded.
- byok_requests integer
- spend number
US dollars.
- tokens integer
Prompt plus completion.
cache_readandreasoningare subsets of those and are not added again.- prompt_tokens integer
- cached_tokens integer
Prompt tokens served from the provider's cache -- a subset of
prompt_tokens.- cache_hit_rate number | null
cached_tokens / prompt_tokens. Null when there were no prompt tokens, which is not the same as a rate of zero.- blended_per_million number | null
USD per million tokens, blended across every model and provider in the window. Null when there were no tokens.
List upstream provider requests
One row per dispatch to a provider, newest first and keyset-paginated. A request that failed over twice appears three times -- filter by request to see a single generation's attempts in order.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- limit integer · query
Page size.
- days integer · query
The window, ending now.
- cursor string · query
The
next_cursorof the previous page. Opaque; do not parse it.- request string · query
A generation id: every dispatch made for it.
- provider string · query
A provider slug.
- status enum · query
Whether the dispatch committed.
Responses
- id string
Opaque; the row's identity, not the request's.
- request_id string
The generation this dispatch was made for. Several rows share it when a fallback fired.
- created_at string
- attempt integer
1-indexed position in the cascade.
- model_id string
- provider_slug string
- endpoint_id string
- is_byok boolean
- status enum
Whether the dispatch committed. A stream that shipped bytes and then failed is
okwith anerror_message.One of: ok, error- http_status integer | null
The upstream status. Null when the dispatch never reached the provider.
- error_code string | null
The provider's own code where the provider answered, or a
router.*reason code where this gateway is what failed -- a credential it could not open, a request it could not express, a stream that broke after it had committed.- error_message string | null
As on the request: the provider, status and code where the provider refused; never its own text.
- duration_ms integer | null
Time inside the provider call. Null when nothing was dispatched.
- ttft_ms integer | null
List conversations
Generations grouped by session_id, most recently active first. Only requests that carried one are included.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- limit integer · query
Page size.
- days integer · query
The window, ending now.
- cursor string · query
The
next_cursorof the previous page. Opaque; do not parse it.
Responses
- session_id string
- generations integer
Requests in this conversation, within the window.
- errors integer
- started_at string
- last_seen_at string
- spend number
US dollars.
- tokens integer
- models string[]
Every model the conversation was served by. More than one means it switched mid-session.
- providers string[]
Get one request's record
Which endpoint served it, at which price version, and what each SKU cost -- enough to recompute the charge.
Not the content. Prompts and completions are stored only when your organisation has enabled input/output logging (§13.1), which is off by default and never retroactive; when it is on, the content is read from GET /v1/generation/{id}/content, not from here.
Authentication
Inference key (ar-v1-…)
Parameters
- id string · queryrequired
The
idof a chat completion.
Responses
- id string
- model string | null
The model that served.
- provider_name string | null
- endpoint_id string | null
- quantization string | null
- total_cost number
US dollars.
- finish_reason string | null
Normalized to five values.
native_finish_reasoncarries the provider's own.One of: stop, length, tool_calls, content_filter, error, null- native_finish_reason string | null
- streamed boolean
- cancelled boolean
- is_byok boolean
- latency integer | null
Time to first token, in milliseconds.
- generation_time integer | null
Milliseconds.
- price_version_ids integer[]
- usage_lines object[]
- app_id string | null
- app_title string | null
- http_referer string | null
Scheme and host only. The path, query string and fragment are never stored on a request, because that is where an app puts the user it is serving.
- user_agent string | null
- created_at string
Get one generation's stored prompt and completion
§13.1. Returns content only if your organisation had input/output logging enabled when the generation was made.
Stored encrypted (AES-256-GCM, data key wrapped by Cloud KMS) in a table separate from request metadata, under an AAD bound to your organisation — a credential ciphertext cannot be read here and content cannot be read from the credential path. Deleted automatically past your configured retention.
This is the only read path for stored content, and it is yours. §13.1 forbids using it for training or analytics, and there is no internal reader.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The generation id (
gen-…).- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- request_id stringrequired
- content objectrequired
The request messages, the completion, and any tool calls.
Credits
Balance and purchases.
Get the balance
Held credits are reserved by requests in flight and are shown apart from the available balance.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- total_credits number
US dollars.
- held_credits number
US dollars.
- available_credits number
US dollars.
- credit_line number
US dollars.
Get the purchase fee schedule
Public. While nothing a credit can buy exists (BYOK-only), purchasable is false and the fee is reported as 0.
Authentication
None: this endpoint is public.
Responses
- fee_bps integer
Basis points.
- fee_min number
US dollars.
- min_purchase number
US dollars.
- configured boolean
A payment processor is configured.
- purchasable boolean
A purchased balance could actually be spent.
List purchases
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- limit integer · query
Page size.
- cursor string · query
The
next_cursorof the previous page. Opaque; do not parse it.
Responses
- id string
- created_at string
- provider string
- status string
- gross number
US dollars.
- fee number
US dollars.
- net number
US dollars.
- tax_jurisdiction string | null
- has_document boolean
Get a purchase's invoice or receipt
Resolved from Stripe on demand; only the checkout session id is stored.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A purchase
id.
Responses
- kind enum
- One of: invoice, receipt
- url string
- pdf_url string | null
- number string | null
Start a credit purchase
Returns a Stripe Checkout URL. Refused with 409 while credits cannot be spent (BYOK-only, zero fee) -- checked before the body is read.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- amount numberrequired
USD.
Responses
- url string
- id string
- fee number
US dollars.
Receive a Stripe event
For Stripe, not for you. Credits on checkout.session.completed and checkout.session.async_payment_succeeded only when payment_status is paid, once per session; logs async_payment_failed; acknowledges everything else with 200.
Authentication
Stripe signature
Responses
- received anyrequired
BYOK
Your provider credentials. Required before anything routes.
List provider credentials
Keys are never returned, by this or any route -- only key_hint.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- provider_slug string
- name string | null
- key_hint string
The last characters of the key. The key itself is never returned.
- tier enum
- One of: prioritized, fallback
- priority integer
- fallback_policy enum
- One of: platform, none_for_models, none_for_provider
- model_filter object
- disabled boolean
- created_at string
- last_used_at string | null
Add a provider credential
Encrypted with a per-credential key before it is stored. Nothing routes until you have one for the provider that serves your model.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- provider stringrequired
A provider slug with an adapter, e.g.
anthropic.- api_key stringrequired
- name string
- tier enum
- One of: prioritized, fallback
- priority integer
- fallback_policy enum
- One of: platform, none_for_models, none_for_provider
- model_filter object
Responses
- id string
- provider_slug string
- name string | null
- key_hint string
The last characters of the key. The key itself is never returned.
- tier enum
- One of: prioritized, fallback
- priority integer
- fallback_policy enum
- One of: platform, none_for_models, none_for_provider
- model_filter object
- disabled boolean
- created_at string
- last_used_at string | null
Enable or disable a provider credential
Only disabled can change. To change the key, add a new credential and delete this one.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A credential
id.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- disabled booleanrequired
Responses
- id string
- disabled boolean
Delete a provider credential
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A credential
id.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- deleted anyrequired
Alerts
Usage alerts: where you are told a key is nearing its spend ceiling.
List usage-alert channels
Where the organisation is told that a key crossed a share of its spend ceiling. email_available says whether this deployment can send email. A webhook's signing secret is never returned here: only once, when the channel is created.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- kind enum
- One of: webhook, slack, email
- target string
- name string | null
- thresholds integer[]
- disabled boolean
- created_at string
Add a usage-alert channel
A key crossing any of thresholds (percent of its ceiling, default 50, 80 and 100), or an agent crossing them on one of its budgets (agent_limit.threshold), is announced once per threshold per ceiling window, on every channel that lists that threshold; a key that jumps several thresholds in one request is announced once, at the highest. A webhook target must be a public https URL on the default port; a slack target must be a https://hooks.slack.com/... incoming-webhook URL; email needs the deployment to be configured for it. Webhook deliveries are JSON, signed in x-agentsrouter-signature: t=<unix>,v1=<hex>, where v1 is HMAC-SHA256 of <t>.<raw body> with the channel's signing_secret. At most 20 channels per organisation.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- kind enumrequired
- One of: webhook, slack, email
- target stringrequired
An https URL, or an email address for
email.- name string
- thresholds integer[]
Whole percentages from 1 to 100. Default [50, 80, 100].
Responses
- id string
- kind enum
- One of: webhook, slack, email
- target string
- name string | null
- thresholds integer[]
- disabled boolean
- created_at string
Remove a usage-alert channel
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The channel id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- deleted anyrequired
Send a test alert
Delivers a test event now and reports the outcome, so a wrong URL or a receiver that rejects the payload shows at once. The attempt is recorded in the delivery log.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The channel id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- status enumrequired
- One of: sent, failed, skipped
- http_status integer | null
What the receiver answered, when it answered.
- error string | null
Why it failed, in our words. The receiver's response body is never read.
What a runaway flag does
alert: every flag is sent to the alert channels and nothing else happens (the default). pause: a flagged KEY is also paused -- it answers 403 key_paused until resumed with PATCH /v1/keys/{hash} {"paused": false}. An agent flag is never a pause: a tag is not a credential.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- runaway_action enumrequired
- One of: alert, pause
Choose what a runaway flag does
Requires config:write (Developer or above): this decides whether a heuristic may stop production traffic.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- runaway_action enumrequired
- One of: alert, pause
Responses
- runaway_action enumrequired
- One of: alert, pause
Runaway-spend flags
A key or an agent (X-AgentsRouter-Agent) flagged because its last 15 minutes were far above its own previous 24 hours: spend at least 3x its usual 15 minutes and at least $5, or requests at least 5x usual and at least 300. Checked every five minutes; a subject is flagged at most once an hour, and each flag is sent to every alert channel as a spend.runaway event. With runaway_action = pause (see /v1/alerts/settings) a flagged key is also paused; action says which happened. The last 30 days, at most 100.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- subject_kind enum
- One of: key, agent
- subject string
The agent tag, or the first 12 characters of the key hash.
- key_name string | null
- key_hash string | null
The full hash, for PATCH /v1/keys/{hash}; null for an agent.
- key_paused boolean
Whether the key is paused right now (by this flag, a later one, or by hand).
- action enum
What the sweep did with this flag.
One of: alert, paused- kind enum
- One of: spend, rate
- window_start string
- window_end string
- spend number
US dollars.
- usual_spend number
US dollars.
- requests integer
- usual_requests number
- created_at string
Recent alert deliveries
The last 50 delivery attempts, newest first, each with its outcome. Kept for 90 days.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- channel_id string | null
Null once the channel has been removed.
- channel_name string | null
- channel_kind string | null
- event enum
- One of: key_limit.threshold, agent_limit.threshold, spend.runaway, test
- threshold integer | null
- status enum
- One of: sent, failed, skipped
- http_status integer | null
- error string | null
- key_name string | null
- key_hash_prefix string | null
- agent_tag string | null
For an agent-budget alert: the X-AgentsRouter-Agent value.
- created_at string
Workspaces
One per client: separate keys, budgets and spend under one account.
List workspaces
One workspace per client is the intended use: each has its own keys, budgets and spend, under one account and one balance. spend_this_month is measured the way a workspace budget is -- settled spend in the current UTC calendar month plus requests in flight, BYOK spend at list price included.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- name string
- slug string
- created_at string
- active_keys integer
- spend_this_month number
USD, current UTC calendar month, measured as a workspace budget measures it.
- budgets object[]
- is_current boolean
Whether this is the calling key's own workspace.
Create a workspace
At most 200 per organisation. Put keys in it with workspace_id on POST /v1/keys, or move one with PATCH /v1/keys/{hash}.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- name stringrequired
Up to 80 characters, e.g. the client's name.
Responses
- id string
- name string
- slug string
- created_at string
- active_keys integer
- spend_this_month number
USD, current UTC calendar month, measured as a workspace budget measures it.
- budgets object[]
- is_current boolean
Whether this is the calling key's own workspace.
Rename a workspace
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The workspace id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- name stringrequired
Responses
- id string
- name string
- slug string
- created_at string
- active_keys integer
- spend_this_month number
USD, current UTC calendar month, measured as a workspace budget measures it.
- budgets object[]
- is_current boolean
Whether this is the calling key's own workspace.
Remove a workspace
Refused with 409 while the workspace has an active key, and for the organisation's last workspace. Revoked keys keep their history and lose the link; provider credentials are never removed with a workspace.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The workspace id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- deleted anyrequired
List a workspace's budgets
An unknown workspace is an empty list, not a 404.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A workspace id.
Responses
- interval enum
- One of: daily, weekly, monthly, lifetime
- limit_nanodollars string
Nanodollars (1e-9 USD), an integer as a string.
- include_byok boolean
Count spend made on your own provider credential toward this ceiling, at IMPUTED LIST PRICE -- what the call would have cost on platform capacity, not the platform fee charged. Defaults to false, and while every model is BYOK-only that means the ceiling counts nothing and cannot bind.
Set a workspace budget
Budgets must shrink as the interval narrows: a daily budget above the weekly one is refused. Each interval is its own ceiling; they are never summed.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A workspace id.
- interval enum · pathrequired
The budget's period.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- limit_usd numberrequired
- include_byok boolean
Responses
- workspace_id string
- interval string
- limit_usd number
US dollars.
Delete a workspace budget
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A workspace id.
- interval string · pathrequired
The budget's period.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- deleted anyrequired
Status
Measured service status.
Measured uptime, last 90 days
From an external probe, not from traffic: a Cloud Monitoring uptime check requests /health (which queries the database) every minute from four regions. One entry per UTC day, oldest first. A day with fewer than 60 probes is uptime: null -- unmeasured, never counted as up. overall is over measured days, weighted by probes, and null when none is measured. Public, limited per client address, cached for a minute.
Authentication
None: this endpoint is public.
Responses
- days object[]
- overall number | null
0 to 1, over measured days.
- measured_days integer
Reports
White-label client reports: the agency's branding, and a client's month as numbers.
Report branding
The name, logo and footer printed on client reports in place of ours. Any role may read it.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- org_name string
The organisation's own name; the fallback when brand_name is unset.
- brand_name string | null
- brand_logo string | null
A PNG or JPEG data URI.
- brand_footer string | null
Set report branding
Owner or Developer. Every field is optional; an absent or empty one clears it. The logo is a PNG or JPEG data URI under 150 KB, checked by its bytes: nothing is ever fetched from a URL, and SVG is refused.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- brand_name string | null
Up to 80 characters.
- brand_logo string | null
data:image/png;base64,...ordata:image/jpeg;base64,..., under 150 KB.- brand_footer string | null
Up to 200 characters, e.g. a contact line.
Responses
- org_name string
The organisation's own name; the fallback when brand_name is unset.
- brand_name string | null
- brand_logo string | null
A PNG or JPEG data URI.
- brand_footer string | null
A client's month, as a report
Totals, by model, by agent and by day for one workspace in a UTC calendar month, with the branding to print it under. Amounts are list price -- what the tokens were worth, the number a client is re-billed on and the one budgets measure -- and the same measurement as the CSV export. A usage report, not an invoice: no tax, due date or markup.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The workspace id.
- month string · query
YYYY-MM, UTC. Default: the current month.
Responses
- workspace object
- month string
- period object
- branding Branding
- totals ReportLine
- by_model ReportLine[]
- by_agent ReportLine[]
- by_day ReportLine[]
- generated_at string
Members
Team seats. Roles: Owner (everything, including members), Developer (keys, provider keys, limits, workspaces, alerts, agents; reads billing), Finance (usage, exports, credits and checkout; changes nothing else). A management key with no person behind it has full power. Every management route shares one rate limit per key: 300 requests a minute, 20,000 a day (429 past it).
List members
Everyone with an active seat in the organisation, owners first, and the caller's own role. Any role may read this.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- user_id string
- role enum
owner = Owner, member = Developer, billing = Finance. What each may do: see the Members tag.
One of: owner, admin, member, billing, readonly- role_name string
- joined_at string
- name string | null
- email string | null
- avatar_url string | null
- provider string | null
- is_you boolean
Change a member's role
Owners only. The organisation's last owner cannot be demoted (409).
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- userId string · pathrequired
The member's user id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- role enumrequired
- One of: owner, member, billing
Responses
- user_id string
- role string
Remove a member
Owners only. The seat is deactivated and the person's dashboard key in this organisation is revoked, ending their sessions here at once; their other organisations are untouched. The last owner cannot be removed (409).
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- userId string · pathrequired
The member's user id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- removed boolean
Open invitations
Owners only. Invitations not yet accepted, revoked or expired. Links are not listed: only their hashes are kept.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- role string
- created_at string
- expires_at string
- created_by_name string | null
Invite someone
Owners only. Returns a link, in this response and never again: single use, valid seven days, revocable. The invitee opens it, signs in, and accepts. At most 50 open invitations.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- role enumrequired
- One of: owner, member, billing
Responses
- id string
- role string
- created_at string
- expires_at string
- url string
The invitation link. Store or send it now.
Revoke an invitation
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
The invitation id.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- revoked boolean
What an invitation is for
Public, limited per address. The token travels in the body to stay out of access logs. An unknown, used, revoked or expired token all answer the same 404.
Authentication
None: this endpoint is public.
Request body
- token stringrequired
Responses
- org_name string
- role string
- role_name string
- expires_at string
Accept an invitation
Requires a signed-in PERSON (a dashboard session); an API key has no seat and gets 403. Takes the seat, and replaces the session with one in the inviting organisation (Set-Cookie).
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- token stringrequired
Responses
- org_id string
Agents
Agents named in X-AgentsRouter-Agent: their spend, and budgets that bind across every key they use.
List agents
Every agent named in X-AgentsRouter-Agent in the last 31 days, plus any with a budget but no traffic yet: requests and spend this UTC month (list price included, measured as an agent budget measures it) and budgets. Newest first; at most 500.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- agent string
- last_seen string | null
- requests_this_month integer
- spend_this_month number
US dollars.
- budgets object[]
Set an agent budget
A hard ceiling on one agent's spend in a window, across every key it uses: a request naming the agent is refused with 403 budget_exceeded once the agent is at or past it. Narrower windows must have smaller caps. BYOK spend counts at list price by default.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- agent string · pathrequired
The X-AgentsRouter-Agent value.
- interval string · pathrequired
daily,weekly,monthlyorlifetime.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- limit_usd numberrequired
- include_byok boolean
- Default: true
- mode enum
hardrefuses at the ceiling (403budget_exceeded);softserves, adds the sentence tox-agentsrouter-limit-warning, and still alerts.One of: hard, softDefault: "hard"- workspace_id string | null
Scope the budget to this client workspace: it binds only requests from that workspace's keys. Omitted or null: the whole organisation. Both may exist for one agent and interval.
Responses
- agent string
- interval string
- limit_usd number
- include_byok boolean
- mode enum
- One of: hard, soft
- workspace_id string | null
Remove an agent budget
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- agent string · pathrequired
The X-AgentsRouter-Agent value.
- interval string · pathrequired
The window.
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.- workspace_id string · query
Remove the budget scoped to this client workspace. Absent: the organisation-wide one.
Responses
- deleted anyrequired
Guardrails
Policy: allowlists, budgets, privacy and content filters.
Get input/output logging settings
§13.1. An organisation that has never configured this gets the defaults: off, 90-day retention, consented to self_access only.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- enabled booleanrequired
§13.1: off by default. Cannot be set true in this release — gated on the review of
PIA-2026-001.- key_include string[]required
Key hashes to capture. Empty means every key.
- key_exclude string[]required
Exclusion wins over inclusion — a key in both is not captured.
- retention_days integerrequired
At least 90 (§13.1's ~3-month floor). Content past this is deleted hourly.
- locked booleanrequired
Settings frozen; further changes refused until cleared.
- purposes enum[]required
What this organisation consented to.
self_accessis its own replay and debugging;ragwould be indexing, and is a separate grant because consent is purpose-specific.- consented_at string | null
When logging was enabled. Null while it is off.
Configure input/output logging
Management key only: an inference key must not be able to change what is recorded about its own traffic.
`enabled: true` is refused in this release. It is gated on the review of PIA-2026-001, whose adequacy conclusion depends on prompt content not being stored. Every other field configures now.
locked: true freezes the settings; further changes are refused until it is cleared — and changing the setting needs the Owner or Developer role (a management key with no person behind it has full power).
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- enabled boolean
Refused when true in this release.
- key_include string[]
Key hashes to capture. Empty means every key.
- key_exclude string[]
Exclusion wins over inclusion — a key in both is not captured.
- retention_days integer
§13.1's ~3-month floor.
- locked boolean
- purposes enum[]
What the organisation consents to. Must include
self_access; to stop storing, disable logging instead. Consent is purpose-specific — agreeing that we store your prompts so you can replay them is not agreeing that we may index them.
Responses
- enabled booleanrequired
§13.1: off by default. Cannot be set true in this release — gated on the review of
PIA-2026-001.- key_include string[]required
Key hashes to capture. Empty means every key.
- key_exclude string[]required
Exclusion wins over inclusion — a key in both is not captured.
- retention_days integerrequired
At least 90 (§13.1's ~3-month floor). Content past this is deleted hourly.
- locked booleanrequired
Settings frozen; further changes refused until cleared.
- purposes enum[]required
What this organisation consented to.
self_accessis its own replay and debugging;ragwould be indexing, and is a separate grant because consent is purpose-specific.- consented_at string | null
When logging was enabled. Null while it is off.
List guardrails
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- name string
- model_allowlist string[]
- provider_allowlist string[]
- allowed_data_regions string[]
Regions an endpoint may run in, matched exactly against the endpoint
deployment_regionfield and lower-cased on write. Empty is unrestricted. This fails CLOSED: an endpoint that declares no region is not in one, so it is refused. A region no ready endpoint declares is rejected at write time rather than refusing every request later.- budget_nanodollars string | null
Nanodollars (1e-9 USD), an integer as a string.
- budget_reset string | null
- include_byok_spend boolean
Count spend made on your own provider credential toward this ceiling, at IMPUTED LIST PRICE -- what the call would have cost on platform capacity, not the platform fee charged. Defaults to false, and while every model is BYOK-only that means the ceiling counts nothing and cannot bind.
- zdr_flags object
- content_filter_builtins string[]
- content_filters ContentFilter[]
- filter_allowlist string[]
- created_at string
- assignments object[]
Create a guardrail
Assign it to a key to take effect. Policy merges organization, then workspace, then key, and each level can only narrow what the one above allows (§4.2).
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- name stringrequired
- limit_usd number
A budget in USD, evaluated per key.
- reset_interval enum
- One of: daily, weekly, monthly, lifetime
- allowed_models string[]
- allowed_providers string[]
- allowed_data_regions string[]
Regions an endpoint may run in, matched exactly against the endpoint
deployment_regionfield and lower-cased on write. Empty is unrestricted. This fails CLOSED: an endpoint that declares no region is not in one, so it is refused. A region no ready endpoint declares is rejected at write time rather than refusing every request later.- include_byok_in_budgets boolean
Count spend made on your own provider credential toward this ceiling, at IMPUTED LIST PRICE -- what the call would have cost on platform capacity, not the platform fee charged. Defaults to false, and while every model is BYOK-only that means the ceiling counts nothing and cannot bind.
- enforce_zdr object
- content_filter_builtins enum[]
- content_filters ContentFilter[]
- filter_allowlist string[]
Phrases a filter must never act on.
Responses
- id string
- name string
- budget_nanodollars string | null
Nanodollars (1e-9 USD), an integer as a string.
- budget_reset string | null
- content_filter_builtins string[]
- content_filters ContentFilter[]
- filter_allowlist string[]
Delete a guardrail
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A guardrail
id.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Responses
- deleted anyrequired
Assign a guardrail
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- id string · pathrequired
A guardrail
id.- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- subject_type enumrequired
- One of: key, member
- subject_id stringrequired
For a key, its
hash.
Responses
- guardrail_id string
- subject_type string
- subject_id string
Auth
Dashboard sign-in.
The organisations I belong to
Every organisation the signed-in person has an active seat in, with their role and which one this session is in.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- id string
- name string
- role string
- role_name string
- current boolean
Switch organisation
Moves the session into another organisation the person has a seat in (Set-Cookie). 404 for one they do not.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- org_id stringrequired
Responses
- org_id string
Get the current session
Authentication
Dashboard session
Responses
- expires_at string
- org_id string
- key_name string | null
- user object | null
- auth_method string
Exchange a management key for a dashboard session
Sets the httpOnly ar_session cookie and the script-readable ar_csrf cookie. Rate limited per client address.
Authentication
None: this endpoint is public.
Request body
- key stringrequired
A management key.
Responses
- expires_at string
- org_id string
- key_name string | null
- user object | null
- auth_method string
Sign out
Always succeeds, and clears both cookies.
Authentication
Dashboard session
Responses
- ended anyrequired
Describe an OAuth PKCE authorization request
What the consent screen at /auth renders. Public and rate limited: it validates the query string and echoes back the terms a key issued under it would carry. It reads nothing about any account, so a malformed request is refused before the user is asked to sign in.
Authentication
None: this endpoint is public.
Parameters
- callback_url string · query
Where to return the code. Omit for the headless flow, which then requires
S256andkey_label.httpsonly, except on localhost.- code_challenge string · query
The PKCE challenge, 43-128 characters.
- code_challenge_method enum · query
Must be
S256, sent explicitly.plainandnoneare refused for every flow, redirect included: a code returned to a localhost callback can be read by any process on that machine, and only a hashed challenge keeps it from minting a key there (RFC 7636 §7.2).- key_label string · query
Names the issued key on the Keys screen. Defaults to the callback host.
Responses
- callback_url string | nullrequired
Where the code will be returned. Null for the headless flow.
- host string | nullrequired
The callback's host — what the consent screen puts in front of the user. Null when headless, and then
key_labelis the only name there is.- headless booleanrequired
No callback URL: the code is displayed for manual entry. Requires
S256andkey_label.- key_label stringrequired
Names the issued key on the Keys screen, so access can be revoked by app.
- code_challenge_method enumrequired
Always
S256;plainandnoneare refused for every flow.One of: S256- limit numberrequired
The spend ceiling the issued key will carry. Served rather than hardcoded in the consent screen, so the terms shown are the terms applied.
- expires_in_days integerrequired
How long the issued key will last.
Approve an app and mint a one-time code
Called by the consent screen once the user agrees. The request is re-validated from the body: the preceding GET is a convenience and proves nothing about this call. Codes are single-use and expire in ten minutes.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Parameters
- x-csrf-token string · header
Required with a session cookie on any method but GET: the value of the
ar_csrfcookie. Not used with a bearer key.
Request body
- callback_url string
- code_challenge string
- code_challenge_method enum
- One of: S256, plain, none
- key_label string
Responses
- code stringrequired
The one-time code. Ten minutes, single use.
- redirect_to string | nullrequired
The callback URL with
codeappended, preserving any query the app already put there. Null when headless.- expires_at stringrequired
Exchange a PKCE code for an API key
Unauthenticated by design -- the caller is an app that has no key yet, and the code plus its verifier are the credential. This is the one route that answers cross-origin (Access-Control-Allow-Origin: *), because a single-page app is exactly the public client PKCE exists for. Access-Control-Allow-Credentials is never set, so no cookie can ride along.
The code is consumed the moment it is looked up, including when verification then fails: a caller gets one attempt at the verifier, not a grinding window (RFC 6749 §4.1.2). The issued key is an inference key carrying a spend ceiling and an expiry, and is revocable from the Keys screen like any other.
Authentication
None: this endpoint is public.
Request body
- code stringrequired
The code from the callback, or pasted from the headless flow.
- code_verifier string
The PKCE verifier. Required unless the code was issued under
none.- code_challenge_method enum
Optional. If sent it must MATCH the method the code was issued under; it never replaces it.
One of: S256, plain, none
Responses
- key stringrequired
The inference key. In this response and never again — only a salted hash is stored.
- hash stringrequired
Identifies the key for revocation.
- label stringrequired
The app this key was issued to.
- limit number | nullrequired
The spend ceiling, in US dollars.
- expires_at stringrequired
List the sign-in methods this deployment offers
Authentication
None: this endpoint is public.
Responses
- management_key any
- oauth enum[]
- wallet boolean
Start signing in with Google or GitHub
A browser navigation, not an API call: redirects to the provider with PKCE and a state cookie (ar_oauth, ten minutes).
Authentication
None: this endpoint is public.
Parameters
- provider enum · pathrequired
The identity provider.
Responses
The OAuth redirect target
Always redirects: to /workspace with a session on success (?welcome=1 for a new user), otherwise to /signin?error= with one of cancelled, provider_error, expired, state_mismatch, no_code, not_configured, exchange_failed.
Authentication
None: this endpoint is public.
Parameters
- provider enum · pathrequired
The identity provider.
- code string · query
The authorization code.
- state string · query
Must match the
ar_oauthcookie.- error string · query
Set by the provider when sign-in did not happen.
Responses
Start signing in with a wallet
Returns a Sign-In with Ethereum message to sign. The challenge lasts five minutes.
Authentication
None: this endpoint is public.
Request body
- address stringrequired
Responses
- message string
- nonce string
- expires_at string
Finish signing in with a wallet
Sets the session cookies on success.
Authentication
None: this endpoint is public.
Request body
- address stringrequired
- signature stringrequired
- nonce stringrequired
Responses
- expires_at string
- org_id string
- is_new_user boolean
Runs
Agent runs (§17.1): one goal, many turns, one budget enforced across all of them.
List runs
Newest first, for the calling key's organization.
Authentication
Inference key (ar-v1-…)
Parameters
- limit integer · query
Page size, capped at 100.
Responses
- id stringrequired
- status enumrequired
exhaustedis set by settlement when spend reaches the budget, andpausedby the §17.4 runaway detector. A caller may set onlycompletedorcancelled— a client able to claim either of the other two could report a breach that never happened.pausedis the one non-open status that is recoverable: seePOST /v1/runs/{id}/resume.One of: open, paused, completed, exhausted, cancelled- goal string | null
- budget numberrequired
The ceiling. Required at creation, always positive: a run without one is what §17.1 exists to prevent.
- spent numberrequired
Settled. Imputed list price — what the turns were worth at catalog prices, not money billed through us. Under the BYOK-only policy inference is billed by your own provider, and a run sized on our fee would report every turn as free (§9.6).
- reserved numberrequired
Worst-case imputed cost committed by turns admitted but not yet settled. Published because
budget - spentalone overstates the headroom a run actually has.- remaining numberrequired
budget - spent - reserved.- max_turns integer | null
- turns_used integerrequired
- max_tool_calls integer | null
- tool_calls_used integerrequired
- model_policy object
- max_cost_per_minute number | null
§17.4 threshold, in USD. Null means the cost-velocity detector is off for this run.
- max_tool_calls_without_progress integer | null
§17.4 threshold. Null means the no-progress detector is off for this run.
- tool_calls_without_progress integer
Consecutive tool calls with no answering turn between them. Reset to 0 by any turn finishing with something other than
tool_calls.- pause_reason string | null
Which detector paused this run. Set only by settlement — the actionable half, since a paused run without a stated cause leaves you guessing which threshold to raise.
One of: cost_velocity, no_progress, null- paused_at string | null
- created_at string
- updated_at string
- closed_at string | null
Open a run
A run is one goal across many turns, with one budget enforced across all of them. Pass its id as run_id on each completion.
Inference class, not management: the thing that opens a run is the agent, and requiring a management key would hand every agent the credential that mints keys and moves budgets. The run is scoped to the organization, so a supervisor and its workers may hold different keys and share one.
Authentication
Inference key (ar-v1-…)
Request body
- goal string
Free text, at most 2000 characters.
- budget_usd numberrequired
Required, and positive. There is no way to open an uncapped run.
- max_turns integer
Bounds how many times the agent may ask. A failed turn refunds its money but not its turn — see
packages/docs/RUNS.md.- max_tool_calls integer
Checked at turn admission, so a single turn can exceed it by its own call count.
- model_policy object
- max_cost_per_minute_usd number
§17.4 runaway detector, opt-in. Pauses the run when spend inside a tumbling one-minute window exceeds this. Omit to leave it off.
The window is tumbling, not sliding: a burst straddling a boundary can be split across two windows and escape. Acceptable for a safety net whose job is to stop a loop running overnight; it is not a billing control.
- max_tool_calls_without_progress integer
§17.4 runaway detector, opt-in. Pauses the run after this many consecutive tool calls with no answering turn between them — "progress" meaning a turn that finished with something other than
tool_calls. Omit to leave it off.
Responses
- id stringrequired
- status enumrequired
exhaustedis set by settlement when spend reaches the budget, andpausedby the §17.4 runaway detector. A caller may set onlycompletedorcancelled— a client able to claim either of the other two could report a breach that never happened.pausedis the one non-open status that is recoverable: seePOST /v1/runs/{id}/resume.One of: open, paused, completed, exhausted, cancelled- goal string | null
- budget numberrequired
The ceiling. Required at creation, always positive: a run without one is what §17.1 exists to prevent.
- spent numberrequired
Settled. Imputed list price — what the turns were worth at catalog prices, not money billed through us. Under the BYOK-only policy inference is billed by your own provider, and a run sized on our fee would report every turn as free (§9.6).
- reserved numberrequired
Worst-case imputed cost committed by turns admitted but not yet settled. Published because
budget - spentalone overstates the headroom a run actually has.- remaining numberrequired
budget - spent - reserved.- max_turns integer | null
- turns_used integerrequired
- max_tool_calls integer | null
- tool_calls_used integerrequired
- model_policy object
- max_cost_per_minute number | null
§17.4 threshold, in USD. Null means the cost-velocity detector is off for this run.
- max_tool_calls_without_progress integer | null
§17.4 threshold. Null means the no-progress detector is off for this run.
- tool_calls_without_progress integer
Consecutive tool calls with no answering turn between them. Reset to 0 by any turn finishing with something other than
tool_calls.- pause_reason string | null
Which detector paused this run. Set only by settlement — the actionable half, since a paused run without a stated cause leaves you guessing which threshold to raise.
One of: cost_velocity, no_progress, null- paused_at string | null
- created_at string
- updated_at string
- closed_at string | null
Get a run and its tree
§17.1's tree: turns, per-turn cost, cache hit rate, failed tool calls, model switches and a terminal status.
Authentication
Inference key (ar-v1-…)
Parameters
- id string · pathrequired
The run id.
Responses
Close a run
Terminal. Closing an already-closed run is a 409 naming its current status, never a silent no-op.
Authentication
Inference key (ar-v1-…)
Parameters
- id string · pathrequired
The run id.
Request body
- status enum
- One of: completed, cancelledDefault: "completed"
Responses
- id stringrequired
- status enumrequired
exhaustedis set by settlement when spend reaches the budget, andpausedby the §17.4 runaway detector. A caller may set onlycompletedorcancelled— a client able to claim either of the other two could report a breach that never happened.pausedis the one non-open status that is recoverable: seePOST /v1/runs/{id}/resume.One of: open, paused, completed, exhausted, cancelled- goal string | null
- budget numberrequired
The ceiling. Required at creation, always positive: a run without one is what §17.1 exists to prevent.
- spent numberrequired
Settled. Imputed list price — what the turns were worth at catalog prices, not money billed through us. Under the BYOK-only policy inference is billed by your own provider, and a run sized on our fee would report every turn as free (§9.6).
- reserved numberrequired
Worst-case imputed cost committed by turns admitted but not yet settled. Published because
budget - spentalone overstates the headroom a run actually has.- remaining numberrequired
budget - spent - reserved.- max_turns integer | null
- turns_used integerrequired
- max_tool_calls integer | null
- tool_calls_used integerrequired
- model_policy object
- max_cost_per_minute number | null
§17.4 threshold, in USD. Null means the cost-velocity detector is off for this run.
- max_tool_calls_without_progress integer | null
§17.4 threshold. Null means the no-progress detector is off for this run.
- tool_calls_without_progress integer
Consecutive tool calls with no answering turn between them. Reset to 0 by any turn finishing with something other than
tool_calls.- pause_reason string | null
Which detector paused this run. Set only by settlement — the actionable half, since a paused run without a stated cause leaves you guessing which threshold to raise.
One of: cost_velocity, no_progress, null- paused_at string | null
- created_at string
- updated_at string
- closed_at string | null
Resume a run the runaway detector paused
The counterpart to pausing rather than cancelling (§17.4): the detector stops a run so a human can look at it, and this is how they say "I looked, carry on".
Clears the counters that caused the pause — without that it would pause again on the very next settlement and this call would appear to do nothing. The budget and turn counts are deliberately not reset: those are the caps the run was opened under, and a pause is not an amnesty.
Only a paused run resumes. exhausted and cancelled are genuinely finished, and resuming those would be a way to reopen a budget that has already bound.
Authentication
Inference key (ar-v1-…)
Parameters
- id string · pathrequired
The run id.
Responses
- id stringrequired
- status enumrequired
exhaustedis set by settlement when spend reaches the budget, andpausedby the §17.4 runaway detector. A caller may set onlycompletedorcancelled— a client able to claim either of the other two could report a breach that never happened.pausedis the one non-open status that is recoverable: seePOST /v1/runs/{id}/resume.One of: open, paused, completed, exhausted, cancelled- goal string | null
- budget numberrequired
The ceiling. Required at creation, always positive: a run without one is what §17.1 exists to prevent.
- spent numberrequired
Settled. Imputed list price — what the turns were worth at catalog prices, not money billed through us. Under the BYOK-only policy inference is billed by your own provider, and a run sized on our fee would report every turn as free (§9.6).
- reserved numberrequired
Worst-case imputed cost committed by turns admitted but not yet settled. Published because
budget - spentalone overstates the headroom a run actually has.- remaining numberrequired
budget - spent - reserved.- max_turns integer | null
- turns_used integerrequired
- max_tool_calls integer | null
- tool_calls_used integerrequired
- model_policy object
- max_cost_per_minute number | null
§17.4 threshold, in USD. Null means the cost-velocity detector is off for this run.
- max_tool_calls_without_progress integer | null
§17.4 threshold. Null means the no-progress detector is off for this run.
- tool_calls_without_progress integer
Consecutive tool calls with no answering turn between them. Reset to 0 by any turn finishing with something other than
tool_calls.- pause_reason string | null
Which detector paused this run. Set only by settlement — the actionable half, since a paused run without a stated cause leaves you guessing which threshold to raise.
One of: cost_velocity, no_progress, null- paused_at string | null
- created_at string
- updated_at string
- closed_at string | null
MCP
Model Context Protocol, for coding agents. Every tool adapts a route documented above.
Not offered: this server has no server-initiated stream
Always 405. MCP's transport requires that status from a server offering no SSE stream, and it is answered deliberately rather than left to a 404, because a client probing for a stream must read "not offered" rather than "wrong URL".
Authentication
None: this endpoint is public.
Responses
Call the MCP server
JSON-RPC 2.0 over MCP's Streamable HTTP transport, protocol revision 2025-06-18. Methods: initialize, tools/list, tools/call, ping, and the notifications/* messages.
Every tool is an adapter over a route documented elsewhere in this file, dispatched through this gateway's own router — so an MCP call passes the same authentication, rate limits, spend ceilings, guardrails and ledger as the HTTP call it stands for. See packages/docs/MCP.md.
Requires an inference key; a management key gets 403, as it does on /v1/chat/completions. The OAuth PKCE flow (/auth) is the intended way for a coding tool to obtain one.
Stateless: no Mcp-Session-Id, because several instances run behind a load balancer with no sticky routing. JSON-RPC batching is refused — revision 2025-06-18 removed it.
Authentication
Inference key (ar-v1-…)
Request body
- jsonrpc anyrequired
- id string | integer | null
Omit the field entirely for a notification, which is answered with 202 and no body. An explicit
nullis a request, not a notification.- method stringrequired
e.g.
tools/call.- params object
Responses
- jsonrpc anyrequired
- id string | integer | nullrequired
- result object
For
tools/call:content(an array of text blocks) andisError.- error object
Meta
Health, region, and this document.
Health
Public; for load balancers and uptime checks. A 500 means the database is unreachable.
Liveness, the version this document already publishes, and whether the rate limiter is shared across instances — nothing here varies with account activity. The cache statistics that used to be served here are at GET /v1/health, behind a management key.
Authentication
None: this endpoint is public.
Responses
- status anyrequired
- version string
The same value this document publishes as
info.version.- rate_limiting object
Operational diagnostics
Everything /health reports, plus the hot-path cache counters and the age of the routing health snapshot.
Behind a management key of an operator organisation (OPERATOR_ORG_IDS): it describes the deployment rather than serving a model, and its counters move with every tenant's traffic, so any other management key receives 404. Unlike /health it is not exempt from the jurisdiction gate — it is authenticated and for operators, so a region we decline to serve reaches nothing here.
Authentication
Management key (ar-mgmt-…) · Dashboard session
Responses
- status anyrequired
- version string
- rate_limiting object
- caches object
Hit, miss, stale and size counters for the hot-path caches (
auth,guardrails,budgets,byok,catalog). Authenticated because the first four move with real account activity: served publicly they were a side channel anyone could poll.- endpoint_health_age_ms integer | null
Age of the routing health snapshot. Growing without bound means the refresher has died and routing is deciding on stale tiers — which looks exactly like healthy routing.
Receive a Content-Security-Policy violation report
For browsers, not for you: the dashboard's CSP names this path in report-uri. Accepts the legacy application/csp-report document and the Reporting API's application/reports+json array; the violation's document, directive, blocked URI and source are logged (each clipped to 200 characters, at most ten per report) and nothing is stored. Unauthenticated and rate-limited per address like the catalog.
Authentication
None: this endpoint is public.
Responses
The caller's coarse region
As the edge reported it. The dashboard uses it to choose a language, so it is never refused by region.
Authentication
None: this endpoint is public.
Responses
- region string | null
- subdivision string | null
This document, as JSON
Authentication
None: this endpoint is public.
Responses
This document, as YAML
Authentication
None: this endpoint is public.
Responses
This document, as JSON
Authentication
None: this endpoint is public.
Responses
This document, as YAML
Authentication
None: this endpoint is public.