# Tokens and scopes An API token acts as you, within the scopes you give it. This page says how scopes work, what no token can ever do, and how to keep tokens safe. ## Token or OAuth? An API token is for your own scripts and tools, acting as you. An app that other people connect to their InfraNest account uses [OAuth](oauth.md) instead: same scopes, but nobody copies a token. ## One organization, or all of them A token works in **the organization it was created in**. A token made while you work in Acme cannot touch Globex, even if you belong to both: it gets `wrong_organization` there, and Globex is left out of every list it reads. When a tool really needs every organization you belong to, tick **Works in all my organizations** when you create the token. Tokens made before this choice existed work in all your organizations; the token list shows which is which. ## Scopes Each area has a **read** scope and, where the API allows changes, a **write** scope. Write includes read. Every scope, and what it allows, is in the [scopes table](scopes.md), generated from the list the token dialog uses. Scopes follow the API, not the app's menu, so one scope can reach several reference pages. `monitoring` is the broad one: besides monitors it covers incidents, maintenance, status pages, certificates, alerts, automations, tags and costs. Every endpoint in the reference shows the scope it needs. | Scope | Reference pages it reaches | |---|---| | `audit-log` | [Audit log](/reference/audit-log) | | `billing` | [Billing](/reference/billing) | | `cloud` | [Servers and cloud](/reference/cloud), [Integrations](/reference/integrations) | | `data` | [Data export](/reference/data) | | `dns` | [DNS](/reference/dns) | | `domains` | [Domains](/reference/domains), [Certificates](/reference/certificates) | | `drop-catch` | [Drop catch](/reference/drop-catch) | | `members` | [Organization and members](/reference/organization) | | `monitoring` | [DNS](/reference/dns), [Certificates](/reference/certificates), [Servers and cloud](/reference/cloud), [Monitoring](/reference/monitoring), [Incidents](/reference/incidents), [Maintenance](/reference/maintenance), [Status pages](/reference/status-pages), [Alerts and notifications](/reference/alerts), [Automations](/reference/automations), [Integrations](/reference/integrations), [Tags and custom fields](/reference/tags), [Costs](/reference/costs) | API writes are switched on per organization. Until they are for yours, write requests answer `write_disabled`. Some reads hand back a secret, and need the **write** scope even though they only read: a certificate's private key needs `monitoring.write`, a domain's transfer code needs `domains.write`. ## What a token can never do Whatever its scopes, these stay with a person signed in to the app. A token gets `not_token_writable` or `session_only` if it tries: - **Ordering and buying:** registering, transferring or renewing domains, new servers, volumes or load balancers, backorders, billing. - **Anything that destroys or overwrites:** deleting servers, zones or volumes, rebuilding, restoring backups, changing nameservers. - **Anything that changes who gets in or where data goes:** members, roles, single sign-on, provider credentials, webhooks, alert channels, automations. - **Your account:** password, email, two-factor, passkeys, sessions and tokens themselves. - **Settings that belong to people, and anything that is itself a key:** single sign-on, notification settings, dashboards, saved payment details, plan changes and promo codes, the set-up screens of integrations and automations, and the addresses of incoming webhooks and the PagerDuty webhook, which would let whoever has them trigger automations or file events. These limits are a safeguard, not a promise that a token causes no costs. What a token does still reaches your providers, and some providers charge for API use or for the resources you change. See [Responsibility and costs](responsibility-and-costs.md). ## Expiry A token expires after the lifetime you pick when you create it: 30, 90, 180 or 365 days. The default is 90. A week before it expires, you get an email. To keep it working, select **Renew for 90 days** in the token's menu under **My account → Developer**. The token itself does not change, so nothing that uses it needs updating. An expired token answers `unauthenticated`. Tokens made before expiry existed never expire. They show **Never** in the list. Once such a token is 180 days old, you get one email suggesting you renew it, which gives it an expiry date. ## Limiting a token to addresses A token can be limited to the addresses it is used from: one IP address or CIDR range per line, such as `203.0.113.10` or `203.0.113.0/24`, up to 50 entries. From anywhere else it answers `403` with the code [`token_ip_not_allowed`](errors.md#token_ip_not_allowed), so a copy of the token taken from a build log or a laptop is useless. Set the list when you create the token, or change it later with **Limit addresses** in the token's menu under **My account → Developer**. An empty list means any address, which is what every token has unless you set one. Changes to the list are in the audit log. The address is the one your request reaches InfraNest from: for a CI runner, its egress address; behind a NAT or proxy, the address of the NAT or proxy. OAuth apps are not limited this way; their access is decided by the grant. ## Rate limits Each token has its own budgets: | Budget | Default | What counts | |---|---|---| | Requests | 300 per minute | Every request | | Changes | 60 per minute | Every `POST`, `PUT`, `PATCH` and `DELETE` (these also count as requests) | | Changes per hour | 1,000 per hour | Every `POST`, `PUT`, `PATCH` and `DELETE`, over a rolling hour | The hourly budget is for long runs: a script that paces itself just under the per-minute line still stops after 1,000 changes in an hour. If a job really makes more than that, split it across hours, or ask us about a plan with a higher limit. Your plan can set different numbers; [Limits](limits.md) has every limit in one place. Every response says where you stand, for whichever budget is closer to running out: ```http X-RateLimit-Limit: 60 X-RateLimit-Remaining: 57 X-RateLimit-Reset: 1793030460 ``` Over a budget, the API answers `429` with the code [`rate_limited`](errors.md#rate_limited) and a `Retry-After` header in seconds. Wait that long, then retry. The body's `limit_key` says which budget ran out (`api_requests_per_minute`, `api_writes_per_minute` or `api_writes_per_hour`) and `limit` its number. After the hourly budget, the wait can be up to an hour. Running out of changes does not stop reads. Two tokens never share a budget. ## Keeping tokens safe - **One token per purpose**, named for where it is used, so revoking one breaks one thing. - **The fewest scopes that work.** A certificate script needs `dns.write`, nothing else. - **One organization per token** unless a tool truly needs all of them. - **Limit it to fixed addresses** when it runs somewhere that has them, such as a CI runner or a server. - **Store tokens as secrets**: your CI's secret store, a vault, an environment variable. Never in a repository. - **Revoke a token you no longer use** under **My account → Developer**. The list shows when each was last used. - **If a token leaks**, revoke it there at once. It stops working immediately. ## Seeing what a token does - **Every change names its token.** In the organization's **audit log**, a change made through a token shows **via token** and the token's name, and the name stays after the token is revoked. Filter the log to one token from the token's menu (**View activity**), or with `token_id` on [`GET /audit-logs`](/reference/audit-log). - **A new token is announced.** Creating one sends a security email to the account it belongs to, as adding a passkey does. If you did not create it, revoke it and change your password. - **A sudden flood of changes is flagged.** When a token makes far more changes in a day than it usually does — ten times its average over the past week, and at least 200 — the organization's owners get a notification, and the token appears under **Needs you** on Home for the rest of the day. A token less than three days old is flagged at 1,000 changes.