Scan API
The scan behind every Legible result is a public API. Send a domain, get back every check with the URL we fetched, its HTTP status and what we found. No account and no API key. The OpenAPI spec describes the same endpoint, and How we check explains each check and how the score works.
Quickstart
- In the browser: type your domain on the home page.
- From a terminal: npx legible-cli <domain>, with your domain.
- In CI: add --min-score and a number, and the command exits 1 below it. Or use the GitHub Actions job below.
- From your editor: add Legible's MCP server, then ask your agent to scan your site.
Request
Send a POST to /api/scan with a JSON body: either a domain, or the id of a company on the email-API board, which scans it the way the board does.
curl -X POST https://leaderfile.vercel.app/api/scan \
-H "content-type: application/json" \
-d '{"domain": "resend.com"}'To check a fix you just shipped, add "rescan": true: it reads the site again instead of returning a cached result.
GET /api/checks lists every check, with a real example from whoever does it best on our boards. For a coding agent, there's a skill that scans a live site and writes its own version of each file.
From your terminal
The same scan as a command, with nothing to install: npx runs it on Node 18.3 or newer. It sends only the domains you name.
npx legible-cli <domain>
Scan a site, like resend.com. Or a company on our board, like sendgrid.npx legible-cli <domain> --vs rival.com
Also show what a rival passes that you don't. Repeat for more.npx legible-cli skill
Add the skill to this project, for your coding agent.--json
Print JSON, for agents and scripts.--min-score <n>
Exit 1 if the score is below n, for CI. If we can't tell, it warns and exits 0.--rescan
Read the site again now, instead of a result up to 10 minutes old.--force
With skill: replace a copy you've changed.
Exit codes: 0 fine, 1 below --min-score, 2 we couldn't run the scan. npx legible-cli --help prints all of this. If Windows PowerShell blocks npx, type npx.cmd instead.
A real run on 9 Nov 2026, with version 1.1.0, as it printed:
$ npx legible-cli resend.com
resend.com: 96 out of 100 (scoring v2). 29 of 31 checks pass.
Fails our check. It doesn't prove the thing isn't there, only that our check didn't pass on what we read:
Errors have a schema
Real example, Mailtrap: https://raw.githubusercontent.com/mailtrap/mailtrap-openapi/main/specs/email-sending-transactional.openapi.yml
Tools for browser agents
Don't do it for the score. It's still a proposed standard, and almost nobody on our boards passes our check, though Bird, Postmark and CrewAI load it from a script our check doesn't read. Build it only if agents need to operate forms on your site.
This reads public files. It isn't a test of what an agent can do with your product.
Full result: https://leaderfile.vercel.app/scan?domain=resend.com&via=cliLegible's MCP server
Legible's MCP server lets the agent in your editor scan a site, list our checks and read our boards, with the same results as this site. It's at https://leaderfile.vercel.app/mcp, over Streamable HTTP, with no account and no API key. Its tools are scan_site, get_checks and get_board.
In Claude Code:
claude mcp add --transport http legible https://leaderfile.vercel.app/mcpIn Cursor: Add to Cursor, or add it to .cursor/mcp.json:
{
"mcpServers": {
"legible": {
"url": "https://leaderfile.vercel.app/mcp"
}
}
}A scan from your editor counts towards the same limit as one here: 50 live scans per 10 minutes from one network.
Use it in CI
A GitHub Actions job that fails when your score drops below the number you pick. A score we had to withhold or a refused rescan also fails it, because the score comes back as null. For a ready-made job that names the check that changed and watches your rivals, and only warns on anything we couldn't read, open "Track it weekly" at the foot of your result.
name: Agent readiness
on:
schedule:
- cron: "0 9 * * 1"
workflow_dispatch:
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Fail if the score drops below 80
run: |
r=$(curl -sS -X POST https://leaderfile.vercel.app/api/scan \
-H "content-type: application/json" \
-d '{"domain": "your-domain.com", "rescan": true}')
version=$(echo "$r" | jq -r '.scoringVersion // "1"')
if [ "$version" = "2" ]; then score=$(echo "$r" | jq -r '.v2.summary.score'); else score=$(echo "$r" | jq -r '.summary.score'); fi
v1=$(echo "$r" | jq -r '.summary.score')
until=$(echo "$r" | jq -r '.v2.legacyUntil // empty')
echo "Score: $score (scoring v$version)"
if [ "$score" != "null" ] && [ "$score" -lt 80 ] && [ "$v1" != "null" ] && [ "$v1" -ge 80 ] && [ -n "$until" ] && [ ! "$(date -u +%F)" \> "$until" ]; then
echo "::warning::Only our scoring change took this below 80. It warns, not fails, until $until."
exit 0
fi
[ "$score" != "null" ] && [ "$score" -ge 80 ]This job is stricter than the CLI's --min-score when we can't tell:
- A score below your number: the CLI exits 1, and this job fails.
- A score we had to withhold: the CLI warns and exits 0, and this job fails.
- Legible or the site couldn't be reached: the CLI warns and exits 0, and this job fails.
- A typo in the domain: the CLI exits 2, and this job fails.
To hear about changes in Slack, use the weekly job from "Track it weekly" at the foot of your result instead. It watches the checks your site passes today, and your rivals' if you compared them:
- In Slack, create an incoming webhook for the channel you want.
- In your GitHub repo, open Settings, then Secrets and variables, then Actions, and add a repository secret named SLACK_WEBHOOK_URL with the webhook's address.
- Copy the job from your result into .github/workflows/legible.yml.
It posts one message a run, only when something changed, with a link back to each result. Nothing else is sent to us.
Response
A 200 with the result. reachable is false when the domain couldn't be reached, with the reason in detail. Otherwise scoringVersion is "2": v2.results holds one entry per check, and v2.summary.score is the score the site shows, null when we could check too little to score. The top-level results and summary are the first scoring's, kept for older CI jobs; from v2.legacyUntil, summary.score carries the new score too.
{
"reachable": true,
"host": "resend.com",
"scannedAt": "2026-11-09T19:03:28.810Z",
"scoringVersion": "2",
"summary": { "score": 96, "withheld": false },
"v2": {
"summary": {
"score": 96,
"withheld": false,
"steps": [{ "name": "Find", "score": 100 }, { "name": "Read", "score": 100 }, { "name": "Act", "score": 90 }]
},
"legacyUntil": "2026-12-09",
"results": [
{
"id": "AR-READ-07",
"status": "pass",
"evidence": [{ "url": "https://resend.com/llms.txt", "httpStatus": 200, "note": "text file with markdown links" }]
}
]
},
"cached": false
}Trimmed: a real result has every check and more summary fields.
Limits
Live scans are limited to 50 per 10 minutes from one network, and a result is cached for up to 10 minutes (1 minute when a file was slow or busy), so asking again soon returns the same scan with cached set to true, which doesn't count towards the limit. A scan stops after 27 seconds; a check still waiting by then shows as couldn't check.
A rescan counts as a live scan, and each domain gets one rescan a minute, whoever asks.
Errors
Errors come back as JSON with an error message: 400 for a body that isn't JSON, an invalid domain or an unknown board company; 429 when your network has run its scans or a domain its rescans, with a Retry-After header; 503 when scanning is switched off or the rate limit couldn't be checked, so no scan ran.
What changed
- 9 Nov 2026: The CLI is legible-cli 1.1.0 on npm: it reads the new scoring, lists the fixes worth the most points first, and compares rivals on every check. (E268)
- 9 Nov 2026: Our rules are version 2026-11-09.2.v2: a code-language-* class shows a code sample's language, a sign-up page or a redirect within an identity provider's own site isn't a login, a spec address written out in an llms.txt counts as linked, and the API checks don't count for a code library. A scan under older rules is never compared with a new one. (E264)
- 9 Nov 2026: Our rules are version 2026-11-09.v2: all 31 checks count. A scan under older rules is never compared with a new one. (E260, E261)
- 4 Nov 2026: The weekly Drop began with Issue 3, with an RSS feed, after a new scan of the AI agent platform board. (E228)
- 4 Nov 2026: The verdict over a result leaves out Tools for browser agents, the one check we say not to do for the score. The score still counts it. (E226)
- 4 Nov 2026: The OpenAPI fix says to link the spec file itself, not a repo or a page about it. (E222)
- 3 Nov 2026: A second board: 13 AI agent platforms, beside the 15 email APIs. (E198, E199)
- 3 Nov 2026: The CLI is legible-cli on npm, version 1.0.0. (E206)
- 2 Nov 2026: Our rules are version 2026-11-02.2: fixes for sites off our boards. A scan under older rules is never compared with a new one. (E180)