Authentication

One key, three surfaces

Bearer keys with scopes drive REST, A2A, and MCP. Console keys choose Read-only or Read + write, and either all sites or a selected list; admin-issued keys carry any scope subset.

Updated 2026-11-08

On this page

API key setup

One key walks the whole flow: REST, A2A, and MCP share the same Bearer credential.

  • Get a key — admin-issued or self-serve

    Admins issue keys in the admin console (POST /v1/ai/keys, any scope subset). Signed-in users create a key in Console → Access (POST /v1/seo/me/api-keys): pick a preset (Read-only / Read + write) or individual scopes, all sites or selected sites, optional 30/90/365-day expiry, max 5 live keys. A raw key is shown once — store it as $SEO_WATCH_KEY and never paste it into docs or chat.

  • Pick the right permissions

    Read-only = radar:read + rules:read + audit:read. Read + write adds sites:write (create/verify sites, billing), audits:write (run audits, import sitemaps), keywords:write and monitoring:write (schedules, alerts, webhooks, custom checks). The agent endpoints still take the smallest scope that does the job: A2A message/send and the site/finding MCP tools need audit:read; the MCP radar tool needs radar:read. The MCP handshake (initialize, notifications/initialized, tools/list, ping), A2A tasks/get, and GET 405s need no key.

  • Scope by site, not by creation

    A key can reach all your sites or only the ones you select. The whitelist gates reads, audits and write tools on those sites; it does not block site creation or the GSC import flow. Radar and rule reads are global and not site-scoped. Other site ids answer 404, the same as a site that does not exist.

  • Auth failures are uniform

    REST answers 401 AUTH_UNAUTHORIZED; A2A/MCP answer 401 with JSON-RPC error code -32002. Missing key and wrong scope look identical on purpose.

  • No anonymous quota anymore

    Agent endpoints no longer count per-IP anonymous quota — a valid key is the only gate. Usage still counts against the key's monthly quota.

Shell
curl -s "$API/v1/ai/quota" \
  -H "Authorization: Bearer $SEO_WATCH_KEY"

Auth · scopes

Pick a credential, then the smallest scope that does the job. Missing key and insufficient scope look identical on purpose (401 AUTH_UNAUTHORIZED; A2A/MCP answer JSON-RPC -32002).

Credentials

  • Admin-issued key REST · A2A · MCP

    Issued in the admin console (POST /v1/ai/keys). Any subset of the 8 scopes, picked at issuance. Raw key shown once — store it as $SEO_WATCH_KEY.

  • Console self-serve key REST · A2A · MCP

    Created in Console → Access (POST /v1/seo/me/api-keys). Pick a preset or individual scopes, all sites or a selected list; never expires by default (optional 30/90/365-day expiry), max 5 live keys. Same $SEO_WATCH_KEY usage.

  • Login session / Cloudflare Access Console BFF (me/*) · admin console only

    Google session cookie drives me/*; Access identity drives the admin console. Neither reaches AI key endpoints — third parties always use a key.

Boundary: me/* endpoints serve the console BFF only (session credential) and are intentionally absent from every reference table here — third parties always use an API key surface above.

Scope matrix

any valid key Any valid key may self-read its quota; the call is not counted.

  • GET /v1/ai/quota

radar:read Read Google update radar (triage-filtered). Also gates the MCP get_radar_updates tool.

  • GET /v1/ai/updates
  • GET /v1/ai/updates/impact

rules:read Read versioned audit rules.

  • GET /v1/ai/rules

audit:read Read audit runs, findings, and site reports. Also gates A2A message/send and the site/finding MCP tools.

  • GET /v1/ai/audit-runs
  • GET /v1/ai/audit-runs/{runId}/findings
  • GET /v1/ai/audit-runs/{runId}/findings/{findingId}
  • GET /v1/ai/sites/{id}/aeo
  • GET /v1/ai/sites/{id}/cross-report
  • GET /v1/ai/sites/{id}/fingerprint
  • GET /v1/ai/sites/{id}/gsc
  • GET /v1/ai/sites/{id}/i18n
  • GET /v1/ai/sites/{id}/opportunities
  • POST /v1/ai/sites/{id}/effect-verify

sites:read Read competitor targets you own. Gates the MCP get_competitor_changes / get_competitor_feed / get_competitor_gaps tools; write tools stay on their own scopes.

    sites:write Create and verify sites, and open billing endpoints for the owning account.

    • POST /v1/ai/sites
    • POST /v1/ai/sites/{id}/verify

    audits:write Run audits and import sitemap URLs. Gates the MCP run_audit / import_sitemap tools.

    • POST /v1/ai/sites/{id}/audits
    • POST /v1/ai/sites/{id}/import-sitemap

    keywords:write Add tracking keywords, write annotations and enrich terms with vendor data.

    • POST /v1/ai/sites/{id}/annotations
    • POST /v1/ai/sites/{id}/keywords
    • POST /v1/ai/keywords/enrich/estimate
    • POST /v1/ai/sites/{id}/keywords/enrich

    monitoring:write Manage audit schedules, alert/webhook subscriptions and custom checks.

    • GET /v1/ai/schedules
    • POST /v1/ai/sites/{id}/schedules
    • DELETE /v1/ai/schedules
    • GET /v1/ai/subscriptions
    • POST /v1/ai/subscriptions
    • DELETE /v1/ai/subscriptions/{id}
    • GET /v1/ai/notify-subscriptions
    • POST /v1/ai/notify-subscriptions
    • DELETE /v1/ai/notify-subscriptions/{id}
    • POST /v1/ai/notify-subscriptions/batch
    • GET /v1/ai/custom-checks
    • POST /v1/ai/custom-checks
    • POST /v1/ai/custom-checks/{id}/run
    • POST /v1/ai/custom-checks/batch

    admin only Admin console only (Cloudflare Access + allowlist). Bearer keys never pass this gate.

    • GET /v1/ai/keys
    • POST /v1/ai/keys
    • POST /v1/ai/keys/{id}/revoke
    • POST /v1/ai/keys/batch
    • GET /v1/ai/sites/{id}/cross-report
    • POST /v1/ai/sites/{id}/effect-verify
    • GET /v1/ai/sites/{id}/gsc
    • GET /v1/ai/sites/{id}/opportunities

    Agent presets

    • Read-only patrol radar:read + rules:read + audit:read + sites:read

      An agent that inspects radar, rules, and findings but changes nothing.

    • Can execute patrol + all write scopes

      Adds site setup, audits, keywords, monitoring, alerts, webhooks and custom checks. Console keys can request this preset; a site whitelist only limits which sites they can read or audit.

    Handshake methods need no key: A2A tasks/get, MCP initialize / tools/list / ping, and GET 405s. Everything else answers 401 without a valid key.

    Agent prompts, one-click copy

    Generated from the OpenAPI surface, never hand-written. <YOUR_API_KEY> stays a placeholder everywhere.

    Markdown
    You are operating Visdenda, a Google Search update radar
    with site audits. Base URL: $API. Auth: header
    "Authorization: Bearer <YOUR_API_KEY>".
    1. POST /v1/ai/sites to register the user's domain
       (verificationMethod: dns, file, or meta).
    2. Serve the returned proof, then POST
       /v1/ai/sites/:id/verify until verified.
    3. POST /v1/ai/sites/:id/audits, poll
       GET /v1/ai/audit-runs, then summarize fails first
       with their evidenceKey values.
    4. Fix, POST /v1/ai/sites/:id/audits again, then prove it:
       POST /v1/ai/sites/:id/effect-verify with changeDate,
       or diff two runs' findings; subscribe audit.finished
       webhook to be notified on completion.
    Never invent verdicts; quote rule ids and snapshots.