Create and use a fine-grained API token
API tokens let scripts, bots and CI jobs call the Zaroz Cloud API without storing your account password or browser session. Every token is deny-by-default: you choose the exact permissions it has and, for a personal token, the exact resources it may touch.
The complete list of routes lives in the API reference. The conventions every call shares (base URL, errors, pagination) are in Using the Zaroz API.
Personal or organization token
| Personal token | Organization token | |
|---|---|---|
| Acts as | You | The organization |
| Scope of each permission | Global, one resource type, one resource, or a resource and its descendants | The whole organization |
| Revoked when | You revoke it, or you lose access | You revoke it; with membership_tied also when its creator leaves |
| Created at | POST /me/api-tokens | POST /organizations/{id}/api-tokens (needs Owner or Admin) |
| Best for | One script, one service, least privilege | A team's CI or a bot that must outlive one person |
A token never has more authority than the person or organization that made it, and it is checked again on every request: if you lose a role, your tokens lose it too.
Before you create one
Treat a token like a password. Anyone who gets it can do everything it allows until it expires or you revoke it.
- Create a separate token for each integration.
- Grant only the permissions the integration needs.
- Prefer one service to all of them (personal tokens only).
- Add an
expires_atwhenever the integration can rotate its secret. - Never put a token in frontend JavaScript, a mobile app, a public repository or a support message.
See what you may grant
You can only grant what you hold yourself. Ask the API, so you never hard-code a list:
curl
Code
TypeScript
Code
Python
Code
The permissions that matter to most customers:
| Permission | Allows |
|---|---|
services.read | Every non-secret read of a service |
services.power | Start, stop, restart |
services.deploy | Set the source and create deployments, nothing else |
services.manage | Change the service (environment, backups, files, firewall...) and everything services.deploy does |
services.console | Logs stream, command console, SSH |
services.files.read | Browse and download files |
services.external_access.manage | Open and close public ports |
services.schedules.manage | Schedules |
services.databases.read | Browse attached databases |
organizations.read, projects.read | Read organizations and projects |
organizations.members.manage | Add, remove and change roles of members |
organizations.manage, projects.manage | Rename an organization; create, rename and delete projects |
organizations.purchase | Buy a subscription billed to the organization |
organizations.wallet.spend, organizations.wallet.top_up | Pay invoices from the wallet; add funds |
subscriptions.renewal.manage, subscriptions.cancel, subscriptions.resize.manage | Turn renewal on or off; end a subscription; resize or change plan |
organizations.api_tokens.manage | Create, list and revoke the organization's tokens |
wallet.read | Read wallet balances and entries |
There are no wildcards: services.read does not imply services.power.
Create a personal token
Minting needs a signed-in session (the console, or the login routes), not another API token. The secret is returned once, in the form zaroz_pat_<id>_<secret>; only a digest is stored.
Each grant is a permission plus a scope:
Scope kind | Reaches |
|---|---|
global | The permission wherever you hold it |
resource_type | Every resource of one type (resource_type) |
resource | Exactly one resource (resource_type, resource_id) |
resource_tree | A resource and what descends from it (resource_type, root_resource_id) |
curl
Code
TypeScript
Code
Python
Code
An empty grants list makes a token that authenticates and can do nothing. Absence denies.
Create an organization token
The caller must be an Owner or Admin of the organization. Capabilities apply to the whole organization.
curl
Code
TypeScript
Code
Python
Code
lifetime defaults to membership_tied: the token is revoked automatically when its creator leaves the organization. Use organization_owned when the token must keep working after that. Staff-only permissions can never be put on an organization token.
Use it
Send it as a bearer token. This reads a service with a token that holds only services.read:
curl
Code
TypeScript
Code
Python
Code
Try calling a route the token lacks (for example POST /service-instances/{id}/restart with the token above): it answers 403. That is the point.
Do not call the API directly from a public website
Browser code is visible to every visitor. Keep the token in a server, bot, CI secret store or another trusted backend.
Errors you should handle
401: the token is missing, malformed, expired or revoked.403: the token, its owner or both lack the permission for that resource.404: the id is wrong, or the resource is deliberately hidden from this identity.429: wait forRetry-Afterand retry.5xx: temporary; retry a limited number of times and log the response without logging the token.
List, rotate and revoke
curl
Code
TypeScript
Code
Python
Code
To rotate: create the replacement, update the integration, check it works, then revoke the old one. Revoking is immediate, and revoking a personal token needs a signed-in session, not a token. Token-backed actions appear in the organization activity with the token's name, so give tokens names you will recognise during an incident.
Next
- Deploy from CI/CD: the narrow
services.deploytoken in practice. - Service principals: credentials for code running inside a Workload, instead of a token of yours.
- Build a Minecraft status monitor
