Skip to content

Scopes

A scope is a single permission — one action on one resource. Every API key carries a set of them, and they’re the core of how managed.dev beats coarse host tokens: instead of one all-or-nothing credential, you grant exactly the actions a key needs and nothing more.

Scopes follow the form resource:action. Resources in the dynamic application layer — the WordPress-specific surface that generic platforms don’t expose at all — are dotted: wp.plugins, wp.cli.

Scope shapes
sites:read # resource:action
sites:write
environments:write
wp.cli:exec # dotted resource, standalone action
wp.plugins:write # dotted resource
vulnerabilities:read

Two relations cut down how many scopes you list:

  • write implies read. Granting sites:write also grants sites:read. You never need to list both.
  • admin implies write (and therefore read). teams:admin covers teams:write and teams:read.

Two things are deliberately outside the implication chain:

  • Standalone actions are never implied. exec and raw sit outside read/write/admin — nothing short of granting wp.cli:exec grants wp.cli:exec.
  • vulnerabilities:read is not implied by security:read. The vulnerability feed is its own grant, so a general security-read key doesn’t automatically see your CVE exposure.

Wildcards expand along the same lines: sites:* grants every action on sites (read, write, admin), and the global * grants every scope in the catalog — except the isolated scopes below, which no wildcard ever includes.

Five scopes are dangerous enough that they’re excluded from every wildcard, including the global *. You can only grant them explicitly, one at a time:

Scope What it unlocks
credentials:read Reveal SFTP/SSH/DB credentials; list authorized SSH keys.
credentials:write Add/remove SSH keys, reset the admin password, mint magic-link SSO.
exec:raw Lift the WP-CLI denylist — run arbitrary commands, not just the safe set.
keys:read List and inspect API-key metadata.
keys:write Mint, roll, and revoke API keys.

So a * key — about as broad as you can mint — still cannot reveal an SFTP password, run an unfiltered command, or mint (or even enumerate) other keys. Those require deliberate, single grants. This is the line that keeps a broad automation key from quietly becoming a root credential. See the security model for why this boundary holds.

A scope grants nothing on its own — it only ever narrows what the key’s owner could already do. Effective permission on any request is the intersection of three things:

effective permission
effective = perms(RBAC role) ∩ scopes(key) ∩ resource-constraint(key)
  1. perms(RBAC role) — what the principal that minted the key is allowed to do under their team role. A key minted by a billing-only member can never deploy, no matter which scopes it lists.
  2. scopes(key) — the scopes you granted at mint time.
  3. resource-constraint(key) — the optional site the key is pinned to. (Team, project, and environment pin types are defined but not mintable yet.)

The headline consequence: a key can never exceed its owner. Scopes can only subtract. This is the same mental model as Cloudflare and Stripe scoped tokens, and it’s why a narrowly-minted key is safe to hand to CI or a contractor — it’s structurally incapable of escalating past the person who created it. Keys are additionally forced to a non-admin role, so there is no admin scope at all; see the security model.

The dotted wp.* scopes (plus cron:* and db:*) are only meaningful where the runtime advertises the matching capability — wp.plugins:write does nothing on a static site because a static site has no plugins. Clients shouldn’t hard-code if runtime == "wordpress"; they should ask the site what it can do via capability discovery and grant scopes accordingly.

A call against a site you can’t see returns 404 site.not_found; a call the site’s runtime can’t fulfil returns 409 capability.unsupported. Both are covered in capability discovery.

Of this family, wp.cli:exec is live today — it gates the WP-CLI exec endpoint. The rest — wp.plugins, wp.themes, wp.content, wp.users, cron, db — are reserved Preview: the grammar defines them, but the endpoints they’ll gate aren’t wired yet.

A representative slice — the full list lives in the scope catalog.

Scope Gates Runtime gate
sites:read / :write Site get, config reads, capability discovery; create, restart, config writes, PHP-version switch. always
environments:write Create, delete, refresh, reset, push, suspend, resume environments. env-capable
deployments:write Trigger builds, deploy artifacts, promote, roll back. always
backups:write Take backups; restore snapshots. always
observability:read Insights, logs, traces, requests, resource metrics. always
security:read / :write Malware overview and scan history; trigger scans, restore or dismiss detections. always
vulnerabilities:read The vulnerability report — not implied by security:read. always
jobs:read List and watch async jobs (incl. SSE). always
webhooks:read / :write Webhook endpoints, deliveries, and replays. always
cache:write Purge the page cache — all, by URL, or by tag. always
wp.cli:exec Denylisted WP-CLI through the exec endpoint — no raw shell. runtime=wordpress