Console and admin API
Every endpoint of the customer console API (/v1/account, /v1/console) and the private operator admin API (/v1/admin), with their OpenAPI contracts.
Everything the console at /app does goes through a JSON API you can call yourself. The contracts are OpenAPI 3.1 documents, checked by the test suite against the registered routes and real responses:
- /docs/openapi-console.yaml: the account and console API, for customers;
- /docs/openapi-admin.yaml: the operator admin API.
Errors are {"error": "<code>", "message": "…"}; the codes are on Error codes.
Authentication
- Console.
POST /v1/account/loginsets theag_accountsession cookie (HttpOnly, SameSite=Lax, Secure over TLS; 12 hours, or 2 hours without use).GET /v1/account/sessionreturns the signed-in user, the customer and a CSRF token; send it asX-CSRF-Tokenon every request that changes something. Requests from other sites are refused (cross_origin). - Two-factor authentication. With 2FA on,
loginanswers{"mfaRequired": true}and a 5-minute pre-session;POST /v1/account/login/mfawith the code from the authenticator app (or a recovery code) completes the sign-in. An account can require 2FA of all its members; members without it get403 mfa_setup_requiredon the console until they turn it on. - API tokens. For scripts and CI, create a token under API tokens and send
Authorization: Bearer agt_…to/v1/console/*(no CSRF token). A token is limited to its scopes (sites:read,sites:write,analytics:read,members:read) and never works on/v1/accountor/v1/admin. - Admin. The admin API is private: the public host answers
404for/v1/admin/. Operators reach it on a private network or through an SSH tunnel, sign in with the operator key (POST /v1/admin/login, cookieag_admin) and sendX-CSRF-Tokenon changes. - Operator and customer sessions never unlock each other's APIs. A customer sees only its own sites; another customer's site key answers
404. - Accounts and roles. A user can belong to several accounts; the session works in one at a time (the active account, changed with
POST /v1/account/switch). In each account the user has a role:owner,admin,memberorreadonly. Every console route needs a permission of that role:sites:read,sites:write,analytics:read,members:read,members:write,tokens:write,account:write,account:deleteoraudit:read. A missing one answers403 forbiddenand names it. A suspended account answers403 account_suspended(its sites keep protecting), a suspended user403 user_suspended.
| Role | Permissions |
|---|---|
owner | all, including account:delete (delete the account, transfer ownership) |
admin | everything else: sites, analytics, members, tokens, account settings, audit log |
member | sites:read, sites:write, analytics:read, members:read |
readonly | sites:read, analytics:read, members:read |
Account
| Method | Path | Summary |
|---|---|---|
POST | /v1/account/request-access | Ask for an account; the same answer whether or not the address is known |
POST | /v1/account/login | Sign in; sets ag_account |
POST | /v1/account/logout | End the session |
GET | /v1/account/session | The signed-in user, their accounts, the active account with role, limits and permissions, and the CSRF token |
POST | /v1/account/switch | Make another of the user's accounts the active one |
POST | /v1/account/accounts | Create another account, owned by the caller (at most 3 owned) |
GET | /v1/account/invite/{token} | Who an invite link is for, without using it |
POST | /v1/account/invite/accept | Set the first password with an invite link (single use, 7 days) and sign in |
POST | /v1/account/password/forgot | Email a reset link (1 hour) if an account uses the address; always 202 |
POST | /v1/account/password/reset | Set a new password with a reset link; ends the user's other sessions and signs in |
POST | /v1/account/login/mfa | Complete a sign-in with a 2FA code or a recovery code |
GET | /v1/account/mfa | Your 2FA state and whether the account requires it |
POST | /v1/account/mfa/setup | Start 2FA setup: a TOTP secret and an otpauth:// URL for a QR code |
POST | /v1/account/mfa/enable | Turn 2FA on with a code; returns 10 single-use recovery codes once |
POST | /v1/account/mfa/disable | Turn 2FA off (password and a code or recovery code) |
POST | /v1/account/password | Change your password; ends your other sessions |
GET | /v1/account/sessions | Your signed-in sessions (browser, pseudonymous address) |
DELETE | /v1/account/sessions/{id} | End one session |
POST | /v1/account/sessions/revoke-others | End every session but this one |
Console
| Method | Path | Summary |
|---|---|---|
GET | /v1/console/account | The active account: name, status, limits and usage |
PATCH | /v1/console/account | Rename the account (account:write) |
DELETE | /v1/console/account | Delete the account (owner; type its name to confirm; no site may enforce); data is purged after 30 days |
POST | /v1/console/account/transfer-ownership | Make another member the owner; the caller becomes an admin |
GET | /v1/console/members | The account's members with role, status and last sign-in |
POST | /v1/console/members | Invite someone by email with a role (members:write) |
PATCH | /v1/console/members/{userId} | Change a member's role (only owners change owners; never the last owner) |
DELETE | /v1/console/members/{userId} | Remove a member (never the last owner) |
POST | /v1/console/members/{userId}/resend-invite | Email a fresh invite link to a member who has not set a password |
GET | /v1/console/audit | The account's audit log: members, roles, sites, credentials, limits, status, sign-ins |
GET | /v1/console/sites | The customer's sites |
POST | /v1/console/sites | Add a site (monitor mode, widget mode invisible unless given); siteKey, customerId and customerName are refused; default action submit; at most 10 allowed origins (400 origin_limit) |
GET | /v1/console/sites/{siteKey} | A site with credentials, changes and rules summary |
PATCH | /v1/console/sites/{siteKey} | Change name, origins (at most 10), actions, routes, mode or widget mode |
GET | /v1/console/sites/{siteKey}/changes | The site's audit trail |
POST | /v1/console/sites/{siteKey}/credentials | A backend credential, shown once (at most 3 live per site) |
POST | /v1/console/sites/{siteKey}/credentials/{credId}/rotate | Replace a credential; the old one works for overlapSeconds |
POST | /v1/console/sites/{siteKey}/credentials/{credId}/revoke | Revoke a credential now |
GET | /v1/console/sites/{siteKey}/rules | The site's rule set and overrides |
PUT | /v1/console/sites/{siteKey}/rules | Replace the site's rules or overrides |
POST | /v1/console/sites/{siteKey}/rules/validate | Check rules without saving |
GET | /v1/console/sites/{siteKey}/install | waiting until AgentGate sees a decision for the site, then live |
GET | /v1/console/sites/{siteKey}/health | Integration health over the last 24 hours: is the server verifying tokens, is traffic arriving, are pages on unlisted origins, are siteverify calls failing |
GET | /v1/console/sites/{siteKey}/analytics | Challenge outcomes, solve rate, solve types, token validation and top lists (default: last 24 hours) |
GET | /v1/console/sites/{siteKey}/agent-prompt | A setup prompt for a coding agent (text/markdown): site key, endpoint contract, AGENTGATE_SECRET from the environment (never the secret), checklist |
GET | /v1/console/managed-groups | The managed rule-group catalog (read-only, the same for every account): what each group reference in a rule set expands to |
GET | /v1/console/metrics | Daily counts, challenges, latency (errors.eventWriteFailures is always 0 here: it is process-wide) |
GET | /v1/console/decisions | Decisions, newest first (same filters as the admin API) |
GET | /v1/console/decisions/{decisionId} | One decision with its labels and rule (no trace link) |
GET | /v1/console/visitors | Pseudonymous request sources |
GET | /v1/console/visitors/{visitorId} | One source and its recent decisions |
GET | /v1/console/tokens | The account's API tokens (never the secrets) |
POST | /v1/console/tokens | Create an API token with scopes and an optional expiry; the secret is shown once |
DELETE | /v1/console/tokens/{id} | Revoke an API token now |
Limits are per account: by default 5 sites, 3 live backend secrets per site, 10 members and 25 live API tokens (GET /v1/console/account shows them and the usage). New sites start in monitor mode with one browser-checked action, submit.
Admin (private)
| Method | Path | Summary |
|---|---|---|
POST | /v1/admin/login | Exchange the operator credential (ADMIN_KEY) for a session cookie |
POST | /v1/admin/logout | End the session |
GET | /v1/admin/session | The current operator and the CSRF token for mutations |
GET | /v1/admin/sites | Every site with today's traffic and integration health |
POST | /v1/admin/sites | Create a site (monitor mode unless mode is given) |
GET | /v1/admin/sites/{siteKey} | Site detail with credentials, recent changes and rules summary |
PATCH | /v1/admin/sites/{siteKey} | Change name, origins, actions, routes or mode |
GET | /v1/admin/sites/{siteKey}/changes | The site's configuration audit trail, newest first |
POST | /v1/admin/sites/{siteKey}/credentials | Create a backend credential; the secret is returned once |
POST | /v1/admin/sites/{siteKey}/credentials/{credId}/rotate | Create a replacement; the old credential works for overlapSeconds (default 86400, at most 7 days) |
POST | /v1/admin/sites/{siteKey}/credentials/{credId}/revoke | Revoke immediately |
GET | /v1/admin/sites/{siteKey}/rules | The site's base rule set, per-rule overrides and effective rule set |
PUT | /v1/admin/sites/{siteKey}/rules | Replace the site's rule configuration |
POST | /v1/admin/sites/{siteKey}/rules/validate | Validate without storing; errors carry line and column for ruleSetText |
GET | /v1/admin/managed-groups | Every registered managed rule group version and its member rules |
GET | /v1/admin/metrics | Overview counts and a bucketed series for a time range |
GET | /v1/admin/visitors | Pseudonymous request sources, most recently seen first |
GET | /v1/admin/visitors/{visitorId} | One source's summary and its 50 newest decisions (default range: 31 days) |
GET | /v1/admin/decisions | Decisions, newest first, with filters |
GET | /v1/admin/decisions/{decisionId} | Why: labels grouped by source, matched rule, scores, versions, would-decision, trace |
PUT | /v1/admin/decisions/{decisionId}/label | Label a decision human, bot, agent or unsure for the model loop |
GET | /v1/admin/labels | Export operator labels in update order (oldest first) for training |
POST | /v1/admin/labels | Label a decision (by decision or request ID) with a source, for probes and scripts |
GET | /v1/admin/sites/{site}/feature-capture | Whether the site stores model feature vectors (never content) and for how long |
PUT | /v1/admin/sites/{site}/feature-capture | Opt in or out of feature capture; opting out deletes the site's vectors |
GET | /v1/admin/models | Active, candidate and previous model per kind (agent, bot, content) |
GET | /v1/admin/models/{kind}/{role} | A model file (weights and metadata) |
PUT | /v1/admin/models/{kind}/{role} | Load a candidate model; it scores traffic in shadow without affecting decisions |
DELETE | /v1/admin/models/{kind}/{role} | Stop shadow scoring |
GET | /v1/admin/models/{kind}/compare | Candidate vs active on recent traffic: agreement, would-change counts, per-label rates |
POST | /v1/admin/models/{kind}/promote | Make the candidate active (recorded in config_changes; survives restarts) |
POST | /v1/admin/models/{kind}/rollback | Restore the previous active model |
GET | /v1/admin/sites/{siteKey}/install | Whether AgentGate has seen traffic for the site (the add-site wizard's install check) |
GET | /v1/admin/sites/{siteKey}/health | Integration health: typed checks over the last 24 hours |
GET | /v1/admin/sites/{siteKey}/analytics | Challenge outcomes, solve types, token validation and top lists for a range |
GET | /v1/admin/sites/{siteKey}/agent-prompt | A self-contained setup prompt for a coding agent (Markdown) |
GET | /v1/admin/access-requests | Access requests from /signup, newest first |
POST | /v1/admin/access-requests/{id}/approve | Create the customer (named by company, else name), the user and a 7-day invite link; email the link |
POST | /v1/admin/access-requests/{id}/decline | Decline a pending request (no email is sent) |
GET | /v1/admin/customers | Accounts with owner, member and site counts, status, limits and last activity (status, q filters) |
GET | /v1/admin/customers/{id} | One account: members, sites with health, API tokens, limits, usage, recent audit events |
PATCH | /v1/admin/customers/{id} | Rename an account or change its limits |
DELETE | /v1/admin/customers/{id} | Delete an account (same rules as the owner's) |
POST | /v1/admin/customers/{id}/suspend | Suspend: console and API closed, sites keep protecting |
POST | /v1/admin/customers/{id}/reactivate | Lift a suspension, or restore a deleted account within 30 days |
POST | /v1/admin/customers/{id}/sites | Create a site in the account |
POST | /v1/admin/customers/{id}/members | Add someone to the account with a role; returns an invite link for a new user |
PATCH | /v1/admin/customers/{id}/members/{userId} | Change a member's role |
DELETE | /v1/admin/customers/{id}/members/{userId} | Remove a member |
POST | /v1/admin/customers/{id}/members/{userId}/resend-invite | A fresh invite link for a member without a password |
GET | /v1/admin/customers/{id}/audit | The account's audit log |
DELETE | /v1/admin/customers/{id}/tokens/{tokenId} | Revoke one of the account's API tokens |
POST | /v1/admin/sites/{siteKey}/move | Move a site to another account |
POST | /v1/admin/users/{userId}/suspend | Suspend a user everywhere; their sessions end |
POST | /v1/admin/users/{userId}/reactivate | Lift a user's suspension |
POST | /v1/admin/users/{userId}/reset-link | A one-hour password reset link, also emailed |
POST | /v1/admin/users/{userId}/mfa/reset | Turn a user's 2FA off (lost authenticator) |
GET | /v1/admin/accounts | Customer users with their accounts and roles |
POST | /v1/admin/accounts | Invite a user directly (a new customer, or customerId to add a teammate) |
GET | /v1/admin/outbox | Messages the service sent or will send, newest first; bodies hold one-time links |
GET | /v1/admin/docs-feedback | "Was this helpful?" answers on the public docs, counted per page (most answered first) |
Public endpoints
These need no session; they are documented on their own pages.
| Method | Path | Page |
|---|---|---|
GET | /sdk/v1/agentgate.js, /sdk/v1/worker.js | Widget configuration |
POST | /v1/browser/challenge, /v1/browser/verify; GET /v1/browser/instrument | How the check works |
POST | /v1/siteverify | Validate tokens |
GET | /v1/gateway/check | Gateway overview |
POST | /agent/submit | Sign requests |
GET | /.well-known/agentgate-tools.json, /v1/agent-tools/{siteKey} | Declared tools |
GET | /v1/handoff/{id} | Human handoff |
GET | /.well-known/agentgate-keys.json; POST /v1/receipts/verify | Signed receipts |
POST | /v1/docs/feedback | the "Was this helpful?" buttons on these pages |
GET | /healthz, /readyz | liveness and readiness: /readyz answers 200 while AgentGate can decide (ready, or degraded when only optional data such as threat intelligence is missing) and 503 with Retry-After: 5 when it cannot |