Scan for AI visibility from code, or from Claude.
Everything the web scanner does, two ways: a small REST API for your own scripts and products, and an MCP server so assistants can scan a page while you are talking to them.
One POST.
One structured verdict.
The shape of a call, not a live response. A scan is asynchronous: you post a URL, get an id, poll until it is done, then fetch the report as JSON.
The request, the header and the response fields are the real v1 shape. The report key shown is an example value, not a live one.
Key. Scan.
Poll. Fetch.
Four calls, no SDK required. The whole surface is small enough to read in one sitting and stable enough to build on.
-
Get a key
Any paid plan that includes the API issues one on your dashboard the moment you subscribe. Send it as an Authorization: Bearer header, never in a URL.
-
Start a scan
POST a URL to /api/v1/scan. A bare domain works. You get a scan id, a report key, and the two URLs to poll and to fetch.
-
Poll for completion
There is no completion webhook. Poll the status_url until the status leaves queued or running; scans usually finish in under a minute.
-
Fetch the report
GET the result_url for the complete structured verdict. The report key is the capability, so that endpoint needs no key at all.
Four surfaces on one key
The same entitlement covers all four, so there is no separate MCP plan and no separate billing to reconcile.
REST API
Start a scan, poll it, and fetch the complete structured verdict. JSON in, JSON out, with the same verdict shape the web report renders.
MCP server
Point Claude, ChatGPT or another assistant at the server and it can scan a page mid-conversation, then read the verdict back to you.
Monitoring hooks
One call when a deploy lands re-checks the pages you already monitor, instead of waiting a week for the next scheduled run.
Brand metrics
Your prompt-tracking history as data, from the key-gated brand-metrics endpoint: naming, sentiment, citation share and the competitors models reached for instead, with unmeasured days left null rather than zeroed.
REST API
Get an API key
Access uses a key (a Bearer token that looks like lantad_…) with
a daily scan cap, because every scan runs a real browser render. Any paid
plan that includes the API issues your key automatically: it is on your
account dashboard the moment you subscribe
(Starter from $59/mo, Pro from $199/mo, Business from $399/mo). Send
the key as an Authorization: Bearer header; never put it in a URL
or commit it to a repo. Need higher limits or a custom arrangement? Email
hi@lantad.co.
Start a scan
curl -X POST https://lantad.co/api/v1/scan \
-H "Authorization: Bearer lantad_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "yoursite.com"}'
A bare domain works; no scheme needed. Returns 202 with a
scan_id, a report_key, and the URLs to poll and to
fetch the result:
{
"scan_id": "1c2fecfa-…",
"report_key": "noYTkhb0v3cTrpBPo7hpK",
"status": "queued",
"report_url": "https://lantad.co/r/noYTkhb0v3cTrpBPo7hpK",
"status_url": "https://lantad.co/api/v1/scan/1c2fecfa-…",
"result_url": "https://lantad.co/api/v1/report/noYTkhb0v3cTrpBPo7hpK"
}
Check status
curl https://lantad.co/api/v1/scan/SCAN_ID
Returns { "status": "queued" | "running" | "done" | … }
plus the sub-scores once the grade lands. Scans usually finish in under a
minute.
Get the full report
curl https://lantad.co/api/v1/report/REPORT_KEY
Returns the complete structured verdict: the AI Visibility Score and grade,
Prose Parity and the other sub-scores, the per-bot access matrix for all
checked crawlers, the ranked defects with their fixes, and the evidence
behind each. The report_key is the capability, so this endpoint
needs no key, exactly like the shareable web report.
A complete poll loop
There is no completion webhook: start the scan, poll the
status_url it returns until the status leaves the queue, then
fetch the result_url. In shell, with jq:
# 1. Start the scan and keep the URLs it returns
resp=$(curl -s -X POST https://lantad.co/api/v1/scan \
-H "Authorization: Bearer lantad_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "yoursite.com"}')
status_url=$(echo "$resp" | jq -r .status_url)
result_url=$(echo "$resp" | jq -r .result_url)
# 2. Poll every few seconds until the scan settles
while :; do
status=$(curl -s "$status_url" | jq -r .status)
if [ "$status" != "queued" ] && [ "$status" != "running" ]; then break; fi
sleep 3
done
# 3. Fetch the structured verdict
curl -s "$result_url" | jq .verdict.scores
queued and running are in flight; everything else
is terminal. done usually carries a graded report, but it can also carry an honest ungraded verdict with a null composite when the page could not be measured fairly (a bot challenge, a login wall, or too little readable text); read the verdict state, not just the status. The other honest endings:
render_blocked (the render was refused or timed out, so you
get a partial verdict without a grade), deferred_budget (our
daily render budget or the monthly spend ceiling had no room, so the browser view was deferred and re-queued),
not_html, opted_out, and failed.
When a scan ends without producing a report, the result endpoint returns
ready: false with a message saying so; it never invents
numbers for a scan that was not measured.
Errors, precisely
Every error response is JSON with an error field describing
what to change. The status codes the v1 routes actually return:
| Code | Route | Meaning |
|---|---|---|
200 |
POST /api/v1/scan |
The same URL was scanned within the last 24 hours: the existing report is returned with deduplicated: true and nothing is charged to your cap. |
202 |
POST /api/v1/scan |
New scan accepted and queued. |
400 |
all | The body is not JSON, url is missing, or a report key or bulk id is malformed (report keys are 16+ letters and digits). |
401 |
POST /api/v1/scan, POST /api/v1/bulk, POST /api/v1/deploy |
Key missing, invalid, or expired. On /api/v1/scan and MCP, every request also re-checks the live plan behind the key, so a cancelled or past-due subscription answers 401 there; on /api/v1/bulk a lapsed plan instead answers 422 with a plan message. |
403 |
POST /api/v1/deploy |
The key is valid but was not minted by a paid plan, so it belongs to no account whose pages could be re-checked. |
404 |
GET routes |
Unknown scan id, report key, or bulk job. The bulk CSV also answers 404 until the job finishes. |
422 |
POST /api/v1/scan, POST /api/v1/bulk |
Refused before scanning: safety-guard rejections (private or reserved targets, non-HTTP schemes, a domain that has opted out), a plan without audit allowance, an exhausted audit allowance, or an empty or unfetchable sitemap. The body says which. |
429 |
POST /api/v1/scan |
The key's daily scan cap is used up. The message names the cap; it resets at 00:00 UTC. |
429 |
POST /api/v1/deploy |
Either the call came inside the 10-minute cooldown, in which case the body carries retry_after_seconds, or the account has used its 200 pages for the day. Nothing is queued either way, so it is safe to call on every deploy and ignore. |
Limits and behaviour
- A repeat scan of the same URL inside 24 hours returns the existing report and does not use budget.
- Each key has a daily scan cap, resetting at 00:00 UTC: 200 scans a day on Starter, 500 on Pro, 1,000 on Business. The counter is a soft limit: it lives in an eventually consistent store, so a burst right at the boundary may land a request or two either side of the cap.
- The cap follows your live plan, not the key: upgrade and the higher cap applies on the next request, no re-minting. The same re-check cuts a key off the moment its plan stops being active.
- Keys from one-time purchases expire with the bundled monitoring months (3 for Deep Audit, 6 for Fix Sprint); subscription keys carry no expiry of their own because the entitlement re-check governs them.
- The same SSRF and safety guards as the web form apply: private, reserved, and non-HTTP targets are refused.
Bulk sitemap audit (paid plans)
curl -X POST https://lantad.co/api/v1/bulk \
-H "Authorization: Bearer lantad_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"sitemap": "https://yoursite.com/sitemap.xml"}'
Audits every same-site page in the sitemap with the raw-HTML checks (no
browser render): readability verdict, structure facts, structured data, and
per-crawler robots access. Poll GET /api/v1/bulk/ID for
progress; results include a shareable page and a per-page CSV. Included
with Starter (up to 2,000 pages
per job, 30,000 per month), Pro (up to 4,000 pages
per job, 100,000 per month) and
Business (up to 6,000 pages
per job, 200,000 per month).
The one-time Deep Audit covers 10,000 pages,
granted once rather than monthly.
Deploy hook (paid plans)
Monitoring re-checks your pages weekly, which leaves a week-wide hole: a deploy that puts your content back behind JavaScript is invisible until the next run. Call this when a deploy lands and we re-check the pages you monitor straight away.
curl -X POST https://lantad.co/api/v1/deploy \
-H "Authorization: Bearer lantad_YOUR_KEY"
No body. The key identifies the account, and we re-check the pages already monitored on it, least-recently-checked first. Results arrive the usual way: each page gets a report, and your existing alerts fire if something broke.
{
"queued": 12,
"skipped": 1,
"budget_stopped": false,
"remaining_today": 188
}
skipped counts pages we could not scan right now, usually a
domain that has since opted out. budget_stopped is
true when the platform's spend ceiling was reached partway
through, so you can tell a short run from a complete one instead of guessing
from the count.
Limits. One call per account per 10 minutes, and
up to 200 pages re-checked per
account per day across every call. A call inside the cooldown answers 429
with retry_after_seconds; one past the day's allowance answers
429 and queues nothing. Deploying more often than the cooldown is fine, the
extra calls are simply refused, so you can wire it to every deploy without
branching on the result.
What it is not. This re-checks pages you already monitor; it does not add pages, and a page that is not monitored is not scanned. It is available on every paid plan with the API (Starter, Pro and Business), using the same key as the rest of this API, so revoking the key revokes the hook.
Brand metrics (paid plans)
Your prompt-tracking history as data: one row per UTC day on which at least one of your verified prompt runs finished, covering the last 365 days. The same rows the dashboard's brand-visibility trends draw, so a chart you saw and a number you fetched can never disagree.
curl https://lantad.co/api/v1/brand-metrics \
-H "Authorization: Bearer lantad_YOUR_KEY"
Read the nulls honestly. A null metric means it was not
measured that day, never zero: a day with no graded answers has
sentiment_net: null, a day where no engine returned
attributable sources has citation_share: null, and a day where
no answer named the brand has avg_position: null (positions
are 1-based, lower is better; 0 is not a possible value). A real 0 is a
measured claim and is returned as 0. A realistic response,
nulls included:
{
"window_days": 365,
"note": "One row per UTC day with at least one finished verified prompt run. A null metric means it was not measured that day, never zero.",
"rows": [
{
"day": "2026-08-03",
"mention_rate": 40,
"sentiment_net": 0.25,
"citation_share": 12,
"avg_position": 2.3,
"runs": 2,
"sov": [{ "name": "Rival Co", "count": 3, "isPinned": true }]
},
{
"day": "2026-08-06",
"mention_rate": 35,
"sentiment_net": null,
"citation_share": null,
"avg_position": null,
"runs": 1,
"sov": []
}
]
}
Requires a plan-issued key: the key identifies the account whose history is
returned, so a key not minted by a plan answers 403. The same
rows are downloadable from the dashboard as CSV or JSON without touching
the API.
MCP server, for Claude, ChatGPT and other assistants
Lantad runs an MCP server so an assistant can scan a site for you and read the result back. It speaks Streamable HTTP JSON-RPC at:
https://lantad.co/api/mcp
Authenticate with the same Bearer key. Two tools are exposed:
scan_website(url)runs a scan and waits up to about 22 seconds for the graded result, polling every 2 seconds. A bare domain works. The result is a text summary (score, grade, sub-scores, and the top issues worst first, each with its fix) plus the complete verdict as structured content, so the assistant can quote exact numbers rather than paraphrase. If the site has a report from the last 24 hours, that report is reused and your daily cap is untouched.get_scan_report(report_key)fetches a prior report, useful when a slow site did not finish inside the wait window:scan_websitethen hands back thereport_keyand says to call this.
Protocol details, for client authors: POST only (GET answers 405; there is
no server-initiated stream), and the server handles
initialize, ping, tools/list, and
tools/call. A missing or dead key gets a 401 with JSON-RPC
error code -32001. Tool-level problems (a refused URL, an unknown report
key, a spent daily cap) come back as tool results flagged
isError with the same plain-language messages as the REST
API, so the assistant can read the reason and tell you.
Connect it
In an MCP client that supports remote HTTP servers with headers (for example Claude Desktop or Cursor), add:
{
"mcpServers": {
"lantad": {
"url": "https://lantad.co/api/mcp",
"headers": { "Authorization": "Bearer lantad_YOUR_KEY" }
}
}
}
In Claude or ChatGPT's custom connector settings, add a connector pointing
to https://lantad.co/api/mcp and set the
Authorization header to your key. Then ask the assistant to
scan a site, for example: "Scan stripe.com for AI visibility and summarise
the top fixes."
Three people this is built for
Rate limits are per key, per day: 200 calls on Starter, 500 on Pro, and 1,000 on Business.
Platform engineers
You want a parity check in CI, so a deploy that moves content behind JavaScript fails the build rather than the quarter.
- A scan step in CI, failing the build on a score drop
- The deploy hook, so a bad deploy is caught the same hour
- The bulk sitemap audit for whole-site sweeps
Product teams
You are building AI-visibility features into your own product and need the grading rather than the interface.
- Client dashboards built on the report JSON
- Scheduled sweeps across a portfolio of sites
- Brand metrics exported as rows, nulls left honest
Assistant users
MCP lets Claude or ChatGPT scan a site mid-conversation and reason about the result with the exact figures in hand.
- Scanning a site without leaving the chat
- Quoting exact sub-scores instead of paraphrasing
- Fetching a prior report by its key
Just the crawler-eye view of one URL, or a robots.txt question? The free What GPTBot sees and robots.txt tester tools need no key. Questions, higher limits, or a bug: hi@lantad.co.
One key, four surfaces, and the same grading code the website runs. There is no separate API scoring path: a scan started from curl, from the MCP server, or from the scan box on the homepage runs the same checks and returns the same verdict shape. What differs is how you start it and where the result lands.
A key works as long as the plan behind it is active: every request re-checks the live entitlement, so a lapsed plan stops the key on the next call.
Common questions
Do I need an API key to read a report?
No. The report_key is the capability: GET /api/v1/report/<key> needs no Authorization header, exactly like the shareable web report at /r/<key>. Keys gate starting scans, not reading results.
Does re-scanning the same URL burn my daily budget?
No. A repeat scan of the same URL inside 24 hours returns the existing report with deduplicated: true, and the dedupe check runs before the daily cap is counted, so it costs nothing.
Is the API scored differently from the website?
No. There is one grading path. A scan started from the API, from the MCP server, or from the scan box on the homepage runs the same checks and returns the same verdict, including the same treatment of anything that could not be measured.
What are the rate limits?
Per key, per day: 200 calls on Starter, 500 on Pro, and 1,000 on Business. A one-time Deep Audit carries 200 a day for the bundled months. The cap resets at 00:00 UTC, and limits are enforced from the same configuration the plans page quotes.
What is the MCP server for?
It lets an assistant run a scan as a tool while you are in the conversation. You ask Claude about a page, it scans it, and it reads the verdict back with the evidence rather than guessing from the URL. If a slow site outlasts the tool's wait window, the assistant gets the report key and fetches the finished report with a second tool call.
Is there a webhook when a scan finishes?
No. Poll the status_url the scan response gives you; scans usually finish in under a minute. The status endpoint needs no key because scan ids are unguessable UUIDs.
How long does my API key last?
A subscription key works as long as the plan is active: every request re-checks the live entitlement, so a cancelled or past-due plan stops the key. Keys from one-time purchases expire with the bundled monitoring months: 3 months for a Deep Audit, 6 for a Fix Sprint.
Is there a free tier for the API?
No. The scan itself is free from the website, without an account, but programmatic access comes with a paid plan because it is the surface that costs real compute at volume.
How long can I fetch a report after scanning?
Scan artifacts are kept for up to 18 months, after which they are deleted or made inaccessible. Render screenshots expire after 24 hours, but they are cosmetic; the structured verdict is what the API returns.
Build the check into your pipeline.
A parity regression is cheapest to fix on the branch that caused it. One POST in CI is the difference between catching it there and finding it in a quarterly report.