Skip to content

Scopes

API key scopes control which endpoints a key can access. A key without the required scope for an endpoint receives a 403 Forbidden response.

ScopeDescriptionGrants access to
audit:readRead audit findings, crawl results, and issue listsGET /v1/projects/:id/audits, GET /v1/projects/:id/issues
projects:readList and read project metadataGET /v1/projects, GET /v1/projects/:id
backlinks:readAccess backlink profile and referring domain dataGET /v1/backlinks/:target, POST /v1/backlinks/batch
rankings:readAccess keyword position data and rank historyGET /v1/projects/:id/rankings, GET /v1/projects/:id/keywords
connectors:readRead connector sync status and synced data snapshotsGET /v1/projects/:id/connectors, GET /v1/projects/:id/gsc

Keys are created in the dashboard (there is no create-key API endpoint — see API Keys). Work backwards from the endpoints your integration actually calls, then grant exactly those scopes and nothing more.

Worked example — a monitoring dashboard that reads audit findings and current rankings:

  1. List the endpoints the integration calls. Say it hits GET /v1/projects (to enumerate projects), GET /v1/projects/:id/issues (to read findings), and GET /v1/projects/:id/rankings (to read positions).
  2. Map each endpoint to its scope using the table above: GET /v1/projectsprojects:read; GET /v1/projects/:id/issuesaudit:read; GET /v1/projects/:id/rankingsrankings:read.
  3. In the dashboard, go to Account → API Keys → Create API key. Name it for the integration (e.g., grafana-monitoring) so a future audit of active keys is self-explanatory.
  4. Check exactly these three scopes — projects:read, audit:read, rankings:read — and leave backlinks:read and connectors:read unchecked. The dashboard does not pre-select a “full access” set; you choose each one deliberately.
  5. Set an expiry if the key lives in a temporary or lower-trust environment. Click create, copy the vis_live_* value once, and store it in your secrets manager.

Verify the new key works and is correctly scoped before you wire it into anything:

Terminal window
# Should succeed (projects:read granted)
curl -s -o /dev/null -w "%{http_code}\n" \
"https://visibilityiq365.com/api/v1/projects" \
-H "Authorization: Bearer vis_live_YOUR_KEY_HERE"
# → 200
# Should fail with 403 (backlinks:read NOT granted — this is correct)
curl -s -o /dev/null -w "%{http_code}\n" \
"https://visibilityiq365.com/api/v1/backlinks/example.com" \
-H "Authorization: Bearer vis_live_YOUR_KEY_HERE"
# → 403

The second call returning 403 is the confirmation that least privilege is actually in effect — the key can reach what it needs and is denied what it doesn’t.

A 403 Forbidden means the key authenticated successfully but lacks the scope for the endpoint. (Contrast with 401 Unauthorized, which means the key itself is missing, malformed, revoked, or expired — that is an auth problem, not a scope problem.) The response body names the scope that was required:

{
"ok": false,
"error": {
"code": "insufficient_scope",
"message": "This endpoint requires the 'backlinks:read' scope.",
"requiredScope": "backlinks:read"
}
}

Walk through it in order:

  1. Read requiredScope from the error body. That field tells you exactly which scope to add — you don’t have to guess from the endpoint path.
  2. Confirm what the key actually has. Go to Account → API Keys and check the scopes listed for the key, or look at the key you minted for this integration. Scopes are fixed at creation and shown next to each key.
  3. Decide: widen the key, or use a different key. If the integration legitimately needs the data, the safe move is usually to mint a new key with the added scope and rotate to it (see API Keys → Rotating a key) rather than broadening a widely-deployed key. If the call was a mistake (the integration shouldn’t be hitting that endpoint at all), fix the caller — don’t add the scope.
  4. Re-test with the curl one-liner above before redeploying. A 200 confirms the fix; a repeated 403 means you’re still presenting the old key (check your environment variable wasn’t cached) or you added the wrong scope.

Common causes, in rough order of frequency:

SymptomLikely causeFix
403 on an endpoint the key used to reachA new key was deployed with narrower scopes than the old oneCompare scopes; re-mint with the missing scope
403 only on backlinks:read/rankings:read endpointsKey was created scoped to audits/projects onlyAdd the data scope on a new key
403 immediately after a new endpoint launchedNew endpoints require explicitly-added scopes; existing keys are not auto-upgradedAdd the new scope to a key (see Future scopes)
401, not 403Not a scope issue — key missing/expired/revokedSee API Keys and Auth overview

Grant each key only the scopes it needs. A key used only to fetch backlink data doesn’t need audit:read or rankings:read. Narrower scopes reduce the blast radius if a key is compromised — a leaked read-only backlinks key cannot be used to read your audit findings or ranking data.

Concrete scenarios:

  • CI/CD gate. A pipeline that triggers an audit and blocks the build on new Critical findings needs only audit:read and projects:read (and, once write scopes ship, audit:write to start the crawl). It does not need backlinks:read, rankings:read, or connectors:read. If the CI runner is compromised, the attacker gets read access to findings and nothing else.
  • Backlink reporting job. A nightly job that pulls referring-domain profiles needs backlinks:read and projects:read only. Withhold audit:read and rankings:read so a leak of this key (which often lives on a shared reporting box) can’t expose your full SEO posture.
  • Embedded/partner dashboard. A read-only widget you embed for a client should get the single narrowest scope that powers it — often just rankings:read + projects:read. Never reuse your internal full-coverage key here.
  • One key per integration. Don’t share one broadly-scoped key across CI, monitoring, and reporting. Separate keys mean you can revoke one integration’s access without breaking the others, and last-used timestamps tell you which key to rotate after an incident.

You can combine any number of scopes on a single key. There is no “full access” wildcard scope — you must explicitly list each scope needed.

Scopes: audit:read, projects:read

This key can list projects and read audit findings but cannot access backlinks or rankings.

Additional scopes will be added as new API endpoints are released. Existing keys are not automatically granted new scopes — you must explicitly add new scopes to existing keys or create new keys.

Planned scopes (not yet available):

  • audit:write — trigger crawls and mark findings
  • connectors:write — trigger connector syncs
  • alerts:read — access alert configurations and triggered alerts