Scopes & Permissions
The permission system that governs sessions, Personal Access Tokens, and OAuth clients — and how to pick the right scopes for your integration
6 min readEvery authenticated request carries a permission set. Sessions get the full set of user-facing
permissions; Personal Access Tokens (PATs) and OAuth client tokens get only the scopes you grant
at creation time. A request missing a required scope fails with INSUFFICIENT_PERMISSIONS.
Quick Reference
All user-facing scopes, grouped by the resource they govern.
| Category | Scopes |
|---|---|
| User profile | user:read, user:write |
| Projects | projects:read, projects:write |
| Subscription | subscription:read, subscription:write |
| API keys | api-keys:read, api-keys:write, api-keys:delete |
These are the scopes you can include in a PAT's scopes array or request from an OAuth client. Tenant permissions tied to your role inside an organization (organization:read, organization:manage-members, organization:manage-billing, organization:manage-security) are granted at request time based on membership and cannot be requested from a token — see Role-gated tenant permissions.
How scopes are assigned
Session users
When a user signs in, their session carries the full set of user-facing permissions listed above. You cannot narrow a session's scopes — narrowing happens at the UI layer.
Personal Access Tokens
When you create a PAT via POST /api/auth/api-key/create, you pass an explicit scopes array. The token can never exceed the user's own permissions, and any scope you leave out is blocked even if the owning user has it. This is the mechanism you use to lock down a CI bot.
POST /api/auth/api-key/create
{
"name": "Build status poller",
"scopes": ["projects:read", "subscription:read"],
"expiresIn": 2592000
}OAuth clients
OAuth clients request scopes during the Authorization Code flow. The end user approves them at consent time, and the issued access token carries exactly those scopes.
Scope Reference
user:read
Read the signed-in user's profile, login history, email preferences, and data export.
Endpoints:
GET /api/user/meGET /api/user/me/login-historyGET /api/user/me/email-preferencesGET /api/user/me/export
user:write
Update the signed-in user's profile, email preferences, and account state (deletion, recovery).
Endpoints:
PUT /api/user/mePUT /api/user/me/email-preferencesPOST /api/user/me/recoverDELETE /api/user/me
projects:read
List and read projects inside an organization (tenant route — the organization id is part of the URL path). Tenant routes additionally require organization:read, granted automatically to any member.
Endpoints:
GET /api/user/organizations/{organizationId}/projectsGET /api/user/organizations/{organizationId}/projects/:id
projects:write
Create, update, and delete projects in an organization. Project creation generates monitoring topics from the supplied monitoringIntent and businessContext — see the Projects API reference. Tenant routes additionally require organization:read, granted automatically to any member.
Endpoints:
POST /api/user/organizations/{organizationId}/projectsPUT /api/user/organizations/{organizationId}/projects/:idDELETE /api/user/organizations/{organizationId}/projects/:id
subscription:read
Read the current organization's subscription state, plan, and usage counters. Paired with organization:read (granted automatically to any member).
Endpoints:
GET /api/user/organizations/{organizationId}/payments/subscriptionGET /api/user/organizations/{organizationId}/payments/subscription/usage
subscription:write
Start checkouts, change subscription details (including seat count), buy credit packs, and open the customer billing portal. Most write endpoints additionally require the role-gated organization:manage-billing permission (owner only) — subscription:write alone is not sufficient.
Endpoints:
POST /api/user/organizations/{organizationId}/payments/checkout— also needsorganization:manage-billingPOST /api/user/organizations/{organizationId}/payments/verifyPOST /api/user/organizations/{organizationId}/payments/credits/checkout— also needsorganization:manage-billingPATCH /api/user/organizations/{organizationId}/payments/subscription— also needsorganization:manage-billingGET /api/user/organizations/{organizationId}/payments/portal— also needsorganization:manage-billing
api-keys:read
List OAuth applications and PATs belonging to the signed-in user.
Endpoints:
GET /api/user/oauth-clientsGET /api/user/oauth-clients/:clientIdGET /api/auth/api-key/listGET /api/auth/api-key/get
api-keys:write
Create and update OAuth applications and PATs.
Endpoints:
POST /api/auth/oauth2/registerPUT /api/user/oauth-clients/:clientIdPOST /api/user/oauth-clients/:clientId/regenerate-secretPOST /api/user/oauth-clients/:clientId/togglePOST /api/auth/api-key/createPOST /api/auth/api-key/update
api-keys:delete
Delete OAuth applications and revoke PATs.
Endpoints:
DELETE /api/user/oauth-clients/:clientIdPOST /api/auth/api-key/delete
Role-gated tenant permissions
Tenant routes (under /api/user/organizations/{organizationId}/...) layer a second permission check on top of token scopes. These permissions cannot be requested in a PAT or OAuth client — they are granted at request time based on your role inside the active organization.
| Permission | Granted to | Used by |
|---|---|---|
organization:read | every member | All tenant reads (projects, payments, members, settings) |
organization:manage-members | owners, admins | Member invites, role changes, removals, MFA enforcement, audit logs |
organization:manage-billing | owners only | Billing-write paths (checkout, subscription patch, portal, domains) |
organization:manage-security | owners only | Security settings (PUT /settings/security) |
A request needs both the token scope and the role permission. A PAT with subscription:write issued by an admin (not owner) cannot run POST /payments/checkout because organization:manage-billing is owner-only. The error is the same INSUFFICIENT_PERMISSIONS shape — the message names the missing piece.
PAT scopes are intersected with the owner's current role. If the user's role on an organization is downgraded after a PAT is issued, the token's effective permissions on that tenant shrink immediately. No revocation needed — the next request narrows automatically.
Common scope sets
Read-only dashboard
For a UI that displays projects and subscription status but never writes.
["user:read", "projects:read", "subscription:read"]CI bot that creates and updates projects
For an automation that provisions monitoring projects and edits their topics.
["projects:read", "projects:write"]Billing automation
For a service that manages seat counts, credit top-ups, and renewals on behalf of an organization. The token's owner must hold the owner role on the org — billing-write endpoints require organization:manage-billing, which is granted at request time only to owners.
["subscription:read", "subscription:write"]Token manager (lifecycle only)
For tooling that provisions and rotates PATs on behalf of a user.
["api-keys:read", "api-keys:write", "api-keys:delete"]Organization pinning
PATs may be pinned to a single organization by passing metadata.organizationId at creation time. A pinned token rejects any request whose URL :organizationId does not match the pin — even if the owner is a member of other organizations.
POST /api/auth/api-key/create
{
"name": "Acme prod bot",
"scopes": ["projects:read", "projects:write"],
"metadata": { "organizationId": "01HZ3K5R4X9Y2V6QF8TJ7W0CDN" }
}Use this for any token that should only ever touch one tenant. It is a far smaller blast radius than relying on the caller to send the right URL.
Scope enforcement
When a request lacks a required scope, the API returns:
{
"success": false,
"status": 403,
"code": "INSUFFICIENT_PERMISSIONS",
"message": "Insufficient permissions. Required: projects:write",
"meta": {}
}This is a hard failure — retrying will not fix it. Either issue a new token with the missing scope or sign in as a user who has it.
Scopes cannot be changed on an existing PAT after creation. The POST /api/auth/api-key/update endpoint updates name and enabled status only. To add a scope, revoke
the token and create a new one.
Best Practices
- Least privilege always: The correct number of scopes on a token is the smallest set that makes the automation work. Err on fewer and add later.
- Pair reads and writes deliberately: A bot that only needs
projects:readshould never getprojects:write, even "just in case." - Pin production tokens to an organization: Accidents at the URL layer become
FORBIDDENresponses instead of cross-tenant writes. - Rotate on schedule: Pass
expiresIn(in seconds) so tokens die on their own. Build rotation into CI secrets management. - Never log the
keyvalue: Theba_*prefix makes them easy to grep for — do not hand leakers the job. - One automation, one token: Revocation becomes surgical instead of catastrophic.
Next Steps
- Set up SSO for your team: Follow Enterprise SSO to require corporate identity for domain users.
- Issue your first token: Walk through Quick Start to create one with the scopes you just picked.
- Plan for rate limits: See Rate Limits before running anything in a loop.
- Browse endpoints: Open the API Keys reference or the Projects reference to start integrating.
Related Pages
Introduction
How the API is structured, how authentication works, and how multi-tenant requests are scoped
Quick Start
Sign in, issue a Personal Access Token, and make your first authenticated call
API Structure
Request headers, response envelope, pagination, and the query conventions shared by every endpoint
Error Handling
Error envelope, full code list, and the retry strategies that actually work