Skip to main content

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.

StatusMeaning
Checking…The keys or health read is still in flight.
Needs gateway upgradeschema.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 connectedNo request has authenticated with this key.
ActiveA 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 trimA source-capable client has retrieval, but has not yet had enough traffic and time to assess source trimming.
Active · source trim not seenAt 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 MCPThe last client is pi, which has no MCP client to register.
Source evidence unavailableInvalid or unreadable source evidence; retrying does not diagnose a host defect.
Active · retrieval not seenRequests land, but no tool on the host has called the gateway's MCP server. Clicking the row opens Setup at step 3.
ExpiredexpiresAt has passed.
RevokedRevoked. 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).

Mint a service key
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"
}'
typestringrequired

service. The same route mints user and enrollment keys; this selects the agent kind.

namestringrequired

The agent's identity, 1 to 64 characters matching [A-Za-z0-9_.:-]. Becomes its attribution user id in the console.

teamstringrequired

Same slug rules. Rolls the agent's spend up to a team.

monthlyBudgetUsdnumber

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.

delegatedAttributionboolean

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).

routingProviderstring

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.

routingProviderKeyIdstring

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.

routingConfigobject

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.

Load balance across two accounts
{
"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:

One request
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

ActionHow
List every agent, with status and last activeThe Agents card, or get /admin/v1/keys?type=service (never returns the raw token)
Read oneClick its row, or get /admin/v1/keys/:id
Change its routingThe row's General info tab, or patch /admin/v1/keys/:id
Revoke oneThe 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.

The budget is a soft cap

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.