Agent reference
The depth behind Add an agent.
The Agents row reports the source hook separately from routing and MCP liveness. command and
http mean installed; missing means upgrade Connect. An absent report is unknown, including
a gateway restart or another replica. Reports expire after one minute and never license trimming.
Status vocabulary
The Agents card reads each key from GET /admin/v1/keys?type=service and the gateway's schema version from GET /admin/health (schema.version). Each status is its own state; none stands in for another.
| Status | Meaning |
|---|---|
| Checking… | The keys or health read is still in flight. |
| Needs gateway upgrade | schema.version is below 0083_client_keys_seen, or the source-evidence count is absent for a supported client. Upgrade the gateway; the host is fine. |
| Never connected | No request has authenticated with this key. |
| Active | A request landed and retrieval evidence is within six hours of it. A supported source lane has also recorded a trim within its observation window. |
| Active · observing source trim | A source-capable client has retrieval, but has not yet had enough traffic and time to assess source trimming. |
| Active · source trim not seen | At least seven days and 100 successful source-capable inference requests since observation began or the last trim, with none recorded. The row opens a copyable repair and polls its key. |
| Active · client has no MCP | The last client is pi, which has no MCP client to register. |
| Source evidence unavailable | Invalid or unreadable source evidence; retrying does not diagnose a host defect. |
| Active · retrieval not seen | Requests land, but no tool on the host has called the gateway's MCP server. Clicking the row opens Setup at step 3. |
| Expired | expiresAt has passed. |
| Revoked | Revoked. Hidden from the roster. |
Last active is lastSeenAt (current to within 5 minutes) with lastSeenTool, the gateway's id for the client that made the request: codex, claude-code, openclaw, shell-env, or the tool from x-anyray-metadata.
The post-mint dialog polls the same record every 5 seconds for up to 10 minutes and stops at Active.
Routing
Routing on the Add agent dialog, or on the agent's detail view later, binds the key to one provider and one of its named keys so its spend lands on a separate upstream account. Left unset, the agent follows the org routing config. Changing it changes nothing on the host.
Retrieval tools
The gateway MCP server omits its extra instruction block by default. Its retrieval tools remain callable, and a model asks for a marked payload when it needs one. The block is a nudge for weaker models, and turning it on adds prefix tokens to every request, so the default stays off. No host configuration is involved either way.
Mint from the admin API
For a provisioning script. POST /admin/v1/keys with type: "service" needs an admin token with the clientkeys:manage capability (the keys:write scope).
curl https://<your-anyray-gateway>/admin/v1/keys \
-H "Authorization: Bearer $ANYRAY_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "service",
"name": "synthetic-deploy-agent",
"team": "platform",
"monthlyBudgetUsd": 50,
"routingProvider": "bedrock",
"routingProviderKeyId": "ci-account"
}'
service. The same route mints user and enrollment keys; this selects the agent kind.
The agent's identity, 1 to 64 characters matching [A-Za-z0-9_.:-]. Becomes its attribution user
id in the console.
Same slug rules. Rolls the agent's spend up to a team.
Caps the key's real out-of-pocket spend per UTC calendar month; included subscription usage
counts only its over-allowance overage. Omit, or pass 0, for an uncapped key. Negative values
clamp to 0.
For a shared agent that serves many people. When true, each request is attributed to the
user (and team, when sent) the agent names in x-anyray-metadata, validated as an id; a
value that fails validation falls back to the agent's own name. The agent stays on every spend
row as agent, and the people it names count as seats like any attributed user. The gateway
trusts what the key sends, so a mis-filed user is your own key mis-reporting; enable it only on
an agent you operate. Change it later with PATCH /admin/v1/keys/:id (null clears).
Binds this agent's traffic to one provider, independent of the org routing config. Must be a
provider this gateway can route to (capabilities.supportedProviders on
GET /admin/v1/providers); anything else returns 400. Omit for the org routing.
Which of that provider's named keys pays. Only valid alongside
routingProvider; omit for the provider's default key. An unknown key id returns 400, so a
mistake surfaces here rather than as 424s on the agent's traffic later.
Routes the agent across several upstream accounts instead of one. Mutually exclusive with
routingProvider / routingProviderKeyId, which the gateway derives from this config's first
target; sending both returns 400.
{
"mode": "loadbalance",
"targets": [
{ "provider": "bedrock", "providerKeyId": "ci-account", "weight": 3 },
{ "provider": "anthropic", "weight": 1 }
],
"retryAttempts": 2
}
mode is single, loadbalance, or fallback. targets holds 1 to 8 entries, each a
provider plus an optional providerKeyId; weight (a non-negative integer, default 1) is
read in loadbalance only, and fallback tries targets in order on 429, 500, 502, and
503. retryAttempts (0 to 5) retries each target on those statuses before moving on. Every
target is validated at write time: an unroutable provider or unknown key id anywhere in the list,
a duplicate target, a single mode with several targets, or an all-zero-weight loadbalance
returns 400.
Load balancing is sticky per conversation (each upstream account keeps its own prompt cache, so moving a conversation mid-flight would rewrite its whole prefix); the split happens across conversations. See the gateway's routing.
Returns 201 with { key, record }, where key is the raw ark_svc_… token, returned only
here. A malformed body returns 400.
Change or clear a binding later with PATCH /admin/v1/keys/:id. {"routingProvider": null}
clears the whole binding, scalars and config alike, and the agent goes back to the org routing;
{"routingConfig": null} clears a multi-target config while leaving a single-provider binding
alone. Sending routingProvider replaces a stored multi-target config rather than editing
its first target, so an agent narrowed back to one provider stops billing the accounts you
removed. Sending routingProviderKeyId alone to a multi-provider agent returns 400 rather
than collapsing the split; send the full routingConfig, or a routingProvider with it. A
binding applies to service keys only; one on a human key returns 400.
Send the key on a raw HTTP request
A client that doesn't read the environment sends the key in a header. The gateway checks
x-anyray-api-key first, then Authorization: Bearer, then x-api-key:
curl https://<your-anyray-gateway>/v1/chat/completions \
-H "Authorization: Bearer ark_svc_…" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-5", "messages": [{"role": "user", "content": "ping"}]}'
x-api-key works only because the token carries the ark_ prefix; that's what tells the
gateway it's ours. A non-ark_ x-api-key is treated as your own provider key (BYO-key mode)
and passed upstream untouched.
Manage keys
| Action | How |
|---|---|
| List every agent, with status and last active | The Agents card, or get /admin/v1/keys?type=service (never returns the raw token) |
| Read one | Click its row, or get /admin/v1/keys/:id |
| Change its routing | The row's General info tab, or patch /admin/v1/keys/:id |
| Revoke one | The row's Revoke, or delete /admin/v1/keys/:id |
Revoking marks the key rather than deleting it, so the agent's historical spend stays out of your seat count after it's retired. Changing a budget means minting a new key.
monthlyBudgetUsd is fail-open. Completed successful requests update the shared counter after
their responses, so concurrent requests can overshoot it. If the counter is unavailable, traffic
continues rather than stalling.