Admin API
Mounted under /admin/api. Authenticated by the console session cookie or by an MCP-audience bearer token; both resolve to the same administrator context and the same permission checks.
Reads
| Route | What it returns |
|---|---|
GET /admin/api/me | The administrator this agent is acting as: their id, email, roles, and the projects they manage. |
GET /admin/api/projects | Every project a super-administrator can see, or just the projects the caller manages. |
GET /admin/api/projects/:id | One project: name, slug, managers, assigned user bucket, client ids, and CORS origins. |
GET /admin/api/projects/:id/clients | The OAuth clients registered in a project. Never returns a client secret. |
GET /admin/api/projects/:id/clients/:clientId | One OAuth client: redirect URIs, grant types, auth method, and other registered metadata. Never returns its secret — a secret is shown once at creation or rotation and is not readable afterwards. |
GET /admin/api/admins | The administrator accounts of this instance, with their roles. |
GET /admin/api/admins/settings | The sign-in policy of the administrator bucket itself. `totpRequired` says whether signing in to the console also needs a one-time code from an authenticator app. The bucket's other settings are deliberately not exposed. |
GET /admin/api/groups | The groups this administrator belongs to. A group owns projects and user buckets, and belonging to it is what grants access to them. |
GET /admin/api/groups/:id | One group: its name, kind, and the administrators in it with their membership kind. A plain member may read this; only an owner may change it. |
GET /admin/api/groups/:id/invitations | Pending invitations into a group. Never returns an invitation token — a token exists only in the mail it was sent in. |
GET /admin/api/scope | The console's active group and the groups available to switch to. An agent has no console session: name a group per call instead of switching. |
GET /admin/api/buckets | The user buckets: every one for a super-administrator, otherwise those the caller manages. The reserved administrator bucket is never listed. |
GET /admin/api/buckets/:id | One user bucket: its name, roles, managers, and registration and verification settings. |
GET /admin/api/buckets/:id/users | The end-user accounts held in one bucket. |
GET /admin/api/buckets/:id/federation | The upstream identity providers configured on a bucket. Never returns a provider client secret. |
GET /admin/api/buckets/:id/users/:uid/identities | The upstream identities linked to one end-user account, by provider. |
GET /admin/api/settings | The editable server settings, with the catalogue describing each one and its current value. |
GET /admin/api/settings/smtp | The outbound mail settings. The password is never returned, only whether one is set. |
GET /admin/api/settings/sentry | The Sentry integration settings. The ingestion credential is never returned, only whether one is set. |
GET /admin/api/jwks | The signing keys, each with its status, plus whether a restart is needed to apply pending changes. Public key material only — private components are never returned. |
GET /admin/api/audit | The administrative audit trail for the groups this administrator belongs to, newest first, filterable by actor, action, target, surface and time window. A super administrator sees the whole instance, including actions that belong to no group. Filter `viaSurface=mcp` for actions taken through an agent. An entry means an authorized actor reached the point of applying a change, not that the change took effect. |
GET /admin/api/errors | Recorded internal server faults, newest first, one entry per distinct fault with an exact occurrence count. Filterable by error code, route, surface, status, client, actor and time window. Only defects are recorded — routine client rejections such as a bad grant or a wrong password never appear. A non-zero `dropped` means recording fell behind and the list is incomplete. |
GET /admin/api/errors/summary | How much is failing over a time window, broken down by error code and by endpoint, most frequent first. Counts sum occurrences rather than distinct faults, so one fault seen 900 times outranks nine seen once. Takes a window only — use error_list to filter by client, actor, status or surface. |
GET /admin/api/errors/purge-preview | How many recorded faults, and how many occurrences, a purge with these filters would remove. Reads only — nothing is deleted. Available whether or not this deployment lets an agent perform the purge itself, because reading the consequence of a deletion is not destructive. |
GET /admin/api/errors/reference/:reference | Resolve the reference identifier a caller reported (it looks like err_XXXXXXXXXXXXXXXX) to the one fault it belongs to, and which occurrence it was. Answers not-found rather than an empty result, so a mistyped reference is distinguishable from a record that has aged out. |
GET /admin/api/errors/:id | One recorded fault with its retained samples: where it arose, how often, when first and last seen. Samples are capped, so a very frequent fault keeps its earliest and its most recent occurrences while the count stays exact. No credential value is ever stored, so none can be read here. |
Mutations (audited)
Every route below writes an append-only audit entry naming the actor, the action and the target before the change is made.
| Route | Audit action | Target | Summary |
|---|---|---|---|
POST /admin/api/setup | setup.bootstrap | AdminUser | Console-only; see below. |
POST /admin/api/projects | project.create | Project | Create a project: the container an instance groups OAuth clients into, with its own managers and CORS origins. A project has no user bucket until one is assigned. |
PATCH /admin/api/projects/:id | project.update | Project | Change a project's name, managers, or CORS origins. An invalid origin refuses the whole list rather than applying part of it. |
DELETE /admin/api/projects/:id | project.delete | Project | Console-only; see below. |
PUT /admin/api/projects/:id/bucket | project.bucket.assign | Project | Assign the user bucket whose accounts this project’s clients authenticate against. |
POST /admin/api/projects/:id/clients | client.create | Client | Register an OAuth client in a project. A confidential client’s generated secret is returned exactly once, here, and is never readable again. |
PATCH /admin/api/projects/:id/clients/:clientId | client.update | Client | Change a client's registered metadata — redirect URIs, grant types, and the rest. |
POST /admin/api/projects/:id/clients/:clientId/secret | client.secret.rotate | Client | Issue a new secret for a confidential client and invalidate the old one. The new secret is returned exactly once. Anything still using the old secret stops working immediately. |
DELETE /admin/api/projects/:id/clients/:clientId | client.delete | Client | Permanently delete an OAuth client and revoke what was issued to it. Irreversible. |
PATCH /admin/api/admins/settings | admin.settings.update | UserBucket | Require a one-time authenticator code for signing in to the administration console, on top of the password. Applies to every administrator; anyone without an authenticator sets one up at their next sign-in, so nobody is locked out. This also covers an agent obtaining a token interactively through the console's own client, so expect to supply a code. |
POST /admin/api/admins | admin.create | AdminUser | Create an administrator account. |
PATCH /admin/api/admins/:id | admin.update | AdminUser | Change an administrator's roles or details. |
DELETE /admin/api/admins/:id | admin.deactivate | AdminUser | Deactivate an administrator: the account is kept but can no longer sign in. Refused for the last active super-administrator. |
POST /admin/api/groups | group.create | Group | Create a group. The administrator this agent acts for becomes its first owner — a group with no owner would be unreachable the instant it existed. |
PATCH /admin/api/groups/:id | group.update | Group | Rename a group, or clear the review flag the ownership migration set on it. Requires being an owner of that group, which is a membership kind rather than an instance role. |
DELETE /admin/api/groups/:id | group.delete | Group | Console-only; see below. |
POST /admin/api/groups/:id/members | group.member.add | Group | Add an existing administrator to a group as an owner or a plain member. This grants them everything the group owns, in one call. Owner-only. |
PATCH /admin/api/groups/:id/members/:userId | group.member.update | Group | Promote a member to owner or demote an owner to member. The last owner can be neither demoted nor removed. Owner-only. |
DELETE /admin/api/groups/:id/members/:userId | group.member.remove | Group | Remove an administrator from a group. They lose access to every project, bucket and end-user the group owns, on their very next request. The last owner cannot be removed. Owner-only. |
POST /admin/api/groups/:id/invitations | invitation.create | Group | Invite somebody into a group by email, as an owner or a plain member. Creates an administrator account for them when they accept, if the address has none. Owner-only. |
DELETE /admin/api/groups/:id/invitations/:inviteId | invitation.revoke | Group | Withdraw a pending invitation before it is accepted. Owner-only. |
POST /admin/api/invitations/accept | invitation.accept | Group | Console-only; see below. |
POST /admin/api/buckets | bucket.create | UserBucket | Create a user bucket. A bucket cannot be created unreachable: at creation it has no providers, so password login cannot be switched off. `totpRequired` makes a password sign-in also require a one-time code from an authenticator app; it governs password sign-in only and never gates a federated one. |
PATCH /admin/api/buckets/:id | bucket.update | UserBucket | Change a bucket's name, roles, managers, or its registration, verification and second-factor settings. Editing the bucket entity needs manager access to the bucket itself, not merely to a project it backs. `totpRequired` governs password sign-in only — it is accepted but inert while `passwordLogin` is off, and it never gates a federated sign-in, so it is not a way to secure a bucket that signs in through an upstream provider. |
DELETE /admin/api/buckets/:id | bucket.delete | UserBucket | Console-only; see below. |
POST /admin/api/buckets/:id/users | enduser.create | EndUser | Create an end-user account in a bucket. |
PATCH /admin/api/buckets/:id/users/:uid | enduser.update | EndUser | Change an end-user's email, roles, active state, or claims. Deactivating is a sign-in decision, not a deletion. |
POST /admin/api/buckets/:id/users/:uid/password | enduser.password.reset | EndUser | Replace an end-user's password. The previous one is unrecoverable and the account holder is not asked. |
DELETE /admin/api/buckets/:id/users/:uid/totp | enduser.totp.clear | EndUser | Clear an end-user's authenticator enrolment. Their existing authenticator stops working at once and their sessions end; they set a new one up at their next sign-in. Use when someone has lost the device holding their codes. Their password, grants and tokens are untouched. |
DELETE /admin/api/buckets/:id/users/:uid | enduser.delete | EndUser | Permanently delete an end-user account and everything issued to it. Irreversible. |
POST /admin/api/buckets/:id/federation | federation.provider.create | UserBucket | Configure an upstream identity provider on a bucket. Available whether or not federation is switched on, so a provider can be prepared first. |
PATCH /admin/api/buckets/:id/federation/:providerId | federation.provider.update | UserBucket | Change an upstream provider's configuration, or enable/disable it. |
DELETE /admin/api/buckets/:id/federation/:providerId | federation.provider.delete | UserBucket | Remove an upstream identity provider from a bucket. Deliberately available even with federation switched off, so a deployment can delete a provider it no longer trusts. Users who signed in only through it lose that route in. |
DELETE /admin/api/buckets/:id/users/:uid/identities/:providerId | federation.identity.delete | EndUser | Sever one end-user's link to one upstream provider. The account survives; only the link is removed. |
POST /admin/api/jwks | jwks.generate | jwks | Generate a new RSA signing key. Takes effect for signing only after a restart; the key is published immediately so verifiers can pick it up first. |
DELETE /admin/api/jwks/:kid | jwks.delete | jwks | Delete a signing key. Refused if it would leave no signing key. Tokens already signed with it stop verifying once it is gone. |
PUT /admin/api/settings | settings.update | ApplicationConfig | Change server settings. The merged configuration is validated first, so a combination the server would refuse at boot is refused here instead of taking the instance down on restart. Most changes apply only after a restart, and the result says so. |
PUT /admin/api/settings/smtp | smtp.settings.update | SmtpSettings | Change the outbound mail settings. The password is write-only: it can be set but never read back. |
PUT /admin/api/settings/sentry | sentry.settings.update | ApplicationConfig | Change where recorded faults are reported. The ingestion credential is write-only: it can be set but never read back, and sending the mask keeps the stored one. Enabling this requires the error store, because the outbound event is built from the internal record. Applies after a restart. |
DELETE /admin/api/errors | error.purge | ErrorRecord | Console-only; see below. |
Console-only operations
POST /admin/api/setup— First-run setup runs when no administrator exists yet, so there is nobody who could authorize an agent to perform it. Console-only.POST /admin/api/invitations/accept— Unauthenticated, and completed by the invited person following a link in their own mail. There is no agent principal to accept as — the same reason first-run setup is inapplicable.POST /admin/api/logout— Ends a browser session, which an agent connection does not have. Session lifecycle, not a change to a managed entity.PUT /admin/api/scope— Points a browser console at one of the groups it may administer, and an agent connection has no session to hold that choice. Name the group in each call instead.DELETE /admin/api/projects/:id— Deleting a project destroys a container of clients with nothing left afterwards to inspect or restore. Withheld from agents by operator decision — delete it in the admin console instead.DELETE /admin/api/buckets/:id— Deleting a user bucket destroys a container of end-user accounts with nothing left afterwards to inspect or restore. Withheld from agents by operator decision — delete it in the admin console instead.DELETE /admin/api/groups/:id— Deleting a group destroys the owner of whatever it held, and with it the only thing that granted anyone access — the same class as the two container deletions above. Withheld from agents by operator decision; delete it in the admin console instead.DELETE /admin/api/errors— Purging recorded faults destroys the only account of what went wrong, and cannot be undone. Withheld from agents — purge them in the admin console instead. Use error_purge_preview to see what a purge would remove.