Administration API
Namespaces, backends, routing rules, members and keys — everything the console drives.
The console is the usual way to do all of this, and the CLI wraps the same routes. This page is the API underneath both, for anyone automating a deployment.
There are two scopes. Tenancy routes live under /{tenancy}/v1 and concern the organisation.
Namespace routes live under /{tenancy}/{namespace}/v1 and concern one isolated workspace
inside it.
Standing and access
Standing is held in the tenancy. It is user, admin or owner, and it decides what a
member may do to the organisation.
| Standing | Can |
|---|---|
user | Find the tenancy's namespaces, and use the ones granted to them |
admin | Everything a user can, plus manage namespaces, backends, rules, members and keys |
owner | Everything an admin can, plus delete the tenancy and transfer ownership |
Access is narrower, and it is what a grant carries: one member, one namespace, and
either use or manage. It is how a user comes to be able to use prod but not staging.
The two vocabularies never mix. user, admin and owner are standings; use and manage
are accesses; neither is ever written where the other belongs.
| Access | Can |
|---|---|
use | Submit to the namespace and retrieve from it |
manage | That, plus routing rules, backend attachments, usage and the request log |
An admin or the owner manages every namespace in the tenancy and needs no grant for any of
them.
Getting in
| Route | Takes | Gives |
|---|---|---|
POST /v1/registrations | A registration token, or an identity provider's | A new tenancy and its owner |
POST /v1/sessions | Email and password | A session key |
POST /v1/sessions/exchange | An identity provider's token | A session key |
A registration token is a file in the deployment's secret mount, one per client. Registration is the only way a tenancy comes to exist, and the first account created owns it.
Where the deployment signs people in through an identity provider, that provider's token is
accepted in place of a registration token, and the owner's address is taken from it rather than
from the body — a token whose address the provider has not confirmed is refused. Such an owner
has no password on this service, because they do not sign in with one: they exchange the
provider's token for a session at POST /v1/sessions/exchange, and everything below that point
is the same for them as for anybody else. A deployment that runs no provider has neither route
behaviour and is unchanged.
Namespaces
| Route | Scope |
|---|---|
GET /{tenancy}/v1/namespaces | Any member |
POST /{tenancy}/v1/namespaces | Admin |
DELETE /{tenancy}/v1/namespaces/{namespace} | Admin |
{ "slug": "prod", "name": "Production" }The slug is the URL segment. name is for people, and defaults to the slug.
Backends
Created in a namespace, then optionally attached to others.
| Route | Does |
|---|---|
POST /{tenancy}/{namespace}/v1/backends | Create one here |
GET /{tenancy}/{namespace}/v1/backends | List the ones this namespace can route to |
GET /{tenancy}/{namespace}/v1/backends/{backend} | Show one |
POST /{tenancy}/{namespace}/v1/backends/{backend} | Attach an existing backend to this namespace |
DELETE /{tenancy}/{namespace}/v1/backends/{backend} | Detach it from this namespace |
GET /{tenancy}/v1/backends | List every backend in the tenancy |
GET /{tenancy}/v1/backends/{backend}/namespaces | Which namespaces use one |
DELETE /{tenancy}/v1/backends/{backend} | Delete it everywhere |
{
"name": "anthropic-prod",
"kind": "anthropic",
"base_url": null,
"credential": "sk-ant-…"
}kind is openai_compat, anthropic or openrouter — see Routing. base_url may
be omitted where the kind implies it. credential is write-only: it is encrypted before
storage and never appears in any response, so BackendView carries id, name, kind,
base_url and credential_source and nothing else.
The address a backend may name
base_url may name anything by default, including an address inside the deployment's own
network. That is deliberate: a dedicated deployment usually reaches its model provider there.
A deployment configured with CTX_BACKEND_HOSTS=public narrows it. A backend may then only
name an address the internet routes to. The rule is every range the IANA special-purpose
address registries mark as not globally reachable, plus the machine's own name. localhost,
any name under .localhost, an address in a loopback, this-network, private, shared or
link-local range, and a name that resolves to one of those, are each refused with 422 and
code backend_host_refused, and nothing is created. The address is checked again when a call
is made, so a name that starts pointing inside the network later is refused there too. A
deployment serving tenants it does not trust sets it.
A backend that holds no credential
credential_source says where a call through this backend gets its provider credential. It
defaults to stored, which is the shape above. The other value is caller, a backend that
holds no key of its own and forwards the one each submission brought:
{
"name": "anthropic-passthrough",
"kind": "anthropic",
"credential_source": "caller"
}A caller backend takes no credential, and sending both is refused with 422, because a
backend that holds a credential and ignores it is one nobody can reason about.
A caller backend needs the deployment to allow it
Creating one, and submitting to one, are both refused with 422 and code
passthrough_disabled unless the process was started with --credential-passthrough. It is a
process argument rather than a setting, because it decides whose terms the traffic runs under,
and the hosted service does not pass it. Claude Code and the Agent
SDK has what it is for and
Anthropic's position on it.
Note the two deletes. Detaching removes a backend from one namespace; deleting removes it from the tenancy.
Routing rules
All namespace-scoped, and all needing manage on the namespace. An admin or the owner
holds that everywhere; a user holds it where granted. The same layer covers /requests,
/usage, /storage and /execution.
| Route | Does |
|---|---|
POST /{tenancy}/{namespace}/v1/routing-rules | Create |
GET /{tenancy}/{namespace}/v1/routing-rules | List |
DELETE /{tenancy}/{namespace}/v1/routing-rules/{rule} | Delete |
{
"priority": 100,
"pattern": "claude-*",
"backend_id": "…",
"model_rewrite": "claude-sonnet-4-20250514"
}Lowest priority wins. Routing has the semantics.
Members and grants
| Route | Does |
|---|---|
GET /{tenancy}/v1/users | List members |
GET /{tenancy}/v1/users/{user} | One member, with the grants they hold |
POST /{tenancy}/v1/users | Invite one |
POST /{tenancy}/v1/users/{user}/role | Change their standing in the tenancy |
POST /{tenancy}/v1/users/{user}/password | Set their password |
DELETE /{tenancy}/v1/users/{user} | Revoke them |
GET /{tenancy}/v1/namespaces/{namespace}/grants | Who may use this namespace |
POST /{tenancy}/v1/namespaces/{namespace}/grants | Give a member use or manage on it |
DELETE /{tenancy}/v1/namespaces/{namespace}/grants/{user} | Take it back |
An invited member given a password they did not choose must replace it before they can do
anything else — that is the 403 password_change_required in Errors.
Keys
| Route | Does |
|---|---|
POST /{tenancy}/v1/me/keys | Mint one for yourself |
GET /{tenancy}/v1/me/keys | List your own |
DELETE /{tenancy}/v1/me/keys/{key} | End one of your own |
POST /{tenancy}/v1/users/{user}/keys | Mint one for a member (admin) |
GET /{tenancy}/v1/users/{user}/keys | List theirs (admin) |
DELETE /{tenancy}/v1/keys/{key} | Revoke any key (admin) |
Minting answers with the only copy of the secret:
{ "id": "…", "name": "batch-worker", "prefix": "ab12cd34", "key": "sar_ab12cd34_…" }Listing never does — ApiKeyView carries id, name, prefix, created_at and revoked_at.
The secret is stored only as a keyed hash, so a lost key is replaced rather than recovered. The
eight-character prefix is the public half, and it is what usage figures and log lines name a
key by.
Ownership
| Route | Does |
|---|---|
POST /{tenancy}/v1/ownership | Transfer the tenancy to another member |
DELETE /{tenancy}/v1/tenancy | Delete the tenancy |
Both are the owner's alone.

