Snooplytics API DocsHome

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 read

Every 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.

CategoryScopes
User profileuser:read, user:write
Projectsprojects:read, projects:write
Subscriptionsubscription:read, subscription:write
API keysapi-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/me
  • GET /api/user/me/login-history
  • GET /api/user/me/email-preferences
  • GET /api/user/me/export

user:write

Update the signed-in user's profile, email preferences, and account state (deletion, recovery).

Endpoints:

  • PUT /api/user/me
  • PUT /api/user/me/email-preferences
  • POST /api/user/me/recover
  • DELETE /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}/projects
  • GET /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}/projects
  • PUT /api/user/organizations/{organizationId}/projects/:id
  • DELETE /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/subscription
  • GET /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 needs organization:manage-billing
  • POST /api/user/organizations/{organizationId}/payments/verify
  • POST /api/user/organizations/{organizationId}/payments/credits/checkout — also needs organization:manage-billing
  • PATCH /api/user/organizations/{organizationId}/payments/subscription — also needs organization:manage-billing
  • GET /api/user/organizations/{organizationId}/payments/portal — also needs organization:manage-billing

api-keys:read

List OAuth applications and PATs belonging to the signed-in user.

Endpoints:

  • GET /api/user/oauth-clients
  • GET /api/user/oauth-clients/:clientId
  • GET /api/auth/api-key/list
  • GET /api/auth/api-key/get

api-keys:write

Create and update OAuth applications and PATs.

Endpoints:

  • POST /api/auth/oauth2/register
  • PUT /api/user/oauth-clients/:clientId
  • POST /api/user/oauth-clients/:clientId/regenerate-secret
  • POST /api/user/oauth-clients/:clientId/toggle
  • POST /api/auth/api-key/create
  • POST /api/auth/api-key/update

api-keys:delete

Delete OAuth applications and revoke PATs.

Endpoints:

  • DELETE /api/user/oauth-clients/:clientId
  • POST /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.

PermissionGranted toUsed by
organization:readevery memberAll tenant reads (projects, payments, members, settings)
organization:manage-membersowners, adminsMember invites, role changes, removals, MFA enforcement, audit logs
organization:manage-billingowners onlyBilling-write paths (checkout, subscription patch, portal, domains)
organization:manage-securityowners onlySecurity 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.

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.

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:read should never get projects:write, even "just in case."
  • Pin production tokens to an organization: Accidents at the URL layer become FORBIDDEN responses 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 key value: The ba_* 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

  1. Set up SSO for your team: Follow Enterprise SSO to require corporate identity for domain users.
  2. Issue your first token: Walk through Quick Start to create one with the scopes you just picked.
  3. Plan for rate limits: See Rate Limits before running anything in a loop.
  4. Browse endpoints: Open the API Keys reference or the Projects reference to start integrating.