skip to content →
FIELD_MANUAL / LIVEREVISIONv1.3 · 2026.10.04Updated 2026-10-04CHAPTERS12 FILEDCH_05INTEGRATION
[ CH_05.01 / FIELD_MANUAL ]

REST API reference

[ CH_05.01 / REST_API ]

REST API reference

All endpoints live under /api/v1. Two auth modes: interactive/management endpoints use a session JWT (Authorization: Bearer <jwt>) from magic-link login, while the read-only Analytics API (/projects/{id}/analytics/*) and the agent recommendations feed authenticate with a per-project API key sent as the x-api-key header — generate one under your project's Settings → Developer & API → Agent API Key. Analytics calls are metered per project and return X-RateLimit-* headers.

To create and manage projects programmatically, use an account API key (vsak_) with the Provisioning API — it spans every project you own and carries explicit write scopes. The per-project vsk_ key stays read-only and is minted from a project that already exists, so it can neither create one nor reach a second.

> base_url
https://api.vectraseo.com/api/v1

This reference is generated from the API's own route table, so it lists every customer route (221 of them). Scope says what a caller needs:

  • A scope name such as projects:read: a signed-in session, or an account key (vsak_) that holds that scope. Two names joined by + means the key needs both.
  • project key: the x-api-key header only, with the project's vsk_ key or an account key that holds projects:read. A session is not accepted.
  • session: a signed-in session only. No API key can call it.
  • none: no authentication.

Plan shows paid when the route returns 403 with code: "subscription_limit" on a free account. paid* means only some requests are paid, as the description says. Plan quotas, such as the monthly post allowance, also apply and are not shown here.

Authentication
POST/auth/magic-linknoneRequest magic link
POST/auth/magic-link/verifynoneVerify token, get JWT
POST/auth/logoutnoneClear the session cookie
GET/auth/mesessionThe signed-in user, with admin, partner and billing status
PATCH/auth/preferencessessionSave UI preferences on your user
POST/auth/lookupnoneReturn whether an email has a registered passkey.
POST/auth/passkey/register/beginsessionStart registering a passkey (WebAuthn options)
POST/auth/passkey/register/completesessionFinish registering a passkey
POST/auth/passkey/authenticate/beginnoneStart a passkey sign-in (WebAuthn challenge)
POST/auth/passkey/authenticate/completenoneFinish a passkey sign-in
GET/auth/passkeyssessionList your passkeys
PATCH/auth/passkeys/:credential_idsessionRename a passkey
DELETE/auth/passkeys/:credential_idsessionDelete a passkey
API keys
GET/account/api-keys/scopesnoneEvery account-key scope and what it grants
GET/account/api-keyssessionYour account keys (metadata only, never the key)
POST/account/api-keyssessionCreate a vsak_ account key with chosen scopes. The key is returned once
DELETE/account/api-keys/:key_idsessionRevoke an account key, effective immediately
GET/projects/:id/api-keysessionThe project key's prefix and dates, never the key
POST/projects/:id/api-key/rotatesessionIssue a new vsk_ project key, returned once. The old key stops working
POST/projects/:id/api-key/revokesessionRevoke the project key. Later calls get 401
Provisioning API (account key)
GET/account/meIdentify the calling key: account, plan, project count
GET/account/projectsEvery project on the account
POST/onboarding/audit/:audit_idsessionTurn a completed free audit into a project with a site-health monitor
POST/onboardingCreate AND configure a project in one call → 202 {project_id, job_id}
GET/onboarding/:job_idPoll an onboarding run: per-step outcomes + the project as it stands
Projects
GET/projectsList projects
POST/projectsCreate project
GET/projects/dashboard-summarysessionPost and competitor counts per project, for the dashboard
GET/projects/list-summarysessionPer-project card data for the projects list
GET/projects/:idGet project
PUT/projects/:idUpdate project
POST/projects/:id/url-notices/ackHide the "we fixed a typo in your URL" notice for one field.
DELETE/projects/:idsessionDelete project
GET/projects/:id/summarySchedule and post count for one project
POST/projects/:id/runpaidTrigger pipeline run: competitor analysis, gaps, posts → 202 {job_id}
GET/projects/:id/generation-configRead the project's intent-weighted topic-generation policy.
PUT/projects/:id/generation-configReplace the generation policy. Then call /gaps/rescore to re-rank existing gaps
POST/projects/:id/credentials/revealsessionReveal one stored CMS credential
GET/projects/:id/indexnowThe project's IndexNow key, where to host it, and the last check.
POST/projects/:id/indexnow/checkMint the key if needed and check the key file on the project's host now.
Competitors
GET/projects/:id/competitorsList competitors
GET/projects/:id/competitors/discoverSuggest competitors from DataForSEO
POST/projects/:id/competitorsAdd competitor
DELETE/projects/:id/competitors/:cidRemove competitor
POST/projects/:id/competitors/analyzepaidRun analysis (starts the same full content run as /run) → 202 {job_id}
Content Gaps
GET/projects/:id/gapsList gaps (paginated: ?limit, ?cursor)
POST/projects/:id/gaps/identifypaidIdentify gaps → 202 {job_id}
POST/projects/:id/gaps/rescoreRe-rank existing gaps after a generation-config change. No new gaps, no model call
POST/projects/:id/gaps/:gap_id/rejectMark a topic off-target. Kept as a negative example for later gap identification
DELETE/projects/:id/gaps/:gap_idDelete gap
Blog Posts
GET/projects/:id/postsList posts (paginated: ?limit, ?cursor)
POST/projects/:id/posts/generateGenerate posts → 202 {job_id}
POST/projects/:id/posts/bulk-delete-archivedsessionPermanently delete up to 20 archived posts, preserving request order.
POST/projects/:id/images/presignsessionGet a presigned URL to upload an image
POST/projects/:id/posts/hybrid-generateGenerate a post from your own outline, with an optional image
POST/projects/:id/posts/title-recommendationssessionpaidRecommend SEO/conversion titles and focus keywords for outline-based posts.
GET/projects/:id/posts/:post_idGet post
GET/projects/:id/posts/:post_id/index-stateCached Google URL Inspection state for the post's live URL
POST/projects/:id/posts/:post_id/recheck-indexsessionRe-run URL Inspection for the post's live URL
GET/projects/:id/posts/:post_id/gscSearch Console metrics for one post
GET/projects/:id/posts/:post_id/bodyThe post's HTML body
PUT/projects/:id/posts/:post_idUpdate post
POST/projects/:id/posts/:post_id/repair-metadatasessionpaidAI repair of the post's SEO title and meta description
DELETE/projects/:id/posts/:post_idsessionDelete post
POST/projects/:id/posts/:post_id/publishPublish to CMS
GET/projects/:id/posts/:post_id/exportsessionExport a post as an HTML or Markdown file download.
POST/projects/:id/posts/:post_id/regenerate-imagessessionpaidRegenerate the post's images → 202 {job_id}
POST/projects/:id/posts/:post_id/repair-contentpaidRun Auto-fix on the post's content (queued job)
POST/projects/:id/posts/:post_id/regenerate-contentpaidRewrite the post without the product claims its destination rejected, then re-check it
POST/projects/:id/posts/:post_id/advance-phasesessionpaidRun the next publish-readiness step on the post
POST/projects/:id/posts/:post_id/replaysessionpaidSend an archived post back through publish readiness
POST/projects/:id/posts/:post_id/remove-unconfirmed-claimssessionpaidRemove unconfirmed claims from a held draft and re-check it
POST/projects/:id/posts/:post_id/archivesessionArchive a post. Archived posts are purged after five days
POST/projects/:id/posts/:post_id/unarchivesessionRestore an archived post.
POST/projects/:id/posts/:post_id/retry-truthsessionpaidRe-run the claim check on the post
Scheduler
GET/projects/:id/scheduleGet schedule
PUT/projects/:id/scheduleUpdate schedule
DELETE/projects/:id/scheduleDisable schedule
Sitemap
POST/projects/:id/sitemapFetch the project's sitemap → 202 {job_id}
GET/projects/:id/sitemapStored sitemap data
DELETE/projects/:id/sitemapsessionClear stored sitemap data
Monitors
GET/projects/:id/monitorsList monitors
GET/projects/:id/monitors/summarySite-monitor rollup for the project
POST/projects/:id/monitorsCreate monitor
GET/projects/:id/monitors/:midGet monitor
PATCH/projects/:id/monitors/:midUpdate monitor (partial)
DELETE/projects/:id/monitors/:midsessionDelete monitor
POST/projects/:id/monitors/:mid/scanTrigger manual scan
POST/projects/:id/monitors/:mid/refresh-sitemapRe-fetch the monitor's sitemap (queued job)
GET/projects/:id/monitors/:mid/scansList scan history
GET/projects/:id/monitors/:mid/scans/:sid/issuesA scan's issues — bare JSON array; next page via the X-Next-Cursor header (?cursor=)
POST/projects/:id/monitors/:mid/issues/implementpaid*Fix one issue on a page VectraSEO published → 202. Model fixers need a paid plan; deterministic ones are free
POST/projects/:id/monitors/:mid/issues/implement-batchpaid*Fix every VectraSEO-published page one rule flagged in a scan. Model fixers need a paid plan
POST/projects/:id/monitors/:mid/issues/change-setpaid*Build a reviewable change-set for a page VectraSEO cannot republish → 202 {job_id}. Model fixers need a paid plan
GET/projects/:id/change-setsThe project's stored change-sets
GET/projects/:id/change-sets/job/:job_idThe change-set a finished change-set job built
POST/projects/:id/monitors/:mid/remediation/snapshotssessionRecord that you copied or downloaded a scan's fix plan
GET/projects/:id/monitors/:mid/remediation/snapshotssessionFix-plan export history, newest first
GET/projects/:id/monitors/:mid/remediationsessionStatus of each finding in the current fix plan, plus verified fixes
AI Visibility MonitorGuide →
GET/projects/:id/visibility/monitorsList AI visibility monitors
GET/projects/:id/visibility/summaryPer-project rollup
POST/projects/:id/visibility/monitorspaidCreate AI visibility monitor
GET/projects/:id/visibility/monitors/:midGet monitor (with prompts)
GET/projects/:id/visibility/monitors/:mid/remediationRemediation plan from the latest completed scan
PATCH/projects/:id/visibility/monitors/:midUpdate monitor — assistants, prompts, schedule, alerts
DELETE/projects/:id/visibility/monitors/:midDelete monitor
POST/projects/:id/visibility/monitors/:mid/scanpaidTrigger manual citation scan
GET/projects/:id/visibility/monitors/:mid/scansList scan history
GET/projects/:id/visibility/monitors/:mid/scans/:sid/resultsGet scan results per assistant
GET/capabilities/visibility-assistantsnoneWhich AI assistants visibility scans can query
Keyword Rank TrackerGuide →
GET/projects/:id/ranksList tracked keywords + current rank + 30-day history
GET/projects/:id/ranks/keywordsList tracked keywords
POST/projects/:id/ranks/keywordsAdd a tracked keyword
DELETE/projects/:id/ranks/keywords/:keywordRemove a tracked keyword
GET/projects/:id/ranks/summaryTop wins this week + drop alerts rollup
GET/projects/:id/ranks/suggestionsAuto-suggest keywords from project + GSC
POST/projects/:id/ranks/fetchForce a rank refresh for the project
Google Search Console
GET/projects/:id/gsc/statussessionSearch Console connection status
GET/projects/:id/gsc/summarysessionProject-level clicks and impressions
GET/projects/:id/gsc/pagessessionSearch Console data for sitemap pages that are not posts
POST/projects/:id/gsc/authorizesessionStart OAuth — returns Google consent URL
POST/projects/:id/gsc/propertiessessionExchange the OAuth code and list your Search Console properties
POST/projects/:id/gsc/connectsessionBind a Search Console property to the project
DELETE/projects/:id/gsc/connectsessionDisconnect Search Console (stored metrics are kept)
POST/projects/:id/gsc/refreshsessionForce a Search Console refresh (queued job)
POST/projects/:id/gsc/sitemapsessionSubmit this project's sitemap to Google now.
GET/projects/:id/search/overviewClicks, impressions, CTR, position (28d)
GET/projects/:id/search/queriesTop queries
GET/projects/:id/search/pagesTop pages
GET/projects/:id/search/pages/trendsPer-page momentum — which pages are improving vs slipping over time.
GET/projects/:id/search/pages/historyWeekly series for one page, with its current trend
GET/projects/:id/search/index-coveragePage indexing buckets from URL Inspection API
GET/projects/:id/indexing-healthDiscovery-health findings for the project's published posts.
GET/projects/:id/search/index-coverage/issuesFAIL-bucket URLs with example fixes
GET/projects/:id/search/index-coverage/urlsInspected URLs, filterable and cursor-paginated
POST/projects/:id/search/index-coverage/inspect-urlRe-run URL Inspection on one URL now ("Validate fix")
Google Indexing API
GET/projects/:id/indexing-api/statusConnection state (never returns the secret)
PUT/projects/:id/indexing-api/credentialssessionSave your own Google OAuth client and record your risk consent
POST/projects/:id/indexing-api/authorizesessionStart OAuth with your own client — returns the consent URL
POST/projects/:id/indexing-api/connectsessionExchange the OAuth code and turn on notifications
PUT/projects/:id/indexing-api/enabledPause or resume notifications, keeping the connection
DELETE/projects/:id/indexing-apisessionRemove the credentials and the connection
POST/projects/:id/indexing-api/request-indexingSubmit selected URLs to the Google Indexing API (URL_UPDATED)
POST/projects/:id/indexing-api/request-all-not-indexedSubmit every not-indexed page in one action
GA4
GET/projects/:id/ga4/statussessionConnection status + bound property
POST/projects/:id/ga4/authorizesessionStart OAuth — returns Google consent URL
POST/projects/:id/ga4/propertiessessionList connectable GA4 properties for the account
POST/projects/:id/ga4/connectsessionBind a GA4 property to the project
DELETE/projects/:id/ga4/connectsessionDisconnect GA4
POST/projects/:id/ga4/refreshsessionForce a GA4 metrics refresh
GET/projects/:id/ga4/pagessessionGA4 top pages + next-best-actions
First-party traffic (push your own logs)
POST/projects/:id/traffic/dailypaidPush one UTC day of per-page aggregates. A replay replaces that day
GET/projects/:id/traffic/overview28-day totals vs the previous 28, daily series, top referrers, AI crawlers, countries, UTM
GET/projects/:id/traffic/pagesPer-page human visits, crawler fetches by class, AI-assistant referrals
Recommendations
GET/projects/:id/recommendationsList active recommendations across monitors
GET/projects/:id/recommendations/:rule_id/:target_kind/:target_idpaidPer-rule detail (cache-or-generate)
POST/projects/:id/recommendations/:rule_id/:target_kind/:target_id/regeneratepaidForce a fresh AI generation
POST/projects/:id/recommendations/:rule_id/:target_kind/:target_id/optimizedDismiss until its Search Console numbers change
POST/projects/:id/recommendations/:rule_id/:target_kind/:target_id/applyApply the suggested fix (republishes the post)
POST/projects/:id/recommendations/apply-allApply every applicable fix in one job. Send dry_run: true first to preview
GET/projects/:id/agent/recommendationsproject keyAgent-consumable feed (GSC index FAIL buckets, monitor issues, AEO gaps) — see below
Analytics API (x-api-key · read-only · paid plans)
GET/projects/:id/analytics/overviewproject keypaidOne-call snapshot: health (AEO score nested), visibility, search, traffic, ranks; each surface nullable (?period_days)
GET/projects/:id/analytics/search/overviewproject keypaidGSC clicks, impressions, CTR, position + daily series
GET/projects/:id/analytics/search/queriesproject keypaidTop search queries (?limit)
GET/projects/:id/analytics/search/pagesproject keypaidPer-URL performance (?sort, ?limit)
GET/projects/:id/analytics/search/index-coverageproject keypaidGoogle index buckets + sparklines
GET/projects/:id/analytics/traffic/pagesproject keypaidGA4 per-page sessions, revenue, AI referrals
GET/projects/:id/analytics/traffic/first-partyproject keypaidTraffic you push via /traffic/daily: 28-day per-page visits (?sort=human|human_delta|ai_crawler, ?limit)
GET/projects/:id/analytics/visibility/summaryproject keypaidPer-monitor AI Visibility rollup (score/citation rate/SoV under latest_scan)
GET/projects/:id/analytics/visibility/monitors/:mid/scansproject keypaidAI Visibility scan history, newest first — bare array (?limit)
GET/projects/:id/analytics/visibility/monitors/:mid/scans/:sid/resultsproject keypaidPer-prompt, per-assistant results
GET/projects/:id/analytics/health/summaryproject keypaidSite-health + AEO score, issue counts
GET/projects/:id/analytics/health/monitors/:mid/scansproject keypaidSite-health scan history, newest first — { items, count } (?limit)
GET/projects/:id/analytics/health/monitors/:mid/scans/:sid/issuesproject keypaidIssues for a scan (severity, category, fix)
GET/projects/:id/analytics/ranksproject keypaidTracked keywords + position history (?days)
Verification Receipt (public)
GET/verification/:project_id/:post_idnonePublic sanitized truth report for a published post. No auth — gated to status=published.
Automation Status
GET/projects/:id/automationsessionRead-only rollup of generation, publish, monitor, and rank automation tracks
Jobs
GET/jobs/:job_idPoll job status
POST/jobs/:job_id/cancelRequest cancellation of a queued or running job
GET/jobs/:project_id/jobsList a project's jobs
Billing
POST/billing/checkoutsessionStart a Stripe Checkout session, or switch plan if already subscribed
POST/billing/switchsessionSwitch an existing subscription to a different plan.
POST/billing/portalsessionOpen the Stripe customer portal
GET/billing/subscriptionsessionGet current user's subscription status for a product (content|local).
GET/billing/plansessionYour plan limits, per product
POST/billing/cancelsessionCancel subscription at period end.
POST/billing/resumesessionUndo a pending cancellation.
GET/billing/local-scout/refund-eligibilitysessionWhether the user's Local Scout subscription is within the money-back window.
POST/billing/local-scout/refundsessionHonor the Local Scout 30-day money-back guarantee: refund the latest payment and cancel the subscription immediately.
POST/billing/verify-sessionsessionVerify a completed checkout session and sync subscription.
GET/billing/confignoneStripe publishable key
Free tools and public endpoints
POST/contactnoneSend a message to VectraSEO
POST/auditnoneStart a free site audit → 202 {audit_id}
GET/audit/:audit_idnonePoll a free audit
POST/audit/:audit_id/emailnoneSubmit an email to unlock the full audit report
GET/audit/:audit_id/og.pngnonePer-scan Open Graph share image.
GET/public/stats/smb-seononeLatest aggregate small-business SEO statistics
GET/public/stats/partner-countnoneNumber of approved partners
POST/public-tools/ai-visibilitynoneRun the AEO readiness checks on one public URL
POST/public-tools/ai-visibility-livesessionpaidQueue a live AI-assistant visibility scan
GET/public-tools/ai-visibility-live/:sidnonePoll a live visibility scan
POST/public-tools/local-scoutsessionpaidQueue a Local Scout scan (needs a Local Scout plan)
GET/public-tools/local-scout/scans/:sidsessionPoll a Local Scout scan
POST/public-tools/local-scout/previewnoneInstant local-findability snapshot
POST/public-tools/local-scout/unlocknoneSubmit an email to see the full Local Scout fix list
GET/public-tools/local-scout/unsubscribenoneUnsubscribe from Local Scout follow-up emails
POST/public-tools/robots-testnoneTest robots.txt rules, fetched from a URL or pasted
POST/public-tools/meta-descriptionsessionpaidGenerate meta description options
POST/public-tools/title-tagsessionpaidGenerate title tag options
Partner program
POST/affiliates/applynoneApply to the partner program
POST/affiliates/validate-refnoneCheck whether a referral code belongs to an approved partner
POST/affiliates/track-clicknoneRecord a click on a partner link
GET/affiliates/programnoneProgram terms: commission rate, window, eligible plans
GET/affiliates/applications/:application_idnoneRead back a submitted application
GET/affiliates/mesessionYour partner profile
GET/affiliates/dashboardsessionPartner dashboard totals
GET/affiliates/commissionssessionYour commission ledger (paginated)
GET/affiliates/referralssessionCustomers you referred (paginated)
GET/affiliates/clicks/dailysessionDaily click counts
PATCH/affiliates/settingssessionUpdate your partner settings
GET/affiliates/assetssessionMarketing assets with your referral link filled in

Agent recommendations feed

GET /projects/:id/agent/recommendations returns every current recommendation for a project in one call: Search Console findings (including Page Indexing failures), site-health SEO issues and AEO issues. It takes a project key, works on every plan, and is read-only.

PARAMETER
MEANING
severity_min
Lowest severity to include: critical, warning, info, opportunity or positive. Default positive, which keeps everything.
categories
Comma-separated subset of gsc, seo, aeo. Default all three.
limit_per_rule
Cap on items per rule, 0–500. Default 0, which means no cap.
format
json (default) or markdown.

With format=markdown the response is text/markdown: the same items written as a briefing you can paste into a coding agent such as Claude Code or Cursor. To have Claude Code fetch it and act on it:

claude-code.sh
claude "Pull SEO recommendations from
https://api.vectraseo.com/api/v1/projects/$PROJECT_ID/agent/recommendations?format=markdown
using header x-api-key: <your-key>, then group fixes by rule_id
and open a PR."

For Cursor or any other agent, fetch the briefing and paste it into the chat:

fetch-briefing.sh
curl -H "x-api-key: <your-key>" \
  "https://api.vectraseo.com/api/v1/projects/$PROJECT_ID/agent/recommendations?format=markdown&severity_min=warning"

Each JSON item has a stable id, so you can compare runs to see what is new and what is resolved. A missing, revoked or wrong key returns 401 invalid_api_key; a query value outside the allowed set returns 422.

Rate limits

There is one hourly limit, and it is the same on every plan: 1,000 requests per hour (the analytics_api_rate_limit_per_hour setting). It is counted in two buckets:

  • Per project for routes whose scope is project key (the Analytics API and the agent feed), whichever key you send.
  • Per account for an account key (vsak_) on every other key-reachable route.

Metered responses carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. Over the limit the API returns 429 with Retry-After: 3600. Calls made with a signed-in session are not counted.

Analytics API · response shapes

Each /analytics/* response below is the exact shape the live API returns. Three conventions trip up first-time integrators:

  • AEO readiness lives inside health. The overview reports it as health.aeo_score — there is no top-level aeo object.
  • Surfaces can be null. In /overview, each of health, visibility, search, traffic, and ranks is null until that source is connected and has data — normalize defensively.
  • Only scan issues are cursor-paginated./analytics/health/monitors/:mid/scans/:sid/issues returns { items, count, next_cursor } — follow next_cursor until it is null. Every other list endpoint returns { items, count } in one response (visibility scans and visibility results return a bare array), with no next_cursor/total. None has server-side severity/category filters.
  • Get a scan_id from the scan lists./analytics/health/monitors/:mid/scans and /analytics/visibility/monitors/:mid/scans list a monitor's scans newest first (?limit 1–100, default 20). Each scan carries the scan_id the issues and results routes take; /analytics/health/summary and /analytics/visibility/summary give the monitor ids.
GET/projects/:id/analytics/overview

One-call snapshot. AEO is health.aeo_score (no top-level aeo). Every surface is null until its source is connected.

overview.json
{
  "project_id": "prj_8fa21c",
  "period_days": 28,
  "health":     { "health_score": 92, "aeo_score": 78, "urls_checked": 184,
                  "critical": 0, "warning": 3, "info": 9 },
  "visibility": { "visibility_score": 61, "citation_rate": 0.34, "share_of_voice": 0.22 },
  "search":     { "clicks": 12431, "clicks_prev": 11705, "impressions": 402118,
                  "ctr": 0.031, "position": 14.2 },
  "traffic":    { "sessions": 18904, "engaged_sessions": 12880,
                  "key_events": 311, "revenue": 4820.50, "ai_referrals": 842 },
  "ranks":      { "tracked": 48, "top_10": 12, "wins_this_week": 3 },
  "generated_at": "2026-05-29T14:02:11Z"
}
GET/projects/:id/analytics/search/overview

GSC clicks, impressions, CTR, position. The daily time series is the daily field. connected is false until Search Console is linked.

search-overview.json
{
  "connected": true,
  "property_url": "https://acme.com/",
  "period_days": 28,
  "clicks": 12431, "impressions": 402118, "ctr": 0.031, "position": 14.2,
  "clicks_prev": 11705, "impressions_prev": 389220, "ctr_prev": 0.030, "position_prev": 15.1,
  "daily": [
    { "date": "2026-05-01", "clicks": 402, "impressions": 13200, "ctr": 0.030, "position": 14.8 }
  ]
}
GET/projects/:id/analytics/search/queries

Top queries for the most recent refresh. Capped by ?limit (default 25, max 100). Not cursor-paginated.

search-queries.json
{
  "items": [
    { "query": "ai seo audit tool", "clicks": 312, "impressions": 8400, "ctr": 0.037, "position": 6.1 }
  ],
  "count": 25
}
GET/projects/:id/analytics/search/pages

Per-URL performance with previous-period values and deltas. ?sort = clicks | clicks_delta | clicks_loss | position_delta | position_loss; ?limit max 200.

search-pages.json
{
  "items": [
    {
      "kind": "post", "target_id": "post_4f2a",
      "url": "https://acme.com/blog/aeo-guide", "title": "The AEO Guide",
      "clicks": 312, "impressions": 8400, "ctr": 0.037, "position": 6.1,
      "clicks_prev": 280, "impressions_prev": 8010, "ctr_prev": 0.035, "position_prev": 7.2,
      "clicks_delta": 32, "position_delta": 1.1
    }
  ],
  "count": 50
}
GET/projects/:id/analytics/search/index-coverage

Google index buckets + 30-day sparklines. severity is info | warning | critical | neutral — only indexed (live on Google) is info.

index-coverage.json
{
  "connected": true,
  "property_url": "https://acme.com/",
  "buckets": [
    { "bucket": "indexed", "severity": "info", "count": 184, "sparkline": [180,181,184], "examples": [] },
    { "bucket": "crawled_not_indexed", "severity": "warning", "count": 12, "sparkline": [10,11,12], "examples": [] },
    { "bucket": "excluded_noindex", "severity": "warning", "count": 31, "sparkline": [31,31,31], "examples": [] }
  ],
  "total_inspected": 227,
  "rollup_days": 30,
  "quota": { "used_today": 14, "daily_cap": 2000 },
  "last_synced_at": "2026-05-29T06:00:00Z"
}
GET/projects/:id/analytics/traffic/pages

Per-page GA4 metrics with previous-period values + ai_referrals (ChatGPT / Claude / Gemini). Returns { items, count } — not cursor-paginated.

traffic-pages.json
{
  "items": [
    {
      "target_id": "post_4f2a",
      "url": "https://acme.com/blog/aeo-guide", "path": "/blog/aeo-guide",
      "matched": true,
      "sessions": 2104, "engaged_sessions": 1502, "engagement_rate": 0.714,
      "key_events": 41, "revenue": 980.00,
      "sessions_prev": 1788, "engaged_sessions_prev": 1290, "engagement_rate_prev": 0.702,
      "key_events_prev": 33, "revenue_prev": 740.00,
      "ai_referrals": 156, "ai_referrals_prev": 92,
      "source_counts": { "google": 1402, "chatgpt.com": 98, "claude.ai": 41 }
    }
  ],
  "count": 37
}
GET/projects/:id/analytics/visibility/summary

Per-monitor AI Visibility rollup. Headline metrics live under each monitor latest_scan; best_score/worst_score summarise across monitors. No top-level score, no by_assistant.

visibility-summary.json
{
  "has_monitor": true,
  "best_score": 61,
  "worst_score": 54,
  "monitors": [
    {
      "monitor_id": "vis_2a91", "name": "Brand prompts", "enabled": true,
      "schedule": "weekly", "assistants": ["chatgpt", "claude", "gemini"],
      "last_scan_at": "2026-05-27T09:00:00Z", "next_scan_at": "2026-06-03T09:00:00Z",
      "latest_scan": {
        "scan_id": "vscan_88c1", "visibility_score": 61,
        "citation_rate": 0.34, "share_of_voice": 0.22, "accuracy_flags": 2
      }
    }
  ]
}
GET/projects/:id/analytics/visibility/monitors/:mid/scans/:sid/results

Per-prompt, per-assistant results. Returns a plain JSON array (no items envelope). response_accurate is reserved and currently always null.

visibility-results.json
[
  {
    "scan_id": "vscan_88c1", "created_at": "2026-05-27T09:01:12Z",
    "assistant": "chatgpt", "prompt_id": "pr_01",
    "prompt_text": "best ai seo tools 2026",
    "answer_text": "…",
    "cited": true, "text_cited": true, "domain_cited": true,
    "position": 2, "matched_alias": "VectraSEO",
    "matched_source": { "url": "https://acme.com/blog/aeo-guide" },
    "sources": ["https://acme.com/blog/aeo-guide"],
    "competitors_cited": ["arvow.com"], "response_accurate": null,
    "model": "gpt-…", "cost_usd": 0.0021, "error": null
  }
]
GET/projects/:id/analytics/health/summary

Per-monitor site-health rollup. health_score, aeo_score, and issue counts live under each monitor latest_scan. No monitor → { has_monitor: false, monitors: [] }.

health-summary.json
{
  "has_monitor": true,
  "monitors": [
    {
      "monitor_id": "mon_3c1", "domain": "acme.com", "enabled": true,
      "last_scan_at": "2026-05-29T05:00:00Z", "next_scan_at": "2026-05-30T05:00:00Z",
      "latest_scan": {
        "scan_id": "scan_5b2", "finished_at": "2026-05-29T05:03:41Z",
        "urls_checked": 184, "health_score": 92,
        "issue_counts": { "critical": 0, "warning": 3, "info": 9 },
        "aeo_score": 78,
        "aeo_issue_counts": { "critical": 1, "warning": 4, "info": 6 }
      }
    }
  ]
}
GET/projects/:id/analytics/health/monitors/:mid/scans/:sid/issues

Issues from a scan. Returns { items, count, next_cursor }. Cursor-paginated: follow next_cursor (pass back as ?cursor=) until null; ?limit= defaults to 2000. There are no severity/category filter params (filter client-side).

health-issues.json
{
  "items": [
    {
      "scan_id": "scan_5b2", "rule_id": "missing_meta",
      "severity": "warning", "category": "seo",
      "url": "https://acme.com/pricing", "url_hash": "…",
      "message": "Page is missing a meta description.",
      "recommendation": "Add a 140-160 char description summarising the page.",
      "evidence": {}
    }
  ],
  "count": 47,
  "next_cursor": null
}
GET/projects/:id/analytics/ranks

Tracked keywords under items, each with a history array of { date, position, source }. top_wins_this_week carries the previous-position / jump deltas. ?days default 30, max 90.

ranks.json
{
  "project_id": "prj_8fa21c",
  "window_days": 30,
  "fetched_at": "2026-05-29T06:00:00Z",
  "schedule": { "cadence": "daily", "interval_hours": 24,
                "last_run_at": "2026-05-29T06:00:00Z", "next_run_at": "2026-05-30T06:00:00Z" },
  "items": [
    {
      "keyword": "answer engine optimization",
      "current_position": 6, "last_fetched_date": "2026-05-29", "current_source": "gsc",
      "history": [
        { "date": "2026-05-23", "position": 9, "source": "gsc" },
        { "date": "2026-05-29", "position": 6, "source": "gsc" }
      ]
    }
  ],
  "top_wins_this_week": [
    { "keyword": "answer engine optimization",
      "current_position": 6, "previous_position": 9, "jump": 3 }
  ]
}
[ END_OF_MANUAL ]
[ NEED_HELP? ]

Can't find what
you're looking for?

Reach out to the team. We answer every email and we read every bug report.