AI agent enrollment
A non-human workload can't complete a browser sign-in. Give it a service key instead.
An agentic workflow, CI job, or SDK script doesn't enroll the way a developer does — there's no
one to sign in. Mint it a service key (ark_svc_…) instead: a durable, revocable credential
carrying its own identity, team, and optional monthly budget.
Service keys are excluded from your billed seat count automatically. An enrolled agent never
adds a per-seat charge, and you don't list it in ANYRAY_SEAT_EXCLUDE.
Mint a key
On the console's Users page, find the Agents card and choose Add agent.
Both are slugs: 1–64 characters of letters, digits, dot, colon, hyphen, or underscore. The team is required — it's how the agent's spend rolls up in the console.
Copy the ark_svc_… value into the workload's secret store now. It's shown once; Anyray
stores its hash, identity metadata, and budget, never the raw token.
Mint from the admin API instead
For a provisioning script, mint it directly. Requires an admin token with the
clientkeys:manage capability.
curl https://<your-anyray-gateway>/admin/service-keys \
-H "Authorization: Bearer $ANYRAY_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "synthetic-deploy-agent",
"team": "platform",
"monthlyBudgetUsd": 50
}'
The agent's identity, 1–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 successful request cost per UTC calendar month. Omit it, or pass 0, for an
uncapped key. Negative values clamp to 0.
Returns 201 with { key, record } — key is the raw ark_svc_… token, returned only here.
A malformed body returns 400.
Point the agent at the gateway
Most agent frameworks and SDKs read the base URL and key from the environment. Which two variables depends on the client's dialect:
- bash
- bash
export OPENAI_BASE_URL=https://<your-anyray-gateway>/v1
export OPENAI_API_KEY=ark_svc_… # the key you just minted
export ANTHROPIC_BASE_URL=https://<your-anyray-gateway>
export ANTHROPIC_AUTH_TOKEN=ark_svc_… # no /v1 — the SDK appends it
The agent then calls models exactly as before — the gateway authenticates the key, routes, meters, and optimizes every request.
Its next request appears in the console's live traffic view, attributed to the name and team
you gave it. The Agents card lists the key with type: service.
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.
Wire the key into client code instead
To put the key straight into the OpenAI or Anthropic SDKs, LangChain, the Vercel AI SDK, or LlamaIndex, see SDKs & frameworks — a service key goes wherever those examples take a gateway key. The console's Enroll agent dialog prints the same snippets with your gateway URL and the new key already filled in.
Manage keys
| Action | How |
|---|---|
| List every agent | The Agents card, or get /admin/service-keys (metadata only — never the raw token) |
| Revoke one | The Agents card, or delete /admin/service-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.
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.