Scopes
The 29 API scopes, the three verbs, the implication rules, and why a credential can hold fewer powers than it was granted.
Every operation in the public API declares the scope it requires. A credential carries a set of scopes, and the intersection of that set with the creator's workspace role is what is actually enforced.
There are 29 grantable scopes in three verbs.
read: overview workspaces domains uptime ssl crux synthetic rum analytics
gsc indexing robots sitemap alerts notifications reports credits
write: crux synthetic analytics gsc indexing robots alerts notifications reports
run: analytics gsc reports| Verb | What it means |
|---|---|
read:<module> | Returns data. Every module has one. |
write:<module> | Creates, updates, or deletes stored configuration. Only modules with a real configuration surface in the dashboard have one. |
run:<module> | Starts asynchronous or external work that spends something. Only modules with a job trigger the dashboard actually exposes have one. |
Three verbs rather than two, because the HTTP method does not tell you whether an operation mutates anything. Some POSTs change nothing, and some POSTs spend credits. Folding both into one write: scope would let a credential granted to rename an alert rule also burn the workspace's credit balance.
Implication rules
write:Ximpliesread:X. You cannot sensibly edit configuration you cannot read, and requiring both would only produce credentials that fail halfway through a workflow.run:Ximplies nothing. Triggering a job and editing configuration are orthogonal risks. If you need both, ask for both.
There is no read:all
read:all, write:all, and run:all do not exist and never will. All three strings are permanently blocked, so every credential has to name what it needs.
That is a few extra seconds when you create a key, and it is the difference between a leaked key being an incident and being a shrug:
write:scopes fail silently. A credential that can delete an alert rule stops alerts a team relies on, with no visible symptom until something breaks unnoticed.run:scopes spend. Everyrun:call costs 25 API credits, the highest price in the table.- The convenience
read:allused to serve is nowread:overview. One scope, one request, the cross-module summary for a domain and nothing beneath it. That is a materially smaller blast radius than every module's full detail, and it is one request instead of eight.
Ask for the narrowest set that does the job. If you only need a health summary, read:overview and read:domains is the whole grant.
Read scopes
| Scope | Grants |
|---|---|
read:overview | The cross-module summary for a domain, with period comparison |
read:workspaces | Your workspaces and their members |
read:domains | The domains in your workspaces |
read:uptime | Uptime Monitoring data |
read:ssl | SSL certificate data |
read:crux | CrUX Monitoring data |
read:synthetic | Synthetic Monitoring data |
read:rum | RUM Monitoring data |
read:analytics | Web Analytics data |
read:gsc | Google Search Console data |
read:indexing | Indexing Monitoring data |
read:robots | Robots.txt Monitoring data |
read:sitemap | Sitemap scanning data |
read:alerts | Alert rules and their history |
read:notifications | Notification settings |
read:reports | Report templates and generated reports |
read:credits | The workspace's per-request credit spending log |
Configure scopes
| Scope | Grants |
|---|---|
write:crux | Change CrUX Monitoring configuration |
write:synthetic | Change Synthetic Monitoring configuration |
write:analytics | Change Web Analytics configuration |
write:gsc | Change Google Search Console configuration |
write:indexing | Change Indexing Monitoring configuration |
write:robots | Change Robots.txt Monitoring configuration, and recompute the sitemap-versus-robots.txt conflict check |
write:alerts | Create and change alert rules |
write:notifications | Change notification settings |
write:reports | Create and change report templates |
Every write: operation is refused outright when the workspace subscription is past due, canceled, or expired, exactly as it would be in the dashboard.
Run scopes
| Scope | Grants | Costs |
|---|---|---|
run:analytics | Run Web Analytics reports | 25 API credits per run |
run:gsc | Run Google Search Console reports | 25 API credits per run |
run:reports | Generate PDF reports | 25 API credits per run |
All three spend server compute and credits, and all three sit in a tighter rate-limit bucket than reads and require an Idempotency-Key header on every call. See Conventions.
A credential is a ceiling, not a grant
This is the single most common source of confusion, so it is worth stating precisely.
Effective permission is the credential's scopes intersected with whatever the creator's current workspace role allows, recomputed on every request.
An API key does not carry a frozen snapshot of its creator's permissions. It tracks them. If the person who created a key is demoted from admin to member, every key they created loses its write: and run: power within about a minute, without the key being touched. Promote them again and the power comes back the same way.
Scopes only ever narrow what a role permits. They never widen it. A member-created key holding write:crux still cannot add a CrUX URL, because that operation is admin-gated in the product itself.
What a member can do
A member is read-only across every module, with two exceptions, because those objects belong to the individual rather than to the shared workspace configuration:
| Scope | Why a member keeps it |
|---|---|
write:alerts | An alert rule is owned by whoever created it |
write:notifications | A member's own read state and notification preferences |
Everything else that is shared, team-visible configuration requires admin or owner: funnels, experiments, uptime configuration, sitemap configuration, indexing groups, Search Console brand patterns and locale configuration, report templates, and robots.txt annotations.
This is the same rule the dashboard enforces, not an API-only restriction. The two layers cannot disagree.
Reads are never role-restricted
A credential holding every read: scope resolves identically for an owner, an admin, and a member. The only role-gated read in the whole product is workspace billing, and billing is excluded from the public API entirely.
One exception sits just outside that rule: GET /credits/log lists every member's requests, which is workspace-wide visibility rather than a view of your own spend, so it requires admin or owner and, for an OAuth credential, the read:credits scope. GET /credits stays readable by anyone, because a capped member has to be able to see whether the workspace is out of credits or they personally are.
Ask, do not guess
GET /me returns both sets:
{
"scopes": ["read:crux", "write:crux", "read:domains"],
"effective_scopes": ["read:crux", "read:domains"],
"roles": { "e0d4a2c8-1b77-4f39-9c52-6a8d3e0f4b21": "member" }
}Build your client's capability list from effective_scopes. A client that branches on scopes will advertise operations that always fail with 403, and will keep retrying them.
For a read-only credential the two sets are always identical, so this only matters once you ask for write: or run:.
Scopes that do not exist
Some scope strings are permanently blocked. They are not missing features waiting to be added; each one is a decision, and a test asserts the registry never contains them:
| Blocked scope | Why |
|---|---|
read:all, write:all, run:all | Aggregates would defeat the point of naming what you need |
write:domains, write:workspaces | Domain verification is coming, and an API-created domain would bypass it |
read:rum.sessions | Individual visitor session records are not reachable through the API at any scope |
write:uptime, write:sitemap | The backend route exists, but the dashboard does not expose it, and the API surface must be a subset of the dashboard |
run:crux | Draws from a shared platform-wide key pool, so one customer's loop would degrade collection for everyone |
run:sitemap, run:synthetic | A scripted trigger turns into permanent recurring collection or an unbounded test bill for data that was coming anyway |
run:robots | The one robots.txt job this API starts, recomputing the sitemap conflict check, fully overwrites its own stored result, so a repeat cannot corrupt or duplicate anything and it sits under write:robots instead |
run:uptime, run:ssl, run:alerts, run:notifications | No dashboard-reachable manual trigger exists |
read:billing, write:billing, run:billing | Billing is out of scope for the API entirely |