Permissions are stored as a string array on each API key and OAuth connection. They are capabilities — combine them with key conditions (project scope, limits, expiry) for full policy.

Values

PermissionUsed today
log_usagePOST /api/v1/messages (usage / batch / allocation), MCP log_usage
add_expensesExpense messages, MCP add_expense
read_summariesSummary / spend / budget endpoints + read MCP tools
estimate_costsReserved (no estimate endpoint yet)
manage_subscriptionsSubscription messages (POST /api/v1/messages)
delete_recordsReserved
Missing permission → 403 with error: "missing_permission".

Defaults

New ingest keys default to:
["log_usage", "add_expenses", "read_summaries", "estimate_costs"]
OAuth scopes use the same four strings (space-separated in the OAuth protocol). Dashboard create UI exposes the first four as checkboxes.

Conditions vs permissions

LayerControls
PermissionsWhat actions the key may call
ConditionsWhere / how much / how often / from where — project, monthly USD, expiry, RPM, CIDRs
See API keys & conditions.

Enforcement

  • Checked on every REST ingest/read and MCP tool call authenticated with an API key
  • Dashboard JWT routes do not use these permissions; they use workspace membership instead
  • Project-scoped keys only see summaries/spend for allowed projects