{"openapi":"3.1.0","info":{"title":"SEO Score API","description":"Comprehensive SEO audit for any URL. Get a scored report with 80+ checks across on-page SEO, performance, accessibility, and AI readability, plus SXO/AEO/AIO scoring on paid plans. Free keys are scored on the 50+ core SEO and AI readability checks, and the free response details 2 checks per category and the top 2 priority fixes. Returns an overall score (0-100), letter grade, category breakdowns, AI readability score, and prioritized fix recommendations. (GEO / AI-search-visibility scoring is a separate /geo/audit endpoint with 26 additional checks.)\n\nAuthenticate every call with your key in the `X-API-Key` header.\n\n## Plain-English fixes\n\nEvery fix in `priorities` (on `GET /audit`, `POST /audit/batch` and `GET /geo/audit`) and in `ai_readability.recommendations` carries two extra fields next to the technical `issue` / `fix` text, so you can hand the output straight to a client:\n\n- `plain_english`: one sentence, no jargon, saying what is wrong and why it matters.\n- `who_fixes_it`: who usually makes the change: `developer`, `content` or `marketing`.\n\n```json\n{\n  \"severity\": \"medium\",\n  \"category\": \"meta\",\n  \"issue\": \"Thin content (180 words)\",\n  \"fix\": \"Page has thin content. Aim for 300+ words for SEO value.\",\n  \"plain_english\": \"The page has only 180 words, which is usually too little for search engines to rank it for anything useful.\",\n  \"who_fixes_it\": \"content\"\n}\n```\n\nThe sentences come from fixed per-check templates, not a language model, so the same audit always returns the same text and no claim is invented. The fields are additive: nothing existing was renamed or removed, so parsers that ignore unknown keys need no change.\n\n## Core Web Vitals (opt-in)\n\nAudits are fast because they do not wait on Google PageSpeed Insights. Add `cwv=true` to `GET /audit` (or `\"cwv\": true` to the `POST /audit/batch` body) when you want measured Core Web Vitals in the same response. It works on every plan, costs nothing extra and never changes the score. The first measurement of a URL adds about 10 seconds (the audit waits up to 25); it is cached for 24 hours, so repeats are instant.\n\n```bash\ncurl -s \"https://seoscoreapi.com/audit?url=https://example.com&cwv=true\" -H \"X-API-Key: $SEOSCORE_KEY\"\n```\n\nEvery audit carries a `core_web_vitals` object with the same keys. Read `status` first:\n\n| `status` | Meaning |\n|---|---|\n| `not_requested` | The default. Nothing was measured; `lcp_ms`, `inp_ms`, `cls`, `fcp_ms` and `ttfb_ms` are `null` and `hint` says how to ask. |\n| `ok` | Measured. `source` is `field` (real-user Chrome UX Report data) or `lab`; `checks` grades each metric against Google's thresholds. `_cached: true` means it came from the 24 hour cache; a cached measurement is included even without `cwv=true`. |\n| `unavailable` | You asked, but PageSpeed failed, rate limited us or was too slow. `reason` says which. The audit itself still succeeds and still counts. |\n| `unavailable` + `pending: true` | PageSpeed was still measuring when the wait ran out. It finishes in the background: audit the URL again and the numbers are there. |\n\n```json\n{\"status\": \"ok\", \"source\": \"field\", \"strategy\": \"mobile\", \"lcp_ms\": 2140, \"inp_ms\": 180, \"cls\": 0.04, \"fcp_ms\": 1320, \"ttfb_ms\": 410, \"checks\": [{\"name\": \"lcp\", \"status\": \"pass\", \"value\": \"2140ms\", \"score\": 100, \"metric\": \"Largest Contentful Paint\"}]}\n```\n\nWith `cwv=true`, set your HTTP client timeout to 60 seconds (180 for a batch).\n\n## Report exports (PDF, Markdown, CSV)\n\n`GET /audit/export?url=...&format=pdf|md|csv` runs the same audit as `GET /audit` (it counts as one audit, with the same plan gating) and returns it as a file: priority fixes with their plain-English explanation and who fixes them, then every check by category. CSV is one row per fix and per check, ready for a spreadsheet.\n\n```bash\ncurl -s -o report.pdf \"https://seoscoreapi.com/audit/export?url=https://example.com&format=pdf\"   -H \"X-API-Key: $SEOSCORE_KEY\"\n```\n\n**White-label (Pro and Ultra):** add `brand_name`, `brand_color` (`#rrggbb`) and `logo_url` (https, PNG/JPEG/WebP, up to 300 KB) to put your agency's name, colour and logo on the report in place of ours. Other plans get `403` for those parameters.\n\nThe hosted report page offers the same three downloads (`/report/{domain}?format=pdf|md|csv`) to anyone who can see that report in full.\n\n## Deep Site Audit (Pro and Ultra)\n\nA second, deeper audit of one URL: a catalog of **14,000+ checks across 9 dimensions** (technical foundation, crawlability, content and entities, Core Web Vitals, technical SEO, structured data and trust, security including an exposed-secret scan, media, off-site signals). Each audit fetches the page (plus robots.txt, sitemap, DNS, TLS and PageSpeed data), scores the thousands of checks that apply to it, then runs an AI analysis pass of up to 150 checks. About 90 seconds per audit, so it is asynchronous.\n\n**Included:** Pro 20 audits/month, Ultra 100/month (calendar month, UTC). Other plans can buy one-off credit packs. A failed audit gives its quota unit or credit back.\n\n**1. Start a job**\n\n```bash\ncurl -s -X POST https://seoscoreapi.com/site-audit \\\n  -H \"X-API-Key: $SEOSCORE_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com\"}'\n# {\"job_id\": \"3f9c2a7e…\", \"status\": \"queued\", \"poll\": \"/site-audit/3f9c2a7e…\"}\n```\n\nOptional body fields: `business_type` (`saas`, `local_service`, `ecommerce`, `storefront`, `blog`, `publisher`), `is_local`, `webhook_url`.\n\n**2. Poll until `completed` or `failed`** (every 5-10 seconds)\n\n```bash\ncurl -s https://seoscoreapi.com/site-audit/3f9c2a7e… -H \"X-API-Key: $SEOSCORE_KEY\"\n# queued    {\"status\": \"queued\", \"queue_position\": 2, \"eta_seconds\": 150, ...}\n# running   {\"status\": \"running\", \"progress\": 60, \"stage\": \"Section 6\", ...}\n# completed {\"status\": \"completed\", \"result\": {\"scores\": {...}, \"sections\": {...}, \"findings\": [...], \"coverage\": {...}}}\n# failed    {\"status\": \"failed\", \"error\": \"...\"}\n```\n\n`result.scores.lai_score` is the headline score on a 0-5 scale with `lai_grade`; `section_scores` has one score per dimension; `findings` lists failing checks by severity with evidence. Only the key that started a job can read it.\n\n**Webhook (optional).** Pass `webhook_url` and we POST `{\"job_id\", \"status\": \"completed\", \"result\"}` to it once the job completes. It is a single attempt (10 s timeout, no redirects, no retries, no signature) and nothing is sent for a failed job, so treat it as a hint and keep polling as the source of truth.\n\n**Quota.** `GET /deep-audit/usage` returns this month's `site_audit.used` / `remaining` (separate from `GET /usage`, which covers the per-URL audit).\n\n**Errors.** `400` URL or webhook is not a public http(s) address · `401` missing or invalid key · `402` no Deep Audit credits left (plans without Deep Audit) · `404` unknown job, or a job started by another key · `429` rate limit (60 requests/minute per key), monthly quota used up, or the audit queue is full: honour `Retry-After` · `503` temporarily unavailable, retry.\n\nThe same endpoints remain available at `https://engine.seoscoreapi.com` for existing integrations.\n\n## Public scoreboard\n\nAudits made with `GET /audit` and `POST /audit/batch` (and the keyless homepage demo) add the audited site to the public [scoreboard](https://seoscoreapi.com/scoreboard), which lists the top 100 sites by score. A row holds only the domain, the URL audited, score, grade, top issues, when it was last audited and how many times. **No API key, email or account is stored with it or shown.** Rows are per domain, so a site anyone audits can appear.\n\nTo keep your audits off it, opt your key out (`opt_out=false` turns it back on):\n\n```bash\ncurl -s -X PUT \"https://seoscoreapi.com/scoreboard/opt-out?opt_out=true\" -H \"X-API-Key: $SEOSCORE_KEY\"\n# {\"scoreboard_opt_out\": true, \"message\": \"Your audits will no longer appear on the scoreboard.\"}\n```\n\nThe setting is per key, survives key rotation, and applies to audits made after it is set; it does not remove a site that is already listed. Deep Site Audits never write to the scoreboard.\n","version":"1.0.0"},"paths":{"/tools/meta-checker":{"get":{"summary":"Meta Checker","operationId":"meta_checker_tools_meta_checker_get","parameters":[{"name":"url","in":"query","required":false,"schema":{"type":"string","default":"","title":"Url"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tools/robots-txt-tester":{"get":{"summary":"Robots Txt Tester","operationId":"robots_txt_tester_tools_robots_txt_tester_get","parameters":[{"name":"url","in":"query","required":false,"schema":{"type":"string","default":"","title":"Url"}},{"name":"path","in":"query","required":false,"schema":{"type":"string","default":"","title":"Path"}},{"name":"ua","in":"query","required":false,"schema":{"type":"string","default":"Googlebot","title":"Ua"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tools/schema-validator":{"get":{"summary":"Schema Validator Tool","operationId":"schema_validator_tool_tools_schema_validator_get","parameters":[{"name":"url","in":"query","required":false,"schema":{"type":"string","default":"","title":"Url"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tools/og-preview":{"get":{"summary":"Og Preview","operationId":"og_preview_tools_og_preview_get","parameters":[{"name":"url","in":"query","required":false,"schema":{"type":"string","default":"","title":"Url"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/site-audit":{"post":{"tags":["Deep Site Audit"],"summary":"Start a Deep Site Audit (async)","description":"Queue a Deep Site Audit of one URL and get a `job_id` back immediately.\n\nThe audit fetches the page and its supporting signals (robots.txt, sitemap,\nDNS, TLS, PageSpeed), runs the thousands of catalog checks that apply to it, then an AI analysis pass of up to 150 checks. It takes\nabout 90 seconds once it starts, so poll `GET /site-audit/{job_id}`.\n\n**Included on Pro (20/month) and Ultra (100/month).** Any other key spends one\npurchased Deep Audit credit per audit. A failed audit gives its quota unit or\ncredit back.","operationId":"site_audit_start_site_audit_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepAuditRequest"}}}},"responses":{"200":{"description":"Job queued.","content":{"application/json":{"schema":{},"example":{"job_id":"3f9c2a7e1b5d4c8f9a0e6b2d7c1f4a93","status":"queued","poll":"/site-audit/3f9c2a7e1b5d4c8f9a0e6b2d7c1f4a93"}}}},"400":{"description":"URL or webhook refused (not a public http(s) address)."},"402":{"description":"No Deep Audit credits left (keys without Pro/Ultra). Buy a credit pack or upgrade."},"401":{"description":"Missing or invalid API key."},"429":{"description":"Rate limit, monthly quota, or queue backpressure. Honour `Retry-After`."},"503":{"description":"Engine temporarily unavailable. Retry after `Retry-After` seconds."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deep-audit/usage":{"get":{"tags":["Deep Site Audit"],"summary":"Deep Site Audit quota for this key","description":"Deep Site Audits used and remaining this calendar month (UTC) for this key.\n\nSeparate from `GET /usage`, which reports the per-URL audit allowance. Keys\nwithout Pro/Ultra show `remaining: 0` here and run on credits instead; see\nyour dashboard for the credit balance.","operationId":"site_audit_usage_deep_audit_usage_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"This month's Deep Site Audit usage.","content":{"application/json":{"schema":{},"example":{"tier":"pro","site_audit":{"used":3,"remaining":17},"serp":{"used":0,"remaining":250}}}}},"401":{"description":"Missing or invalid API key."},"429":{"description":"Rate limit, monthly quota, or queue backpressure. Honour `Retry-After`."},"503":{"description":"Engine temporarily unavailable. Retry after `Retry-After` seconds."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/site-audit/{job_id}":{"get":{"tags":["Deep Site Audit"],"summary":"Poll a Deep Site Audit","description":"Status of a Deep Site Audit: `queued` (with `queue_position` and\n`eta_seconds`), `running` (with `progress` 0-100 and `stage`), `completed`\n(with `result`) or `failed` (with `error`). Poll every 5-10 seconds. Only the\nkey that started a job can read it.","operationId":"site_audit_poll_site_audit__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Job state. `result` is present once `status` is `completed`.","content":{"application/json":{"schema":{},"examples":{"queued":{"value":{"job_id":"3f9c…","status":"queued","progress":0,"queue_position":2,"eta_seconds":150}},"running":{"value":{"job_id":"3f9c…","status":"running","progress":60,"stage":"Section 6"}},"completed":{"value":{"job_id":"3f9c…","status":"completed","progress":100,"stage":"done","result":{"website_url":"https://example.com","scores":{"lai_score":3.23,"lai_grade":"fair","seo_score":2.53,"ai_score":3.66,"section_scores":{"1":4.37,"2":2.69,"9":1.04},"tasks_scored":5782,"tasks_failed":1779},"sections":{"1":{"name":"Technical Foundation & Rendering","score":4.37}},"findings":[{"task_id":"2.2.01","section":2,"severity":"high","weight":"critical","evidence":"No XML sitemap found","count":1}],"coverage":{"scored_tasks":5782,"hybrid_ai_tasks":150,"total_tasks":14385}}}},"failed":{"value":{"job_id":"3f9c…","status":"failed","progress":40,"stage":"Section 4","error":"…"}}}}}},"404":{"description":"Unknown job, or a job started by a different key."},"401":{"description":"Missing or invalid API key."},"429":{"description":"Rate limit, monthly quota, or queue backpressure. Honour `Retry-After`."},"503":{"description":"Engine temporarily unavailable. Retry after `Retry-After` seconds."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/signup":{"post":{"summary":"Signup","description":"Start signup: send a verification code to your email. Send JSON: {\"email\": \"you@example.com\"}","operationId":"signup_signup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]},"example":{"email":"you@example.com"}}}}}},"/verify":{"post":{"summary":"Verify","description":"Complete signup: verify your code and get your API key. Send JSON: {\"email\": \"you@example.com\", \"code\": \"123456\"}","operationId":"verify_verify_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"code":{"type":"string"}},"required":["email","code"]},"example":{"email":"you@example.com","code":"123456"}}}}}},"/usage":{"get":{"summary":"Usage","description":"Check your API usage and limits.","operationId":"usage_usage_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/upgrade":{"post":{"summary":"Upgrade","description":"Create a Stripe Checkout session to upgrade your plan. Send JSON: {\"email\": \"...\", \"tier\": \"basic\"}","operationId":"upgrade_upgrade_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"tier":{"type":"string","enum":["starter","basic","pro","ultra"]}},"required":["email","tier"]},"example":{"email":"you@example.com","tier":"basic"}}}}}},"/ai-readability":{"get":{"summary":"Ai Readability","description":"Score how well a page can be consumed by AI/LLM systems. Requires an API key.","operationId":"ai_readability_ai_readability_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The URL to analyze for AI readability","title":"Url"},"description":"The URL to analyze for AI readability"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/trackers":{"get":{"summary":"Tracker Inventory","description":"List the third-party trackers and pixels a page loads.\n\nLoads the page in a real browser, waits a few seconds, and reports every analytics,\nadvertising, session-replay, chat, marketing-automation, A/B-testing and monitoring\ntool it saw, including pixels a tag manager injects (which never appear in the page\nsource).\n\nEach item in `trackers` has `vendor`, `category`, `found_in` (`html`, `network`),\n`injected` (seen on the network but not in the source), `requests`,\n`transfer_bytes`, `evidence` (up to 3 URLs) and, where one is exposed, `ids`\n(a GA4, GTM or Google Ads id). `summary` totals them by category and names the\n`consent_manager` on the page, if any.\n\nThis lists what loaded during one visit with no interaction. It does not determine\nwhether a tracker waited for consent, and it is not legal advice.\n\nCounts as one audit against your plan. A page we can't load returns **422** with\n`reason`, and is not counted.","operationId":"tracker_inventory_trackers_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The page to inspect (e.g., https://example.com)","title":"Url"},"description":"The page to inspect (e.g., https://example.com)"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/conversion":{"get":{"summary":"Conversion Score","description":"Score how well a page turns a visitor into a lead or a sale.\n\nReads the page's HTML (the same fetch `/audit` uses: plain HTTP, then a real browser\nwhen the page is built by JavaScript) and scores five areas from 0 to 100:\n\n- `headline`: one H1 that says what the page offers, with a sentence under it\n- `cta`: a call to action near the top, worded as an action, repeated down the page.\n  A phone link and \"Add to cart\" both count\n- `trust`: testimonials, ratings, guarantees, contact details, credentials\n- `forms`: how many fields the form asks for, and whether they are labeled\n- `objections`: price or a path to it, FAQ, what happens next, shipping and returns\n\nReturns `score`, `grade`, `page_type`, `categories` (per-area score, weight and\nchecks), `signals` (what we found: the H1, the button labels, the trust evidence)\nand `priorities`, the fix list. Every priority has `severity`, `category`, `issue`,\n`fix`, `plain_english` and `who_fixes_it` (`developer` | `content` | `marketing`),\nplus `evidence` where there is some.\n\n**What it does not do.** It does not measure your conversion rate; only your\nanalytics can. \"Near the top\" is source order, not pixels: we do not lay the page\nout. A form embedded from another service (HubSpot, Calendly, Typeform) is reported\nbut not scored, and a page with no form is not marked down for it: `forms.score`\nis `null` and its weight goes to the other areas. A page over 3 MB is scored on what\nwe read, and nothing is reported as missing.\n\nCounts as one audit against your plan. A page we can't load or can't read returns\n**422** with `reason` and is not counted. Free keys get the scores and the first\ntwo priorities; paid plans get the full list. `?include=conversion` on `/audit`\n(paid plans) adds the same block to an audit at no extra charge.","operationId":"conversion_score_conversion_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The page to score (e.g., https://example.com/services)","title":"Url"},"description":"The page to score (e.g., https://example.com/services)"},{"name":"page_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`local_service`, `ecommerce`, `saas` or `general`. Detected from the page when omitted.","title":"Page Type"},"description":"`local_service`, `ecommerce`, `saas` or `general`. Detected from the page when omitted."},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/quick-wins":{"post":{"summary":"Page Two Quick Wins","description":"Find the page-2 quick wins in your Search Console data.\n\nSend your own Search Console rows and get back the queries ranking 11-20 that are\nworth working on first, each with the page it lands on, an opportunity score and an\nestimate of the extra clicks from moving it onto page 1.\n\n**We do not connect to your Search Console.** You export the rows (Performance\nreport CSV, or the Search Analytics API with the `query` and `page` dimensions)\nand send them. Nothing is fetched and nothing is stored.\n\nSend JSON with either `rows` or `csv`:\n\n- `rows`: `[{\"query\": \"...\", \"page\": \"https://...\", \"clicks\": 3, \"impressions\": 900, \"position\": 11.4}]`.\n  The API's own shape (`{\"keys\": [\"query\", \"page\"], \"clicks\": ...}`) works too. `page` is optional.\n- `csv`: the export as text, with a header row. Column names are matched\n  (`Top queries`/`Query`, `Page`, `Clicks`, `Impressions`, `Position`).\n- `min_impressions` (default 50), `target_position` (1-10, default 5), `limit` (default 25, max 200)\n- `exclude_terms`: words to leave out, such as your brand name\n- `ctr_curve`: your own expected click-through rate by position, `{\"1\": 0.28, \"2\": 0.15}`\n\nEach item in `quick_wins` has `query`, `page`, `position`, `impressions`, `clicks`,\n`ctr`, `expected_ctr`, `opportunity_score` (0-100: 40% how close to page 1, 40%\nimpressions, 20% how far clicks fall short of expected), `estimated_extra_clicks`\nat the target position with a range (position 10 to position 3), an `action`\n(`small_push`, `improve_page`, `fix_snippet`, `consolidate`) and a `plain_english`\nsentence. `also_ranking_pages` lists other pages of yours showing for the same query.\n`pages` groups the wins by landing page.\n\n**Read the numbers as estimates.** Google publishes no click-through curve; the\ndefault is a rough one. Extra clicks hold impressions constant and assume every\nimpression is a person. Position is an average over the export's dates, countries\nand devices.\n\n**Send the whole export, not only page 2.** With 500 or more page-1 impressions in\nthe rows, `ctr_calibration` compares the clicks your page-1 results earned with\nwhat the curve predicts (`ratio`), and each win also gets\n`estimated_extra_clicks_calibrated` (the estimate times that ratio). A ratio far\nbelow 1 usually means many of the impressions are rank trackers or bots.\n\nWorks on every plan. Counts as one audit; a request we reject (400) is not counted.\nUp to 1 MB of JSON per request (roughly 5,000 rows with URLs); filter the export\nto positions 11-20 first if yours is larger.","operationId":"page_two_quick_wins_quick_wins_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object"},"description":"Search Console rows: query, page (optional), clicks, impressions, position."},"csv":{"type":"string","description":"The Performance export as text, with its header row. Send rows or csv."},"min_impressions":{"type":"integer","default":50},"target_position":{"type":"integer","minimum":1,"maximum":10,"default":5},"limit":{"type":"integer","maximum":200,"default":25},"exclude_terms":{"type":"array","items":{"type":"string"}},"ctr_curve":{"type":"object","additionalProperties":{"type":"number"},"description":"Expected click-through rate by position."}}},"example":{"rows":[{"query":"seo audit api","page":"https://example.com/","clicks":3,"impressions":900,"position":11.4}]}}}}}},"/crawl":{"post":{"summary":"Start Site Crawl","description":"Start a multi-page crawl of one site (async).\n\nFollows same-site links from `url`, plus the URLs in the sitemap, up to your page cap,\nand reports broken pages, redirects, duplicate titles and headings, pages missing a\ntitle or heading, orphan pages (in the sitemap, linked from nowhere crawled) and slow\npages. Plain HTTP requests, 4 at a time, robots.txt honoured.\n\n**Limits.** Pro: 25 pages per crawl, 20 crawls a month. Ultra: 100 pages, 100 crawls a\nmonth. Any other plan: one Deep Audit credit covers a 25-page crawl. A failed crawl is\nnot counted and a credit is returned.\n\nReturns `job_id`; poll `GET /crawl/{job_id}`. `site_map` is a shareable page with the\nsite diagram once the crawl has finished.","operationId":"start_site_crawl_crawl_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CrawlRequest"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/crawl/{job_id}":{"get":{"summary":"Get Site Crawl","description":"Poll a site crawl. `status` is `queued`, `running`, `completed` or `failed`.\n\nWhile running, `pages_done` counts up. When completed, `result` holds `summary`,\n`issues` (broken_links, redirects, duplicate_titles, duplicate_h1, missing_title,\nmissing_h1, orphan_pages, slow_pages, noindex_pages, rate_limited), `pages` (one row\nper URL: status, depth, redirects, response_ms, title, h1, canonical, inlinks) and\n`links` (the internal link graph). Only the key that started a crawl can read it.","operationId":"get_site_crawl_crawl__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audit":{"get":{"summary":"Audit","description":"Run a comprehensive SEO audit on any URL.\n\nReturns an overall score (0–100), letter grade, prioritized fix\nrecommendations, and a `audit` block of category breakdowns\n(SEO, performance, accessibility, AI readability).\n\nPaid plans (Starter $5/mo and up) additionally receive:\n  - `sxo`, `aeo`, `aio` — extended scoring blocks\n  - `history` — delta vs the previous audit for this URL\n    (overall score, grade change, per-category deltas, days since)\n  - Full priorities list and uncapped per-category checks\n\nEvery priority carries `plain_english` (one jargon-free sentence) and\n`who_fixes_it` (`developer` | `content` | `marketing`) next to `issue`/`fix`.\n\n`?include=trackers` (paid plans) adds a `trackers` block: the same inventory as\n`GET /trackers`, at no extra audit. It adds a few seconds.\n\n`?include=conversion` (paid plans) adds a `conversion` block: the same score and\nfix list as `GET /conversion`, at no extra audit. Combine them: `?include=trackers,conversion`.\n\nFree / demo keys see gated placeholders for the paid blocks\n(`_extended_gated`, `history._gated`, `_priorities_gated`).\n\n**Core Web Vitals are opt-in: `?cwv=true`** (every plan, no extra charge, never\npart of the score). The response always carries a `core_web_vitals` object with\n`lcp_ms`, `inp_ms`, `cls`, `fcp_ms`, `ttfb_ms`, `checks` and a `status`:\n\n  - `not_requested` (the default): no measurement was made; the metrics are\n    `null` and `hint` says how to ask. A default audit never waits on PageSpeed.\n  - `ok`: measured by Google PageSpeed Insights. `source` is `field` (real-user\n    Chrome UX Report data) or `lab`; `_cached: true` when it came from the\n    24 hour cache. A cached measurement is included even without `cwv=true`,\n    because it costs no time.\n  - `unavailable`: `cwv=true` was set but PageSpeed failed, rate limited us or\n    was too slow; `reason` says which. The audit itself still succeeds.\n  - `unavailable` with `pending: true`: PageSpeed was still measuring when the\n    wait ran out (about 25 seconds). The measurement finishes in the\n    background; the next audit of that URL has it.\n\nWith `cwv=true` the first audit of a URL takes about 10 seconds longer; repeats\nwithin 24 hours are instant. Set your client timeout to 60 seconds.\n\nRequires an API key passed in the `X-API-Key` header.","operationId":"audit_audit_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The URL to audit (e.g., https://example.com)","title":"Url"},"description":"The URL to audit (e.g., https://example.com)"},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated extras on paid plans: `trackers` (tracker and pixel inventory) and `conversion` (conversion score). Each adds a few seconds.","title":"Include"},"description":"Comma-separated extras on paid plans: `trackers` (tracker and pixel inventory) and `conversion` (conversion score). Each adds a few seconds."},{"name":"cwv","in":"query","required":false,"schema":{"type":"boolean","description":"Set `cwv=true` to include measured Core Web Vitals (LCP, INP, CLS, FCP, TTFB from Google PageSpeed Insights) in `core_web_vitals`. Off by default because the first measurement of a URL adds about 10 seconds (up to 25); it is then cached for 24 hours. Available on every plan, costs nothing extra and never changes the score.","default":false,"title":"Cwv"},"description":"Set `cwv=true` to include measured Core Web Vitals (LCP, INP, CLS, FCP, TTFB from Google PageSpeed Insights) in `core_web_vitals`. Off by default because the first measurement of a URL adds about 10 seconds (up to 25); it is then cached for 24 hours. Available on every plan, costs nothing extra and never changes the score."},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audit/export":{"get":{"summary":"Audit Export","description":"Run an audit and download it as a PDF, Markdown or CSV report.\n\nSame audit, same usage and same plan gating as `GET /audit` (it counts as one\naudit): the file contains exactly what your key's `/audit` JSON contains,\nincluding `plain_english` and `who_fixes_it` on every priority fix. Free keys get\nthe free slice with a note on what the full report adds.\n\n**White-label (Pro and Ultra):** `brand_name`, `brand_color` and `logo_url` put your\nagency's name, colour and logo on the report instead of ours. On other plans\nthose parameters return `403`.","operationId":"audit_export_audit_export_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The URL to audit (e.g., https://example.com)","title":"Url"},"description":"The URL to audit (e.g., https://example.com)"},{"name":"format","in":"query","required":true,"schema":{"type":"string","description":"pdf | md | csv","title":"Format"},"description":"pdf | md | csv"},{"name":"brand_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"White-label: your agency name (Pro and Ultra)","title":"Brand Name"},"description":"White-label: your agency name (Pro and Ultra)"},{"name":"brand_color","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"White-label: accent colour, #rrggbb (Pro and Ultra)","title":"Brand Color"},"description":"White-label: accent colour, #rrggbb (Pro and Ultra)"},{"name":"logo_url","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"White-label: https URL of a PNG/JPEG/WebP logo, max 300 KB (Pro and Ultra)","title":"Logo Url"},"description":"White-label: https URL of a PNG/JPEG/WebP logo, max 300 KB (Pro and Ultra)"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/compare":{"post":{"summary":"Compare Urls","description":"Compare 2–5 URLs side by side with a structured diff.\n\nReturns each URL's score + category breakdown plus a `diff` object\nthat tells you who is ahead and by how much, per category, per URL\npair. Built for agencies who embed comparisons in sales decks and\nfor devs who want a one-call sanity check across an old vs. new\ndeploy.\n\nSend JSON: {\"urls\": [\"https://a.com\", \"https://b.com\", ...]}\nRequires Basic plan ($15/mo) or higher.","operationId":"compare_urls_compare_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":5}},"required":["urls"]},"example":{"urls":["https://a.com","https://b.com"]}}}}}},"/audit/batch":{"post":{"summary":"Audit Batch","description":"Audit multiple URLs in one request. Paid plans only (Starter $5/mo and up).\n\nEach URL is audited concurrently and counts against your monthly\naudit quota. Results include the same `history` delta block as\n`/audit` and the extended `sxo`/`aeo`/`aio` scores.\n\nSend JSON: {\"urls\": [\"https://a.com\", \"https://b.com\", ...]}\nMax 10 URLs per request. URLs that fail validation are returned\nwith an `error` field instead of a score.\n\nAdd `\"cwv\": true` to the body to include measured Core Web Vitals for every\nURL (see `GET /audit` for the `core_web_vitals` statuses). It is off by default:\neach result then says `status: \"not_requested\"`, or carries a measurement that\nwas already cached. With it on, the measurements run side by side while the\nURLs are audited, and the batch as a whole waits at most about 50 seconds on\nthem; a URL whose measurement is not ready reads `unavailable` + `pending: true`\nand has it on the next audit. Set your client timeout to 180 seconds.","operationId":"audit_batch_audit_batch_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key from /signup","title":"X-Api-Key"},"description":"Your API key from /signup"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":10},"cwv":{"type":"boolean","default":false,"description":"Include measured Core Web Vitals for every URL. Off by default: it is slower. See `core_web_vitals` on `GET /audit`."}},"required":["urls"]},"example":{"urls":["https://a.com","https://b.com"]}}}}}},"/llms-generator":{"get":{"summary":"Llms Generator","description":"Generate an llms.txt file for any domain.\n\nFree / no-key: basic version. Basic plan ($15/mo) and higher: curated version\nwith per-page descriptions pulled from each page's meta. Returns plain text\nsuitable for saving directly to /llms.txt on the user's site.","operationId":"llms_generator_llms_generator_get","parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string","description":"Domain to generate llms.txt for (e.g. example.com)","title":"Domain"},"description":"Domain to generate llms.txt for (e.g. example.com)"},{"name":"X-API-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/backlinks":{"get":{"summary":"Backlinks Lookup","description":"Return observed backlinks for a target domain.\n\nAudit-fed dataset: every audit run by SEO Score API customers contributes\nobservations. Not a comprehensive backlink index — see `data_caveat` in the\nresponse. Requires Basic plan ($15/mo) or higher.","operationId":"backlinks_lookup_backlinks_get","parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string","description":"Target domain (e.g. example.com)","title":"Domain"},"description":"Target domain (e.g. example.com)"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"description":"Max sample rows to return","default":50,"title":"Limit"},"description":"Max sample rows to return"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history":{"get":{"summary":"History","description":"Return historical audit scores + summary trend for a URL audited by this key. Requires Starter plan ($5/mo) or higher.","operationId":"history_history_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The URL whose audit history to fetch","title":"Url"},"description":"The URL whose audit history to fetch"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Max number of points to return","default":100,"title":"Limit"},"description":"Max number of points to return"},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"UNIX timestamp lower bound (inclusive)","title":"Since"},"description":"UNIX timestamp lower bound (inclusive)"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/history/domains":{"get":{"summary":"History Domains","description":"List every domain this key has audited with latest score and 30-day trend. Requires Starter plan ($5/mo) or higher.","operationId":"history_domains_history_domains_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geo/audit":{"get":{"summary":"Geo Audit","description":"Run a GEO (Generative Engine Optimization) audit — 26 checks measuring how visible your page is to LLMs. Requires Basic plan ($15/mo) or higher.","operationId":"geo_audit_geo_audit_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The URL to audit for GEO optimization","title":"Url"},"description":"The URL to audit for GEO optimization"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audit/accessibility":{"get":{"summary":"Ada Audit","description":"Run an ADA / WCAG 2.1 AA accessibility compliance audit. Paid plans only.\n\nReturns a detailed accessibility report including:\n- Overall compliance score and grade (WCAG 2.1 A/AA rules only)\n- Lawsuit risk assessment (high/medium/low/minimal)\n- Category breakdowns (images, forms, contrast, keyboard, ARIA, etc.)\n- `violations`: WCAG 2.1 AA failures, with affected elements and a plain-English fix\n- `best_practices`: axe best-practice findings (e.g. heading-order). Not WCAG\n  requirements, so they never lower the score or raise the risk level\n- `needs_review`: checks axe couldn't decide automatically, with what to verify by hand.\n  They are excluded from the score rather than counted as failures\n- `priorities`: WCAG violations first, then best practices. `severity` maps from axe\n  `impact` one-to-one: critical→critical, serious→high, moderate→medium, minor→low\n  (best practices are always low)\n\n**Limits.** ADA audits have their own monthly allowance (`ada_monthly`: Starter 5,\nBasic 20, Pro 100, Ultra 500), separate from your audit quota. Each key may run\n20 ADA audits per minute and 2 at a time; the tier `rpm` does not apply here.\n`GET /usage` reports `ada_usage_this_month` and `ada_remaining`.\nA 429 includes `Retry-After`, and a 429 is never counted against `ada_monthly`\n(nor is any failed audit).\n\n**Errors.** A page we can't load returns **422** with `detail` (message) and\n`reason`: `blocked` (the site refused our crawler), `timeout`, `dns`, `tls`,\n`unreachable`, `not_found`, `http_error`, `non_html`, `redirect_loop`,\n`blocked_url`, `load_failed`. A URL we refuse up front (private/internal address,\nmalformed URL) is **400** with `reason` `blocked_url` / `invalid_url`. A **502**\nmeans the failure was on our side.\n\nUses the axe-core accessibility engine (industry standard) to check\nagainst WCAG 2.1 Level AA — the standard referenced in most ADA lawsuits.","operationId":"ada_audit_audit_accessibility_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","description":"The URL to audit for ADA/WCAG compliance","title":"Url"},"description":"The URL to audit for ADA/WCAG compliance"},{"name":"include","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"`trackers` adds the tracker and pixel inventory to the report","title":"Include"},"description":"`trackers` adds the tracker and pixel inventory to the report"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geo/brand-probe":{"post":{"summary":"Geo Brand Probe","description":"Probe LLMs to measure how often your brand is mentioned in AI responses. Requires Basic plan ($15/mo) or higher.\n\nSend JSON: {\"brand\": \"MyBrand\", \"domain\": \"mybrand.com\", \"prompts\": [\"What are the best X?\"], \"models\": [\"claude\", \"nova\"], \"runs_per_prompt\": 3}","operationId":"geo_brand_probe_geo_brand_probe_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string"},"domain":{"type":"string"},"prompts":{"type":"array","items":{"type":"string"}},"models":{"type":"array","items":{"type":"string"}},"runs_per_prompt":{"type":"integer","default":3}},"required":["brand"]},"example":{"brand":"MyBrand","domain":"mybrand.com","prompts":["What are the best X?"],"models":["claude","nova"],"runs_per_prompt":3}}}}}},"/citations/trackers":{"post":{"tags":["AI Citations"],"summary":"Create Citation Tracker","description":"Track a brand's visibility in AI answers. Requires Starter ($5/mo) or higher.\n\nSend JSON: {\"brand\": \"Acme\", \"domains\": [\"acme.com\"], \"prompts\": [\"best CRM for agencies\"],\n\"competitors\": [\"Rival\"], \"engines\": [\"chatgpt\",\"gemini\",\"perplexity\",\"claude\"],\n\"samples\": 3, \"cadence\": \"weekly\", \"webhook_url\": \"https://...\"}\n\n**No prompts yet?** Leave `prompts` out and send `\"starter\": {\"topic\": \"CRM\",\n\"audience\": \"agencies\"}` instead. The tracker is created with a starter set built\nfrom `topic`, your `brand` and `competitors` (the same list\n`GET /citations/prompts/starter` returns), cut to the tracked prompts your plan has\nleft and to what one run can spend of your monthly checks at the tracker's engines\nand samples. With no `cadence`, a starter tracker runs weekly when the allowance\ncovers a month of weekly runs, otherwise monthly. The response's `starter` block\nsays how many were generated and kept, the checks per run and the cadence chosen.\nEdit them later with `PATCH`.\n\nMonthly allowance (checks / tracked prompts): Starter 150 / 15, Basic 500 / 30,\nPro 1,500 / 75, Ultra 4,000 / 200. A check is one prompt on one engine, sampled once.","operationId":"create_citation_tracker_citations_trackers_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string"},"prompts":{"type":"array","items":{"type":"string"},"description":"The questions to ask the AI engines."},"engines":{"type":"array","items":{"type":"string","enum":["chatgpt","gemini","perplexity","claude"]}},"competitors":{"type":"array","items":{"type":"string"}},"domains":{"type":"array","items":{"type":"string"}},"samples":{"type":"integer","minimum":1,"maximum":5,"default":3},"cadence":{"type":"string","enum":["daily","weekly","monthly","manual"]},"webhook_url":{"type":"string","format":"uri","description":"https only."},"starter":{"type":"object","description":"Send instead of prompts to start from a generated set.","properties":{"topic":{"type":"string"},"audience":{"type":"string"}}}},"required":["brand"]},"example":{"brand":"Acme","domains":["acme.com"],"prompts":["best CRM for agencies"],"competitors":["Rival"],"engines":["chatgpt","gemini","perplexity","claude"],"samples":3,"cadence":"weekly"}}}}},"get":{"tags":["AI Citations"],"summary":"List Citation Trackers","description":"List this key's citation trackers.\n\n`usage` reports the month and any top-up: `checks_limit`, `checks_used` and\n`checks_remaining` are the plan's monthly allowance; `topup_checks_remaining` is the\npurchased balance (spent only after the month's checks, never reset, expires 12 months\nafter purchase: `topup_next_expiry`); `checks_available` is what a run can spend now.\nThe same block is on `GET /usage` as `citations`.","operationId":"list_citation_trackers_citations_trackers_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/trackers/{tracker_id}":{"get":{"tags":["AI Citations"],"summary":"Get Citation Tracker","description":"Read one tracker.","operationId":"get_citation_tracker_citations_trackers__tracker_id__get","parameters":[{"name":"tracker_id","in":"path","required":true,"schema":{"type":"integer","title":"Tracker Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["AI Citations"],"summary":"Update Citation Tracker","description":"Edit a tracker's prompts, engines, competitors, samples, cadence or webhook.","operationId":"update_citation_tracker_citations_trackers__tracker_id__patch","parameters":[{"name":"tracker_id","in":"path","required":true,"schema":{"type":"integer","title":"Tracker Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompts":{"type":"array","items":{"type":"string"},"description":"The questions to ask the AI engines."},"engines":{"type":"array","items":{"type":"string","enum":["chatgpt","gemini","perplexity","claude"]}},"competitors":{"type":"array","items":{"type":"string"}},"domains":{"type":"array","items":{"type":"string"}},"samples":{"type":"integer","minimum":1,"maximum":5,"default":3},"cadence":{"type":"string","enum":["daily","weekly","monthly","manual"]},"webhook_url":{"type":"string","format":"uri","description":"https only."}}},"example":{"prompts":["best CRM for agencies"],"cadence":"monthly"}}}}},"delete":{"tags":["AI Citations"],"summary":"Delete Citation Tracker","description":"Stop tracking a brand. Run history is kept until its retention expires.","operationId":"delete_citation_tracker_citations_trackers__tracker_id__delete","parameters":[{"name":"tracker_id","in":"path","required":true,"schema":{"type":"integer","title":"Tracker Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/trackers/{tracker_id}/run":{"post":{"tags":["AI Citations"],"summary":"Run Citation Tracker","description":"Run a tracker now. Every prompt × engine × sample counts as one check.\n\nA run needs all of its checks up front: the month's remaining allowance plus any\ntop-up balance. If that is short the run is refused with 429 and nothing is spent.\nBuy more with `POST /citations/topups/checkout`. A check whose engine returned an\nerror is not counted against either balance.","operationId":"run_citation_tracker_citations_trackers__tracker_id__run_post","parameters":[{"name":"tracker_id","in":"path","required":true,"schema":{"type":"integer","title":"Tracker Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/runs/{run_id}":{"get":{"tags":["AI Citations"],"summary":"Get Citation Run","description":"Run status plus every per-prompt, per-engine result.","operationId":"get_citation_run_citations_runs__run_id__get","parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"integer","title":"Run Id"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/trackers/{tracker_id}/history":{"get":{"tags":["AI Citations"],"summary":"Citation Tracker History","description":"Timeseries of mention rate, citation rate, share of voice and average position.","operationId":"citation_tracker_history_citations_trackers__tracker_id__history_get","parameters":[{"name":"tracker_id","in":"path","required":true,"schema":{"type":"integer","title":"Tracker Id"}},{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":90,"title":"Days"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/check":{"post":{"tags":["AI Citations"],"summary":"Citation Check","description":"One-off check — no tracker, metered per check. Paid plans only (Starter and up).\n\nSend JSON: {\"brand\": \"Acme\", \"domains\": [\"acme.com\"], \"prompt\": \"best CRM for agencies\",\n\"engines\": [\"chatgpt\"], \"samples\": 1, \"competitors\": [\"Rival\"]}","operationId":"citation_check_citations_check_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"type":"string"},"prompt":{"type":"string","maxLength":400},"domains":{"type":"array","items":{"type":"string"}},"engines":{"type":"array","items":{"type":"string","enum":["chatgpt","gemini","perplexity","claude"]}},"samples":{"type":"integer","minimum":1,"maximum":5,"default":1},"competitors":{"type":"array","items":{"type":"string"}}},"required":["brand","prompt"]},"example":{"brand":"Acme","domains":["acme.com"],"prompt":"best CRM for agencies","engines":["chatgpt"],"samples":1}}}}}},"/citations/topups":{"get":{"tags":["AI Citations"],"summary":"Citation Topups Info","description":"Top-up packs for AI citation checks, and this account's balance.\n\nA top-up is a one-time purchase for when the month's checks run out: 500 checks for\n$10 or 2,000 for $36 (`packs` is the live list). Top-up checks are spent only after\nthe plan's monthly allowance, do not reset on the 1st, and expire 12 months after\npurchase. `can_buy` is false on the free tier, which cannot run citation checks.","operationId":"citation_topups_info_citations_topups_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/topups/checkout":{"post":{"tags":["AI Citations"],"summary":"Citation Topup Checkout","description":"Start a one-time Stripe Checkout for top-up checks. Paid plans only.\n\nSend JSON: {\"pack\": \"500\"} (500 checks, $10) or {\"pack\": \"2000\"} (2,000 checks, $36).\nReturns {\"url\": ...}: open it to pay by card. The checks are added to the account\nwhen the payment completes (see `GET /citations/topups`), are used only after the\nmonth's allowance, and expire 12 months after purchase. 403 on the free tier.","operationId":"citation_topup_checkout_citations_topups_checkout_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pack":{"type":"string","description":"A pack key from GET /citations/topups."}},"required":["pack"]},"example":{"pack":"500"}}}}}},"/citations/auto-reload":{"get":{"tags":["AI Citations"],"summary":"Citation Auto Reload Get","description":"Auto-reload setting for AI citation checks, and this month's use.\n\nRead-only. Auto-reload is **off unless you turn it on, and it can only be turned on\nor changed from the dashboard** (signed in), never with an API key, because turning it\non authorizes charges. When on, a run that needs more checks than you have is not\nrefused: we charge the card on your subscription for one pack (`pack`: \"500\" = $10,\n\"2000\" = $36), add the checks and let the run go ahead, every time you run out.\n`reloads_this_month`, `charged_this_month_usd` and `failed_this_month` show what has\nhappened so far; after 2 failed charges in a row it pauses (`paused`) until you save\nthe setting on the dashboard again.","operationId":"citation_auto_reload_get_citations_auto_reload_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/prompts/starter":{"get":{"tags":["AI Citations"],"summary":"Starter Citation Prompts","description":"A starter set of prompts to track, from your topic, brand, competitors and audience.\n\nCovers the six kinds of question buyers ask an AI assistant: `direct_recommendation`,\n`comparison`, `alternatives`, `feature_specific`, `use_case` and `pricing`. Built from\nfixed templates, not a model: the same inputs always return the same list, nothing is\nfetched, and no AI check is spent. A template that needs an input you didn't send is\nleft out, so with no `competitors` the comparison prompts are generic.\n\n`prompts` is the flat list, interleaved across categories, ready to send as `prompts`\nto `POST /citations/trackers`. `categories` groups them; `items` flags which ones name\nyour brand or a competitor.\n\nThe default is two per category, 12 prompts. Run on the default four engines at three\nsamples that is 144 checks, which fits one run a month on Starter (150 checks).\n\nWorks on every plan and is not metered. Treat the list as a first draft: rewrite it in\nthe words your buyers use. To read prompts off a website instead, use\n`GET /citations/prompts/suggest`.","operationId":"starter_citation_prompts_citations_prompts_starter_get","parameters":[{"name":"topic","in":"query","required":true,"schema":{"type":"string","description":"What you sell, as a buyer would type it, singular: `SEO audit API`, `emergency plumber in Grand Rapids`, `standing desk`","title":"Topic"},"description":"What you sell, as a buyer would type it, singular: `SEO audit API`, `emergency plumber in Grand Rapids`, `standing desk`"},{"name":"brand","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your brand name. Adds the reputation and pricing questions that name you","title":"Brand"},"description":"Your brand name. Adds the reputation and pricing questions that name you"},{"name":"competitors","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated competitor names (up to 5). Adds `X vs Y` and `alternatives to X`","title":"Competitors"},"description":"Comma-separated competitor names (up to 5). Adds `X vs Y` and `alternatives to X`"},{"name":"audience","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Who buys it, plural: `marketing agencies`, `homeowners`","title":"Audience"},"description":"Who buys it, plural: `marketing agencies`, `homeowners`"},{"name":"features","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated features buyers ask about (up to 6): `a free tier, PDF reports`","title":"Features"},"description":"Comma-separated features buyers ask about (up to 6): `a free tier, PDF reports`"},{"name":"use_cases","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Comma-separated jobs it is bought for (up to 6): `CI/CD checks`","title":"Use Cases"},"description":"Comma-separated jobs it is bought for (up to 6): `CI/CD checks`"},{"name":"per_category","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"description":"Prompts per category (default 2 = 12 prompts; 3 = 18)","default":2,"title":"Per Category"},"description":"Prompts per category (default 2 = 12 prompts; 3 = 18)"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":60,"minimum":1},{"type":"null"}],"description":"Cut the list to this many, keeping the spread across categories (use your plan's tracked-prompt limit)","title":"Limit"},"description":"Cut the list to this many, keeping the spread across categories (use your plan's tracked-prompt limit)"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/citations/prompts/suggest":{"get":{"tags":["AI Citations"],"summary":"Suggest Citation Prompts","description":"Suggest prompts to track, read off what the site actually says it does.","operationId":"suggest_citation_prompts_citations_prompts_suggest_get","parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audit/competitive":{"post":{"summary":"Competitive Audit","description":"Head-to-head SEO comparison with keyword-relevance scoring. Requires Pro plan ($39/mo) or higher.\n\nSend JSON: {\"url\": \"https://yoursite.com/page\", \"competitor_url\": \"https://competitor.com/page\", \"keyword\": \"target keyword\"}","operationId":"competitive_audit_audit_competitive_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","description":"Your API key","title":"X-Api-Key"},"description":"Your API key"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"competitor_url":{"type":"string","format":"uri"},"keyword":{"type":"string","maxLength":200}},"required":["url","competitor_url","keyword"]},"example":{"url":"https://yoursite.com/page","competitor_url":"https://competitor.com/page","keyword":"target keyword"}}}}}},"/geo/monitor":{"post":{"summary":"Geo Monitor Create","description":"Create a GEO monitor for a URL. Requires Basic plan or higher.\n\nSend JSON: {\"url\": \"https://example.com\", \"frequency\": \"weekly\", \"alert_threshold\": -5, \"webhook_url\": \"https://...\"}","operationId":"geo_monitor_create_geo_monitor_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"frequency":{"type":"string","default":"weekly"},"alert_threshold":{"type":"number"},"webhook_url":{"type":"string","format":"uri"}},"required":["url"]},"example":{"url":"https://example.com","frequency":"weekly","alert_threshold":-5}}}}},"delete":{"summary":"Geo Monitor Delete","description":"Remove a GEO monitor. Send JSON: {\"url\": \"https://example.com\"}","operationId":"geo_monitor_delete_geo_monitor_delete","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]},"example":{"url":"https://example.com"}}}}}},"/geo/monitors":{"get":{"summary":"Geo Monitor List","description":"List your active GEO monitors.","operationId":"geo_monitor_list_geo_monitors_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/geo/monitor/{monitor_id}/history":{"get":{"summary":"Geo Monitor History","description":"Get score history for a GEO monitor.","operationId":"geo_monitor_history_geo_monitor__monitor_id__history_get","parameters":[{"name":"monitor_id","in":"path","required":true,"schema":{"type":"integer","title":"Monitor Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1,"title":"Page"}},{"name":"per_page","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Per Page"}},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/monitors":{"post":{"summary":"Create Monitor","description":"Set up SEO score monitoring for a URL. Paid plans only.\n\nSend JSON:\n  {\n    \"url\": \"https://example.com\",\n    \"frequency\": \"daily\" | \"weekly\",\n    \"webhook_url\": \"https://hooks.slack.com/services/...\" (optional),\n    \"alert_threshold\": 5  (optional, points; default 5)\n  }\n\nIf webhook_url is a Slack incoming-webhook URL it is auto-formatted\nas a Slack Block Kit message; otherwise the raw event JSON is POSTed.","operationId":"create_monitor_monitors_post","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"frequency":{"type":"string","enum":["daily","weekly"],"default":"daily"},"webhook_url":{"type":"string","format":"uri","description":"Optional. A Slack incoming-webhook URL gets a formatted message."},"alert_threshold":{"type":"number","default":5,"description":"Points."}},"required":["url"]},"example":{"url":"https://example.com","frequency":"daily"}}}}},"get":{"summary":"Get Monitors","description":"List your active monitors.","operationId":"get_monitors_monitors_get","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Monitor","description":"Remove a monitor. Send JSON: {\"url\": \"https://example.com\"}","operationId":"delete_monitor_monitors_delete","parameters":[{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"}},"required":["url"]},"example":{"url":"https://example.com"}}}}}},"/scoreboard/opt-out":{"put":{"summary":"Scoreboard Opt Out","description":"Opt in or out of the public SEO scoreboard.","operationId":"scoreboard_opt_out_scoreboard_opt_out_put","parameters":[{"name":"opt_out","in":"query","required":true,"schema":{"type":"boolean","description":"true = hide from scoreboard, false = show","title":"Opt Out"},"description":"true = hide from scoreboard, false = show"},{"name":"X-API-Key","in":"header","required":true,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/rotate-key":{"post":{"summary":"Portal Rotate Key","description":"Rotate your API key. Send your CURRENT key as X-API-Key; the response carries the new\none. **The old key stops working immediately** and the new key is shown only once, so\nstore it before you close the response. Also available as a button on your dashboard at\n/dashboard. Rate limited to 5 requests/minute.","operationId":"portal_rotate_key_rotate_key_post","parameters":[{"name":"X-API-Key","in":"header","required":false,"schema":{"type":"string","title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"CrawlRequest":{"properties":{"url":{"type":"string","maxLength":2048,"title":"Url","description":"Where to start (e.g., https://example.com)"},"max_pages":{"anyOf":[{"type":"integer","maximum":100.0,"minimum":1.0},{"type":"null"}],"title":"Max Pages","description":"Fewer pages than your plan's cap, if you want"}},"type":"object","required":["url"],"title":"CrawlRequest"},"DeepAuditRequest":{"properties":{"url":{"type":"string","title":"Url","description":"Page to audit (scheme optional). Must be a public http(s) address."},"business_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Business Type","description":"Tunes which checks apply: saas | local_service | ecommerce | storefront | blog | publisher. Inferred when omitted."},"is_local":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Local","description":"Force local-business checks (NAP, LocalBusiness schema)."},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url","description":"Optional public URL POSTed once when the job completes. Single attempt, no retries, no signature: keep polling as the source of truth."}},"additionalProperties":true,"type":"object","required":["url"],"title":"DeepAuditRequest","description":"Start a Deep Site Audit. Unknown fields are passed to the engine untouched.","example":{"business_type":"local_service","url":"https://example.com","webhook_url":"https://yourapp.example/hooks/deep-audit"}},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}