REST API + MCP server
SEO Report API for
Developers and AI Agents
Create reports over REST, poll them to completion, and read the same saved report your team sees on the website. The same API key from your paid plan connects any MCP-capable agent.
Access model
API access is account-linked and key-gated. Choose a plan, create an API key in your account, and every new site you run through the API uses your plan's credits, exactly as it would on the website. Credits reset on the first day of each month (UTC) and never roll over.
Website sessions, API calls, and agent sessions read from the same saved report state.
Create a report, poll for status, then read the full results from the same object.
Available endpoints
/api/v1/reports/previewCreate a score preview for partner integrations on a paid plan.
/api/v1/reportsCreate a new report or reuse one that already exists. Add "forceRerun": true to scan the site again instead.
/api/v1/reports/:idGet the latest report status and sections.
/api/v1/reports/:id/resultRead the full report results.
/api/v1/reports/:id/download?format=jsonExport the report payload as JSON for programmatic integrations.
Quickstart: an SEO report from curl
Three requests cover the whole flow, using an API key from your paid plan. The first creates the report, the second polls it until its status is no longer queued or running, and the third exports it. A new site uses one credit; running a site you already have a report for again does not use a credit.
export SEOREPORT_API_KEY="sr__live_your_api_key"
# Send the key as a header file so it never sits in curl's argv, where ps shows
# it to every local user. printf is a shell builtin, so it spawns no process.
auth() { printf 'Authorization: Bearer %s\n' "$SEOREPORT_API_KEY"; }
# 1. Create a report and keep its job ID
JOB_ID=$(curl -s -X POST https://seoreport.dev/api/v1/reports \
-H @<(auth) \
-H "Content-Type: application/json" \
-d '{"url": "example.com"}' | jq -r '.report.jobId')
# 2. Poll until the report is no longer queued or running
while :; do
STATUS=$(curl -s "https://seoreport.dev/api/v1/reports/$JOB_ID" \
-H @<(auth) | jq -r '.report.status')
case "$STATUS" in queued|running) sleep 3 ;; *) break ;; esac
done
echo "status: $STATUS"
# 3. Export the finished report (format=pdf, md and txt also work)
curl -s "https://seoreport.dev/api/v1/reports/$JOB_ID/download?format=json" \
-H @<(auth) -o report.jsonWhat the SEO report API returns
Every finished report exports as one JSON document: the overall score and its band, a score for each area, how many pages were analysed, open issues by severity, and every finding in fix order with why it matters, how to fix it, how to verify the fix, and the evidence and pages behind it. Markdown, text and PDF are rendered from the same diagnosis.
{
"exportVersion": 1,
"jobId": "3f6c2a1e-8d4b-4c7a-9e21-5b0d7f4a6c18",
"targetUrl": "https://example.com",
"status": "completed",
"isSnapshotReady": true,
"auditedAt": "2026-10-14T09:12:41.000Z",
"locale": "en",
"score": { "overall": 72, "band": "stable" },
"areas": [
{ "id": "access_crawl", "name": "Crawl & Index", "score": 61 },
{ "id": "metadata_onpage", "name": "On-Page SEO", "score": 78 },
{ "id": "security", "name": "Security", "score": 84 }
],
"pagesAnalyzed": 24,
"openIssues": { "critical": 0, "high": 2, "medium": 5, "low": 3, "total": 10 },
"findings": [
{
"rank": 1,
"title": "Render parity mismatch",
"status": "fail",
"severity": "high",
"area": { "id": "access_crawl", "name": "Crawl & Index" },
"whyItMatters": "Raw HTML and rendered DOM should tell the same SEO story so crawlers and AI systems do not see conflicting versions of the page.",
"fix": "Ensure raw HTML and rendered DOM contain the same critical SEO elements (title, H1, canonical, meta description, structured data). If content is injected by JavaScript, move it to server-side rendering so crawlers see it immediately.",
"verification": [
"Recheck these recorded examples: https://example.com/pricing. Method: compare the raw HTML with the rendered DOM. Previously observed: H1 present only after rendering",
"Expected after the change: the same critical elements in both. Obtain a fresh capture and compare the same check and URLs; a changed sample alone does not verify a fix."
],
"evidence": ["Raw HTML and rendered DOM were compared for critical elements."],
"pages": ["https://example.com/pricing"]
}
]
}Errors and limits
Each refusal below names its code. Handle these and a script never retries blindly.
| 402 | PAYMENT_REQUIRED | No paid plan is behind the request: the key is missing, invalid or revoked, or the account has no active plan. A missing key returns 402, not 401. |
| 402 | REPORT_CREDITS_EXHAUSTED | This month's new-site credits are used up. Re-running a site you already have a report for still works, and credits reset on the first day of each month (UTC). |
| 429 | FRESH_RUN_LIMIT | More than 30 fresh runs (forceRerun) in an hour for one account. Wait for the time in the Retry-After header. |
| 200 | status: failed | dead_lettered | The report could not finish. GET /api/v1/reports/:id returns error.code, error.message and error.retryable when the cause was recorded; retry only when retryable is true. |
| 200 | pollAfterMs | How long to wait before asking for the status again; 0 once the report is finished. |
Setup guides and recipes
Step-by-step pages for connecting an AI agent over MCP, calling the API from code, and comparing SEO APIs. In English.
Connect an AI agent (MCP)
- Connect SEOReport to Claude Code: MCP setup for SEO audits
- Connect SEOReport to Cursor: MCP setup for SEO audits
- Connect SEOReport to VS Code: MCP setup for GitHub Copilot
- Connect SEOReport to Windsurf (Devin Desktop): MCP setup
- Connect SEOReport to OpenAI Codex CLI: MCP setup for SEO audits
- Connect SEOReport to Gemini CLI: MCP setup for SEO audits
- Connect SEOReport to Claude Desktop: MCP setup for SEO audits
Call the API from code
SEO monitoring API
A domain registered for monitoring is re-audited every week. When something changes, the alert address receives an email: a new critical or high-severity finding, a resolved critical finding, or a move to a different score band. A week without a change sends nothing.
/api/v1/monitorsStarts weekly monitoring for a domain; "enabled": false pauses it.
/api/v1/monitorsLists the domains this account monitors.
/api/v1/monitors?url=Stops monitoring a domain and deletes its stored results.
# Uses the auth() helper from the quickstart above.
# Re-audit a domain every week and email [email protected] when it changes
curl -X PUT https://seoreport.dev/api/v1/monitors \
-H @<(auth) \
-H "Content-Type: application/json" \
-d '{"url": "example.com", "alertEmail": "[email protected]"}'
# List monitored domains
curl https://seoreport.dev/api/v1/monitors \
-H @<(auth)
# Stop monitoring (pass the host the list returns)
curl -X DELETE "https://seoreport.dev/api/v1/monitors?url=example.com" \
-H @<(auth)Monitoring is included with paid plans and does not spend report credits.
Official TypeScript Client
A typed client for the REST API. Authenticate with your plan's API key, then create, poll and export reports from TypeScript.
Command Line
Run reports from your terminal with your API key. One global install.
npm install -g @seoreport/clientMCP server — same API, same key
Point any MCP-capable client at https://seoreport.dev/mcp and authenticate with the same Bearer API key you use for REST. The report and account tools are advertised on connect, so an agent can run an audit and read the findings without any glue code.
{
"mcpServers": {
"seoreport": {
"url": "https://seoreport.dev/mcp",
"headers": {
"Authorization": "Bearer sr__live_your_api_key"
}
}
}
}seoreport_create_reportStart a report for a URL and get a job ID back.
seoreport_get_report_statusPoll a job until the report is ready.
seoreport_get_reportRead the finished report with its score and findings.
seoreport_list_reportsList the reports on the account.
seoreport_get_report_downloadGet a download URL for JSON, Markdown, text, or PDF.
seoreport_get_accountRead the account's plan, remaining credits and renewal date.
Checkout returns a browser link instead of charging directly: an agent can start it, and only a person can pay. Cancelling a plan, managing API keys and deleting the account stay in your dashboard.
Ready to build?
Choose a plan, create an API key, and start integrating SEO reports into your product.