Quota
/ docs
Dashboard

OAuth scopes

Nine scopes, closed vocabulary. Each token carries a subset; each protected endpoint requires one. Granular scopes let read-only integrations live without spend permission, and let dashboards show a precise consent prompt instead of an all-or-nothing one.

The shape
Scopes are space-delimited strings (RFC 6749 §3.3). Request them on /oauth/authorize via the scope parameter; the granted scopes come back in the token response and are echoed on the consent screen.

01 The vocabulary

Every scope Quota knows about. New scopes go through code review and a migration — the discovery document's scopes_supported reads from this same source of truth.

openidSign the user in. Triggers an id_token in the token response. Required for any OIDC flow.
profileSee the user's display name and avatar. Adds name and picture claims to the id_token (when present in the database).
emailSee the user's email address. Adds email and email_verified claims to the id_token.
credits.readSee credit balance and usage history. Required by GET /v1/balance, GET /v1/me, and GET /v1/models.
credits.spendSpend credits on the user's behalf. Required by every billing-touching endpoint — POST /v1/chat/completions, POST /v1/messages (Anthropic), POST /v1beta/models/* (Google), and POST /v1/audio/speech.
account.readSee account profile and billing settings. Required by the /v1/me account-management surface.
account.writeUpdate account profile and billing settings. Required by payment-method and auto-topoff endpoints under /v1/payments/*.
apps.readSee developer apps and API keys. Almost no third-party app should ask for this — it's for first-party tooling.
apps.writeCreate, update, and delete developer apps. Same first-party-only caveat as apps.read.

02 Endpoints by scope

Quick lookup — find the scope you need to mint a token for a given call. Every endpoint here is enforced via requireScopeForAuth.

credits.spend

  • POST /v1/chat/completions
  • POST /v1/messages (Anthropic)
  • POST /v1beta/models/* (Google generateContent / stream)
  • POST /v1/audio/speech

credits.read

  • GET /v1/balance
  • GET /v1/models

account.read

  • GET /v1/me

account.write

  • POST /v1/payments/* (payment methods, auto-topoff)

apps.read / apps.write

Reserved for first-party tooling that manages developer apps and API keys on behalf of a user. No public API endpoint currently requires these scopes — the developer-dashboard surface (/developers/apps/*) is session-authenticated, not OAuth.

API keys aren't scoped
Scopes only apply to OAuth bearer tokens. API keys (sk-quota-...) are full-power and predate the scope concept — every endpoint accepts them regardless of scope.

03 Requesting scopes

Pass a space-delimited list (URL-encoded as +) on /oauth/authorize. The user sees a consent screen with the human-readable description of each scope.

https://api.usequota.ai/oauth/authorize
  ?response_type=code
  &client_id=quota_client_my_app
  &redirect_uri=https://myapp.com/callback
  &state=xyz
  &scope=openid+profile+email+credits.read+credits.spend

Granted scopes are echoed on the token response, and on every introspection of the resulting access token:

{
  "access_token": "quota_token_...",
  "token_type": "Bearer",
  "expires_in": 604800,
  "refresh_token": "quota_refresh_...",
  "scope": "openid profile email credits.read credits.spend",
  "id_token": "eyJ..."
}

04 Validation

A requested scope must clear two gates: it must be in the closed vocabulary above, AND it must be on the authorizing client's allowed_scopes list. Either failure produces a clean OAuth error.

invalid_scope (unknown)The string isn't in the vocabulary. Typical cause: typo (credits_read instead of credits.read) or referring to a scope from another provider.
invalid_scope (not_allowed)The scope is valid but the client's allowed_scopes list does not include it. Edit the app at POST /developers/apps/:id to widen the allowlist.

05 Insufficient scope at the API

If a token is missing a required scope, the protected endpoint returns:

{
  "error": {
    "code": "insufficient_scope",
    "message": "Token is missing required scope 'credits.spend'. Granted scopes: [openid, credits.read]. Re-authorize with scope=credits.spend included."
  }
}

Status 403. The fix is always to re-authorize with the missing scope added — refresh tokens cannot widen scope.

06 Recommended scope sets

Sign-in onlyopenid profile email — gets you a verified user identity with name and avatar. No API access.
Read-only dashboardopenid email credits.read — show balance and usage; can't spend.
User-pays AI appopenid profile email credits.read credits.spend — the canonical set for an end-user-facing chat or completions app billed against the user's balance.
Account self-serviceopenid email account.read account.write — let users edit their own profile, payment method, and auto-topoff from inside your app.