Skip to content

Permissions

HappyView uses a granular permission system to control access to the admin API. Each user has a set of permissions that determine which endpoints they can access. Permissions can be assigned individually, via templates, or both.

HappyView defines 51 permissions organized by category:

PermissionDescription
lexicons:createUpload and register new lexicon schemas
lexicons:readView registered lexicon schemas
lexicons:deleteRemove lexicon schemas
lexicons:publishPublish lexicons to the network and manage publishing rules
PermissionDescription
records:readBrowse indexed atproto records
records:deleteDelete individual records from the index
records:delete-collectionBulk-delete all records in a collection
PermissionDescription
scripts:readView trigger-keyed scripts
scripts:manageCreate, update, and delete trigger-keyed scripts
PermissionDescription
script-variables:createAdd or update environment variables for Lua scripts
script-variables:readView script environment variable keys and values
script-variables:deleteRemove script environment variables
PermissionDescription
users:createAdd new dashboard users
users:readView the user list and their permissions
users:updateModify user permissions
users:deleteRemove dashboard users
PermissionDescription
api-keys:createGenerate new API keys for admin access
api-keys:readView existing API keys
api-keys:deleteRevoke existing API keys
PermissionDescription
backfill:createTrigger historical record backfill jobs
backfill:readView backfill job status and progress
PermissionDescription
labelers:createSubscribe to external labeler services
labelers:readView subscribed labeler services
labelers:deleteUnsubscribe from labeler services
PermissionDescription
settings:manageModify instance settings, logo, and configuration
PermissionDescription
plugins:readView installed plugins and their configuration
plugins:createInstall and configure new plugins
plugins:deleteUninstall plugins
PermissionDescription
api-clients:viewView registered OAuth API clients
api-clients:createRegister new OAuth API clients
api-clients:editModify API client settings and credentials
api-clients:deleteRemove registered API clients
PermissionDescription
dead-letters:readView failed hook executions
dead-letters:manageRetry, re-index, or dismiss dead letters
PermissionDescription
spaces:createCreate new permissioned data spaces
spaces:readView space details, metadata, and members
spaces:updateModify space settings
spaces:deleteRemove spaces and their data
spaces:manage-membersAdd or remove space members and roles
spaces:manage-invitesCreate and revoke space invitations
spaces:manage-recordsRead and write records within spaces
spaces:manage-credentialsIssue and revoke space access credentials
PermissionDescription
jobs:readView background job status and progress
jobs:createQueue new background jobs
jobs:manageCancel, pause, and resume background jobs
PermissionDescription
linked-repos:readView linked repos, their status, and their outstanding invites
linked-repos:createAdd linked repos, start authorizations, mint and revoke invites
linked-repos:deleteRevoke linked repos and delete their stored sessions

Revoking an invite uses linked-repos:create rather than linked-repos:delete, because minting and revoking are one lifecycle. linked-repos:delete is reserved for destroying a grant and the OAuth session behind it. See Linked Repos.

PermissionDescription
project:deployReplace the instance’s project with a deployed bundle and start the backfills it declares

It also covers reading what is deployed. A deploy can add, change and remove every lexicon and script the project owns, so it is as strong as lexicons:create, lexicons:delete and scripts:manage together, plus backfill:create for the backfills a project declares. See Project.

PermissionDescription
stats:readView collection statistics and record counts
events:readView the event log
events:purgeBulk-delete event log entries matching a filter

Templates are predefined sets of permissions that simplify adding an operator. Pass a template value when creating one via POST /admin/users. A template is named after a level of access, not a kind of person: every one of them is given to an operator, including the Operator template.

Read-only access. Can browse lexicons, records, scripts, stats, events, dead letters, and user lists but cannot modify anything.

Includes: lexicons:read, records:read, scripts:read, script-variables:read, users:read, api-keys:read, backfill:read, stats:read, events:read, dead-letters:read

Everything in the Viewer template, plus the ability to run backfill jobs, manage API keys, and manage dead letters.

Adds: backfill:create, api-keys:create, api-keys:delete, dead-letters:manage

Everything in the Operator template, plus the ability to manage and publish lexicons, records, scripts, labelers, settings, plugins, API clients, and spaces, and to deploy the project.

Adds: lexicons:create, lexicons:delete, lexicons:publish, scripts:manage, project:deploy, script-variables:create, script-variables:delete, records:delete, labelers:create, labelers:read, labelers:delete, settings:manage, plugins:read, plugins:create, plugins:delete, api-clients:view, api-clients:create, api-clients:edit, api-clients:delete, spaces:create, spaces:read, spaces:update, spaces:delete, spaces:manage-members, spaces:manage-invites, spaces:manage-records, spaces:manage-credentials

All 52 permissions. Equivalent to granting every permission individually (but still not superadmin).

Superadmin is a privilege one operator holds. On a fresh instance, the first person to sign in becomes an operator with it, unless SUPERADMIN_DID names someone else. The dashboard marks that operator Owner. The operator with superadmin:

  • Has unrestricted access to all endpoints, regardless of which permissions are assigned
  • Is the only operator who can call POST /admin/users/transfer-super
  • Cannot be deleted
  • Cannot have their permissions modified by other operators

Usually one operator holds superadmin. A transfer, from the dashboard or the transfer endpoint in the Admin API, moves it to another operator and takes it from the previous holder. SUPERADMIN_DID only adds: the configured account gets superadmin at every boot, and anyone else who holds it keeps it.

HappyView prevents privilege escalation:

  • When creating a user or API key, you can only grant permissions that you yourself have. Attempting to grant a permission you lack returns 403 Forbidden.
  • When updating a user’s permissions, the same rule applies — you cannot grant permissions beyond your own.

Users cannot modify their own account in destructive ways:

  • You cannot delete yourself
  • You cannot revoke your own permissions

These guards prevent accidental lockout.

API keys have their own set of permissions, specified at creation time. The effective permissions of an API key are the intersection of:

  1. The permissions assigned to the key
  2. The permissions of the user who owns the key

This means if a user’s permissions are later reduced, any API keys they created are also effectively reduced — even though the key’s own permission list doesn’t change.

For example, if a user with lexicons:create and lexicons:read creates a key with both permissions, and the user later loses lexicons:create, the key can only use lexicons:read.

Go to Access > Users to view and manage user permissions. Click on a user to see their current permissions and modify them. You can also assign templates when creating new users.

  • POST /admin/users — create a user with a template or explicit permissions
  • PATCH /admin/users/{id}/permissions — grant or revoke individual permissions
  • POST /admin/users/transfer-super — pass superadmin to another operator (superadmin only)

See the Admin API — Users for full details.