Developers
Build on the AIEO scan
Every scan AIEO runs for a human is also a JSON API for an agent — the same four-group score, the same checks, the same fixes, plus a Markdown export built for pasting straight into a prompt or a pull request.
Endpoints
Three endpoints cover the whole surface: run a scan, get an instant report, or fetch a previously persisted one. All responses are JSON unless you ask for Markdown.
/api/agent-scanRuns a full AIEO scan for a domain and returns the v2 report as JSON, or as Markdown with ?format=md. A successful scan is persisted to KV for 7 days (fail-open: storage errors are noted in meta.warnings, never fail the scan). Rate limited per IP per hour — 12/hour by default, 20/hour with ?source=compare.
| Param | Type | Required | Notes |
|---|---|---|---|
| domain | string | Yes | Bare domain to scan, e.g. example.com (a scheme, if present, is stripped). |
| format | string | No | "json" or "md" explicitly selects the response format. Otherwise Accept weights select JSON or Markdown; ties and unsupported preferences return JSON. |
/api/demoSame engine and v2 report contract as /api/agent-scan. Body: { "domain": "example.com" }. Rate limited 10/IP/hour. Persists the report to KV for 7 days on success.
curl -X POST https://aieo.fyi/api/demo \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'
/api/report/[id]Reads back a report saved by a prior /api/agent-scan or /api/demo call. Not rate limited — no scan runs. Ids are 12 lowercase Crockford base32 characters and expire after 7 days.
curl "https://aieo.fyi/api/report/9f3ak2m7pqrs"
# Markdown download
curl "https://aieo.fyi/api/report/9f3ak2m7pqrs?format=md"
The JSON contract
Every scan — from /api/agent-scan, /api/demo, or a stored /api/report/[id] — returns the same shape: an overall score, four weighted group scores, a flat list of individual checks, and a short top-5 fix list ordered by points recoverable.
This excerpt contains selected fields and items from an offline test fixture, not a scan of a real business. The full response includes all checks and metadata; report links and rate-limit details are omitted here. A title fix can recover readiness points; DMARC is an informative security finding worth zero readiness points.
{
"version": 2,
"domain": "poor.example",
"scores": {
"overall": 29,
"traditionalSEO": 25,
"aiDiscoverability": 75,
"schemaCoverage": 0,
"agentInteraction": 0
},
"groups": [
{ "id": "traditionalSEO", "label": "Traditional SEO", "weight": 40, "score": 25 },
{ "id": "aiDiscoverability", "label": "AI Discoverability", "weight": 25, "score": 75 },
{ "id": "schemaCoverage", "label": "Schema Coverage", "weight": 15, "score": 0 },
{ "id": "agentInteraction", "label": "Agent Interaction (WebMCP)", "weight": 20, "score": 0 }
],
"checks": [
{
"id": "title",
"group": "traditionalSEO",
"category": "seo",
"title": "Page title",
"severity": "fail",
"scoreMode": "scored",
"detail": "No <title> tag found.",
"why": "Search engines truncate long titles and pad short ones; both cost click-through.",
"learnMoreUrl": "/methodology#title",
"scope": "page",
"order": 1,
"pointsRecoverable": 4,
"fix": "Add a descriptive <title> tag (50–60 characters) containing your main keyword.",
"pageUrl": "https://poor.example/",
"pagesAffected": 1
},
{
"id": "dmarc",
"group": "security",
"category": "security",
"title": "DMARC record",
"severity": "fail",
"scoreMode": "informative",
"detail": "No DMARC record. Email spoofing has no enforcement.",
"why": "DMARC turns SPF/DKIM alignment into an enforceable anti-spoofing policy.",
"learnMoreUrl": "/methodology#dmarc",
"scope": "site",
"order": 2,
"pointsRecoverable": 0,
"fix": "Add TXT at _dmarc.yourdomain: \"v=DMARC1; p=quarantine; rua=mailto:dmarc@yourdomain\""
}
],
"topFixes": [
{
"id": "title",
"title": "Page title",
"severity": "fail",
"fix": "Add a descriptive <title> tag (50–60 characters) containing your main keyword.",
"group": "traditionalSEO",
"pageUrl": "https://poor.example/",
"pointsRecoverable": 4,
"pagesAffected": 1
}
],
"security": { "grade": "D", "score": 45, "checks": 10 }
}
Markdown export
Add ?format=md to /api/agent-scan or /api/report/[id] to get a clean text/markdown report: YAML front-matter with the domain and scores, one section per score group, and a - [ ] fix checklist you can paste straight into an issue. The export_report WebMCP tool below produces the same output client-side.
Examples
The same request in curl, JavaScript and Python.
curl "https://aieo.fyi/api/agent-scan?domain=example.com"
# Markdown, for pasting into a PR or an agent's context window
curl "https://aieo.fyi/api/agent-scan?domain=example.com&format=md"
const res = await fetch(
"https://aieo.fyi/api/agent-scan?domain=example.com"
);
const report = await res.json();
console.log(report.scores.overall, "/ 100");
import requests
r = requests.get(
"https://aieo.fyi/api/agent-scan",
params={"domain": "example.com"},
)
report = r.json()
print(report["scores"]["overall"], "/ 100")
Rate limits, CORS and headers
Limits are per IP, per hour, tracked in Cloudflare KV. Every API response carries rate-limit headers so an agent can pace itself without guessing.
| Endpoint | Limit | Notes |
|---|---|---|
| GET /api/agent-scan | 12 / IP / hour | CORS open; JSON or ?format=md |
| POST /api/demo | 10 / IP / hour | Instant scan, no email |
| GET /api/report/[id] | not rate-limited | Reads a persisted report (7-day TTL) |
| Header | Notes |
|---|---|
| X-RateLimit-Limit | Requests allowed in the current window |
| X-RateLimit-Remaining | Requests left in the current window |
| X-RateLimit-Reset | Unix timestamp in seconds when the window resets; JSON rateLimit.resetAt uses ISO-8601 |
| Retry-After | Seconds to wait, sent only on a 429 response |
CORS is open (Access-Control-Allow-Origin: *) on every /api/* route — this is public scan data, meant to be read from anywhere, including from inside another site's agent.
OpenAPI schema
A machine-readable schema for the REST endpoints, including the 429 error shape and its headers, lives at /api/openapi.json. Point your codegen or client SDK at it directly.
Connect your AI assistant
The remote MCP beta is at /mcp on this deployment. Add its full HTTPS URL to an assistant that supports Streamable HTTP MCP, with no authentication. It exposes three tools:
| Tool | What it does |
|---|---|
| scan_site | Check a public website domain and return findings, fixes and a shareable report. |
| get_report | Retrieve every check in an existing report by its 12-character ID. |
| explain_check | Explain a check ID: its rule, scoring role, generic fix and methodology. |
Try “Check mybusiness.co.uk and explain the three most useful fixes.” The score measures technical readiness; it does not establish rankings, traffic or actual AI mentions and citations. Recoverable points rank changes to this score, not business impact.
Scans share the public API's 12-per-source-IP hourly allowance. Assistant providers may share an IP between users. Discovery, explanations and report retrieval do not spend a scan. Reports are kept for seven days when storage is available, and anyone with the report link can read them. Read the data policy.
For ChatGPT, use its developer-mode connection flowto test a personal plugin. This beta has not been submitted to the public directory. These remote tools are separate from the browser WebMCP tools below.
WebMCP tools on this site
aieo.fyi registers its own WebMCP tools so an AI agent can run a scan for you directly on the page, no API key required. There are seven:
| Tool | What it does |
|---|---|
| get_site_overview | What AIEO is, how the tools fit together, the privacy and rate-limit terms. No network call; call it first. |
| run_scan | Runs a full AIEO scan for a domain, renders the score card in the page and returns scores, top fixes and the 7-day report link. |
| get_scan_result | Returns the JSON result of the most recent scan run on this page. |
| explain_check | Explains a single check by id: what it measures, why it matters, how to fix it. |
| list_checks | Lists every check in the catalogue, grouped by score group. |
| show_full_report | Renders the full report for the last scan (or a given domain) in the page — the same report /scan shows. |
| export_report | Exports the last scan, a stored report by id, or a given domain as Markdown or JSON, with a Copy and Download panel; the download starts in-page. |
Ask your agent to open the homepage and "scan example.com" — it calls run_scan, reads the result back with get_scan_result, and can hand you a Markdown copy with export_report. Tools follow the 2026-09 Web Model Context draft: document.modelContext.registerTool(tool, { signal }), plain-JSON results (failures are { ok: false, error, hint }), and annotations — every tool is read-only and the ones that return scanned-site text carry untrustedContentHint.