Skip to content

Overview

The admin API lets you manage lexicons, monitor records, run backfill jobs, and control user access. All endpoints live under /admin and require authentication from a DID that exists in the happyview_users table, with the appropriate permissions for the endpoint being called. You can also manage all of this through the web dashboard.

The admin API supports three authentication methods:

  1. API keys — read/write tokens starting with hv_, passed as Authorization: Bearer hv_.... See the API Keys guide for details.
  2. Cookie-based session auth — signed session cookies set during the dashboard OAuth login flow. The web dashboard uses this method.
  3. App sessions granted dev.happyview.adminFull — an API client’s DPoP session, when the user approved the permission set dev.happyview.adminFull at sign-in. The app asks for it with the scope include:dev.happyview.adminFull. The session then acts with the user’s own permissions.

HappyView decides whether a session was granted the set by what the user’s authorization server says, never by the scope the app registered. On the session’s first admin request it refreshes the session itself, after checking that the user’s PDS names the session’s authorization server, and reads the granted scope from the token response. It reads it again once that access token expires, so revoking the grant at the PDS ends admin access within one token lifetime. Any other API client session is refused with 403 Forbidden, because those sessions belong to apps built on the instance, and an admin signing in to one must not hand it the instance.

hpy, the HappyView CLI, signs in this way through a client every instance has built in: hvc_hpy, which GET /config publishes as cli_client_key. An operator who wants another app to manage the instance registers it with include:dev.happyview.adminFull among its scopes.

In all cases the resolved DID is checked against the happyview_users table, and the user’s permissions are loaded to authorize the request.

An atproto service-auth token is refused with 403 Forbidden, whatever method it names: sign in with an app granted dev.happyview.adminFull, or use an API key.

A hosting platform’s key (PLATFORM_API_KEY_HASH) reaches only Platform, Domains, Stats and Jetstream status.

Auto-bootstrap: If the happyview_users table is empty and SUPERADMIN_DID isn’t set, the first authenticated request makes the caller an operator with the superadmin privilege and every permission.

Non-user DIDs receive a 403 Forbidden response. Users without the required permission for a specific endpoint also receive 403 Forbidden.

Error responses are JSON with an error field:

{
"error": "description of what went wrong"
}

A missing permission names it, and a server error carries an id to find in the server’s log:

{ "error": "InsufficientPermissions", "message": "Missing permission: lexicons:create" }
{ "error": "Internal server error", "correlationId": "…" }
StatusMeaning
400 Bad RequestInvalid input (missing required fields, malformed lexicon JSON)
401 UnauthorizedMissing or invalid credentials
403 ForbiddenThe caller isn’t an operator, lacks the permission, or used a credential the route doesn’t accept
404 Not FoundThe lexicon, user, job or other resource doesn’t exist
409 ConflictThe change conflicts with the current state, such as a lexicon a project file defines
412 Precondition FailedAn If-Match didn’t match, as on Project
413 Payload Too LargeA body over its limit, such as a project bundle
422 Unprocessable EntityWell-formed input that can’t be applied, such as a project that doesn’t build
503 Service UnavailableSomething the request needs isn’t available, such as record storage
Terminal window
# All examples assume $TOKEN is an API key (hv_...)
AUTH="Authorization: Bearer $TOKEN"
GroupDescription
LexiconsUpload, list, get, and delete lexicons and network lexicons
Lexicon PublishingPublish lexicons to the network and manage publishing rules
StatsRecord counts by collection, operator and client counts, Jetstream status
BackfillCreate and monitor historical backfill jobs
JobsList, inspect, cancel, pause and resume background jobs, and read their logs
Event LogsQuery, count and purge the audit trail of system events
API KeysCreate, list, and revoke API keys
UsersCreate, list, update, and delete operators
LabelersManage external labeler subscriptions
RecordsList, delete and reconcile indexed records
ProjectDeploy a project and read what’s deployed
Linked ReposGrant, invite and revoke access to repositories an instance can write to
SpacesBrowse spaces and their records for moderation
Instance SettingsConfigure app name, logo, policy URLs, and concurrency settings
XRPC ProxyDecide whether and where unknown XRPC methods are proxied
TelemetryTelemetry consent, previews and sending
DatabaseDatabase status, SQLite vacuum and record compression
DomainsManage domains and their OAuth client identities
OAuth KeysRotate and revoke the instance’s OAuth client-assertion signing key
ScriptsCreate, list, update, delete and migrate scripts
Script VariablesEncrypted key/value pairs for scripts’ ctx.env
API ClientsRegister and manage third-party XRPC clients
PluginsInstall, configure, and manage plugins
Dead LettersList, inspect, dismiss, retry, and reindex dead-lettered events
Service IdentityGet and update service identity configuration
Service EntriesManage service entries and their XRPC bindings
Verification MethodsCreate, list, and delete DID verification methods
Feature FlagsList feature flag status
PermissionsList available permission definitions
IdentityResolve a handle or DID
PlatformFor a hosting platform: set the operator with superadmin

Each admin API endpoint requires a specific permission. See the Permissions guide for the full list of permissions and templates.

EndpointRequired Permission
POST /admin/lexiconslexicons:create (plus backfill:create to start a backfill)
GET /admin/lexiconslexicons:read
GET /admin/lexicons/{id}lexicons:read
DELETE /admin/lexicons/{id}lexicons:delete
POST /admin/network-lexiconslexicons:create (plus backfill:create to start a backfill)
GET /admin/network-lexiconslexicons:read
DELETE /admin/network-lexicons/{nsid}lexicons:delete
GET /admin/lexicon-publishinglexicons:read
GET /admin/lexicon-publishing/dnslexicons:read
GET /admin/lexicon-publishing/dns/{nsid}lexicons:read
POST /admin/lexicon-publishing/ruleslexicons:publish
PATCH /admin/lexicon-publishing/rules/{id}lexicons:publish
DELETE /admin/lexicon-publishing/rules/{id}lexicons:publish
POST /admin/lexicon-publishing/publishlexicons:publish
POST /admin/lexicon-publishing/unpublishlexicons:publish
GET /admin/statsstats:read, or the platform key
GET /admin/stats/countsstats:read, or the platform key
GET /admin/jetstream/statusstats:read, or the platform key
POST /admin/backfillbackfill:create
GET /admin/backfill/statusbackfill:read
POST /admin/backfill/{id}/cancelbackfill:create
POST /admin/backfill/{id}/pausebackfill:create
POST /admin/backfill/{id}/resumebackfill:create
GET /admin/backfill/{id}/eventsbackfill:read
GET /admin/backfill/{id}/reposbackfill:read
GET /admin/backfill/{id}/pds-summarybackfill:read
GET /admin/backfill/{id}/errorsbackfill:read
POST /admin/backfill/{id}/retry-failedbackfill:create
GET /admin/backfill/collections/{nsid}backfill:read
DELETE /admin/backfill/{id}/detailsbackfill:create
DELETE /admin/backfill/detailsbackfill:create
GET /admin/eventsevents:read
GET /admin/events/countevents:read
POST /admin/events/purgeevents:purge
GET /admin/jobsjobs:read
GET /admin/jobs/{id}jobs:read
GET /admin/jobs/{id}/logsjobs:read
POST /admin/jobs/{id}/canceljobs:manage
POST /admin/jobs/{id}/pausejobs:manage
POST /admin/jobs/{id}/resumejobs:manage
POST /admin/api-keysapi-keys:create
GET /admin/api-keysapi-keys:read
DELETE /admin/api-keys/{id}api-keys:delete
POST /admin/usersusers:create
GET /admin/usersusers:read
GET /admin/users/{id}users:read
PATCH /admin/users/{id}/permissionsusers:update
DELETE /admin/users/{id}users:delete
POST /admin/users/transfer-superSuperadmin only
PUT /admin/platform/super-userThe platform key only
GET /admin/identity/resolveAny operator
PUT /admin/projectproject:deploy
GET /admin/projectproject:deploy
GET /admin/linked-reposlinked-repos:read
POST /admin/linked-reposlinked-repos:create
POST /admin/linked-repos/{id}/authorizelinked-repos:create
POST /admin/linked-repos/{id}/invitelinked-repos:create
GET /admin/linked-repos/{id}/inviteslinked-repos:read
DELETE /admin/linked-repos/{id}/invites/{invite_id}linked-repos:create
DELETE /admin/linked-repos/{id}linked-repos:delete
GET /admin/script-variablesscript-variables:read
POST /admin/script-variablesscript-variables:create
DELETE /admin/script-variables/{key}script-variables:delete
GET /admin/scriptsscripts:read
POST /admin/scriptsscripts:manage
GET /admin/scripts/languagesscripts:read
GET /admin/scripts/{id}scripts:read
PATCH /admin/scripts/{id}scripts:manage
DELETE /admin/scripts/{id}scripts:manage
POST /admin/scripts/{id}/codemodscripts:read to preview, scripts:manage to apply
GET /admin/editor/declarationsscripts:read
POST /admin/labelerslabelers:create
GET /admin/labelerslabelers:read
PATCH /admin/labelers/{did}labelers:create
DELETE /admin/labelers/{did}labelers:delete
GET /admin/recordsrecords:read
GET /admin/records/collectionsrecords:read
DELETE /admin/recordsrecords:delete
DELETE /admin/records/collectionrecords:delete-collection and records:delete
POST /admin/records/collection/reconcilerecords:read for a dry run, records:delete to apply
GET /admin/spacesspaces:read
GET /admin/spaces/{id}spaces:read
GET /admin/spaces/{id}/recordsspaces:manage-records
GET /admin/spaces/{id}/blobspaces:manage-records
GET /admin/spaces/migration-statusspaces:read
GET /admin/database/statussettings:manage
POST /admin/database/vacuum/schedulesettings:manage
DELETE /admin/database/vacuum/schedulesettings:manage
POST /admin/storage/retrainsettings:manage
GET /admin/settingssettings:manage
GET /admin/settings/db-infosettings:manage
PUT /admin/settings/{key}settings:manage
DELETE /admin/settings/{key}settings:manage
PUT /admin/settings/logosettings:manage
DELETE /admin/settings/logosettings:manage
GET /admin/settings/telemetrysettings:manage
PUT /admin/settings/telemetrysettings:manage
POST /admin/settings/telemetry/dismisssettings:manage
GET /admin/settings/telemetry/previewsettings:manage
POST /admin/settings/telemetry/sendsettings:manage
GET /admin/pluginsplugins:read
POST /admin/pluginsplugins:create
POST /admin/plugins/previewplugins:create
GET /admin/plugins/officialplugins:read
DELETE /admin/plugins/{id}plugins:delete
POST /admin/plugins/{id}/reloadplugins:create
POST /admin/plugins/{id}/check-updateplugins:create
GET /admin/plugins/{id}/secretsplugins:read
PUT /admin/plugins/{id}/secretsplugins:create
GET /admin/plugins/{id}/allowed-hostsplugins:read
PUT /admin/plugins/{id}/allowed-hostsplugins:create
GET /admin/domainssettings:manage, or the platform key
POST /admin/domainssettings:manage, or the platform key; only the platform key on an instance it manages
DELETE /admin/domains/{id}settings:manage, or the platform key; only the platform key on an instance it manages
POST /admin/domains/{id}/primarysettings:manage, or the platform key; only the platform key on an instance it manages
GET /admin/oauth/instance-keysettings:manage
POST /admin/oauth/instance-key/rotatesettings:manage
DELETE /admin/oauth/instance-key/{kid}settings:manage
GET /admin/api-clientsapi-clients:view
POST /admin/api-clientsapi-clients:create
GET /admin/api-clients/{id}api-clients:view
PUT /admin/api-clients/{id}api-clients:edit
DELETE /admin/api-clients/{id}api-clients:delete
POST /admin/api-clients/{id}/auth-keyapi-clients:edit
GET /admin/api-clients/{id}/auth-keyapi-clients:view
GET /admin/api-clients/{id}/auth-keysapi-clients:view
POST /admin/api-clients/{id}/auth-key/recheckapi-clients:edit
POST /admin/api-clients/{id}/auth-key/rotateapi-clients:edit
DELETE /admin/api-clients/{id}/auth-key/{kid}api-clients:edit
DELETE /admin/api-clients/{id}/auth-keysapi-clients:edit
GET /admin/dead-lettersdead-letters:read
GET /admin/dead-letters/countdead-letters:read
GET /admin/dead-letters/{id}dead-letters:read
POST /admin/dead-letters/{id}/dismissdead-letters:manage
POST /admin/dead-letters/{id}/retrydead-letters:manage
POST /admin/dead-letters/{id}/reindexdead-letters:manage
POST /admin/dead-letters/bulk/dismissdead-letters:manage
POST /admin/dead-letters/bulk/retrydead-letters:manage
POST /admin/dead-letters/bulk/reindexdead-letters:manage
GET /admin/service-identitysettings:manage
PUT /admin/service-identitysettings:manage
GET /admin/service-entriessettings:manage
POST /admin/service-entriessettings:manage
PUT /admin/service-entries/{id}settings:manage
DELETE /admin/service-entries/{id}settings:manage
GET /admin/service-entries/{id}/xrpcssettings:manage
POST /admin/service-entries/{id}/xrpcssettings:manage
DELETE /admin/service-entries/{id}/xrpcssettings:manage
POST /admin/service-entries/sync-plcsettings:manage
POST /admin/service-entries/sync-plc/requestsettings:manage
POST /admin/service-entries/sync-plc/submitsettings:manage
GET /admin/lexicons/{id}/servicessettings:manage
GET /admin/verification-methodssettings:manage
POST /admin/verification-methodssettings:manage
DELETE /admin/verification-methods/{fragment_id}settings:manage
GET /admin/feature-flagssettings:manage
GET /admin/network-lexicons/resolve/{nsid}lexicons:read
GET /admin/permissionsusers:read
GET /admin/settings/xrpc-proxysettings:manage
PUT /admin/settings/xrpc-proxysettings:manage