Permissions (scopes)
A key does only what you ticked. Permissions are named resource:access. A call outside its permissions answers 403 API_SCOPE_MISSING:<scope>, and the suffix names the permission to add.
The catalogue
| Permission | Routes it opens |
|---|---|
account:read | GET /me |
account.notifications:read | GET /account/notifications |
account.access:read | GET /account/access |
account.ssh_keys:read | GET /ssh-keys, GET /ssh-keys/{id} |
account.ssh_keys:write | POST /ssh-keys, DELETE /ssh-keys/{id} |
services:read | GET /services, GET /services/{code} |
services:write | PATCH /services/{code}; POST /services/{code}/renew together with billing.invoices:pay |
services.metrics:read | GET /services/{code}/status, GET /services/{code}/metrics/history |
services.addons:read | GET /services/{code}/addons |
services.power:write | POST /services/{code}/power; actions power, start_vps, stop_vps, reboot_vps |
services.console:write | POST /services/{code}/console/command; action send_console_command |
services.backups:read | GET /services/{code}/backups; action backup_list |
services.backups:write | POST /services/{code}/backups, DELETE /services/{code}/backups/{backupId}, POST /services/{code}/backups/restore; actions backup_create, backup_delete, backup_restore |
services.firewall:read | action firewall_list |
services.firewall:write | actions firewall_create, firewall_update, firewall_move, firewall_delete |
services.rdns:write | action rdns, including op: "get" |
services.reinstall:write | POST /services/{code}/reinstall |
billing.invoices:read | GET /invoices, GET /invoices/{code}, GET /invoices/{code}/pdf |
billing.credit_notes:read | GET /credit-notes, GET /credit-notes/{code}/pdf |
billing.balance:read | GET /balance, GET /balance/transactions |
billing.payment_methods:read | GET /payment-methods |
billing.invoices:pay | POST /invoices/{code}/pay, POST /orders/{orderNumber}/pay, POST /services/{code}/renew; POST /orders when it pays |
billing.saved_methods:charge | the four routes above when the funding is saved_method or account_default. Never used alone |
catalog:read | GET /catalog/products, GET /catalog/products/{shortname} |
orders:read | GET /orders, GET /orders/{orderNumber} |
orders:write | POST /orders |
tickets:read | GET /tickets, GET /tickets/{ticketNumber} |
tickets:write | POST /tickets, POST /tickets/{ticketNumber}/messages, POST /tickets/{ticketNumber}/close |
Two routes fall outside the table: GET /me/key needs no permission, and GET /v1/openapi.json needs no key.
POST /services/{code}/actions/{action} has no fixed permission. It depends on the action sent: see the "actions" entries above and the full table in Managing services.
How a :write implies a :read
A :write implies the :read of the exact same name, and nothing else.
| You hold | You also get |
|---|---|
services:write | services:read |
services.backups:write | services.backups:read |
services.firewall:write | services.firewall:read |
account.ssh_keys:write | account.ssh_keys:read |
orders:write | orders:read |
tickets:write | tickets:read |
What does not carry over, despite the shared prefix:
services:writegives none ofservices.metrics:read,services.backups:read,services.addons:read,services.firewall:read.billing.invoices:paydoes not givebilling.invoices:read: paying an invoice and reading it are two permissions.services.rdns:writeandservices.reinstall:writehave no matching:read.
What a permission alone does not buy
Effective rights are the intersection of the permission, the key's service restriction, and the state of the service.
| Case | Answer |
|---|---|
| Service outside the key's restriction | 404 SERVICE_NOT_FOUND |
Suspended or cancelled service, relayed routes (/power, /console/command, /actions/{action}) | 409 SERVICE_NOT_ACTIVE |
| Suspended or cancelled service, delegated routes (backups, restore, reinstall) | 400 SERVICE_NOT_ACTIVE |
| Service in dunning, same delegated routes | 400 SERVICE_IN_DUNNING |
| Service with no provisioned instance | 409 on relayed routes, 400 INSTANCE_NOT_PROVISIONED on delegated ones |
| Action the platform does not classify | 403 API_ACTION_NOT_ALLOWED:<action> |
Choosing permissions
- Start from what the integration does today. Widening a key asks for an identity confirmation, not a new key.
- Monitoring or an accounting export needs
:readpermissions only. billing.saved_methods:chargegoes only on the key that has to charge, with a cap sized to the job. It is the only permission that forces a cap.services.reinstall:writedestroys the disk. Keep it on the key that reinstalls.