Choose enrollment
Enroll users from the console so their tools route through the gateway.
Choose an enrollment path
Best for a pilot or small team before SSO is configured. Mint a personal link or share one reusable link.
SSO enrollmentBest when user identity should be verified by your IdP. Share one organization command that enrolls the user and configures every supported tool it detects; no per-user invite is required.
Inbound SCIMBest when the IdP should create, group, activate, and deactivate identities.
Bulk MDM enrollmentBest for fleet rollout through Jamf, Intune, or another device manager. The Users page shows regular provisioning-token enrollment without SSO, and only the SSO handoff after SSO is connected.
Share one command
A shared enrollment link has no pre-bound email. The raw enl_… token is the bearer capability,
so share it only in a channel whose members should be able to enroll.
On Users, choose Invite users. The console mints the org's shared link and shows it
as a copy-paste curl … connect.sh | sh command (the raw link is shown once — reopening the
pane offers rotate/revoke instead). The mint request omits email:
{
"team": "platform"
}
Paste the command in Slack. Anyone on the team can run the same command until the link
expires or an admin revokes it — their identity is self-asserted by anyray-connect
(detected git name/email, else OS user; --user overrides), and each enrollee appears on the
Users roster. Once SSO is configured, direct link redemption is refused and users enroll
through the organization SSO command instead.
Enroll an AI agent or CI job
A non-human workload does not need interactive SSO. Enroll it as a revocable service key — from the
console or the admin API. Either way the agent is automatically excluded from your billed seat
count, so an enrolled agent never adds a per-seat charge (you don't list it in
ANYRAY_SEAT_EXCLUDE).
Console — on the Users page, find the Agents card and choose Add agent. Give the
agent a name and team (slugs: letters, digits, dot, colon, hyphen, underscore), then copy the
ark_svc_… key it shows once. The same card lists every agent and revokes one in a click.
Admin API — mint it directly, e.g. from a provisioning script. The optional monthlyBudgetUsd
caps the key's successful request cost for each UTC calendar month:
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
}'
Save the returned ark_svc_… key in the workload's secret store immediately. It is shown only once;
Anyray persists its hash, identity metadata, and budget, never the raw token.
Then point the agent at the gateway with that key. 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. A raw-HTTP agent sends the same key as x-anyray-api-key,
x-api-key, or Authorization: Bearer:
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"}]}'
To wire the key straight into client code instead of the environment — the OpenAI and Anthropic SDKs, LangChain, the Vercel AI SDK, 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.
Revoke the key with delete /admin/service-keys/:id (or the Agents
card on the console's Users page) when the job or agent is retired.
The per-key dollar budget is a soft, fail-open cap. Completed successful requests update the shared
counter after their responses, so concurrent requests can overshoot. If the counter is unavailable,
traffic continues. Omitting monthlyBudgetUsd, or setting it to 0, makes the key unlimited.
Once SSO is configured, regular enrollment-link and provisioning-token minting or rotation returns
409, and previously issued enl_… or enp_… tokens return sso_required when redeemed.
Both email and machine MDM modes are blocked. Existing tokens remain visible so an admin can revoke
them; non-human automation uses a service key.
Rollout order
Save server-held provider keys on Providers for traffic Anyray will serve through a provider API. Skip this for first-party subscription pass-through and native Cursor Team Claude/Opus.
Use Connect to confirm the gateway, routing, and spend attribution are working. Test routing with API-key traffic. Claude Code and Codex subscription pass-through requests cross the gateway with the first-party OAuth token and do not use Anyray provider routing. Native Cursor Team Claude/Opus requests remain on Cursor; verify the personal key and local hook/MCP health instead of expecting an inference trace.
With an active SSO connection, share the command under Users → SSO enrollment. Without SSO, mint a passwordless link or MDM provisioning token from Users.
The Users roster moves users from pending to enrolled as their machines
finish setup. Each row includes a provenance source (manual, provisioning, sso,
scim, email, mdm, or service) and an identity type (person or service). Existing
manual and MDM rows remain unchanged; SCIM-provisioned service accounts use scim + service.