AFR.IM · API v1
API documentation
Every read endpoint on AFR.IM is public: no API key, no authentication, and Access-Control-Allow-Origin: * so browsers can call it from any origin. Responses are JSON snapshots of the same data this site renders; ratings are computed from public, reproducible evidence — see the AFR standard.
Base URL
https://afr.im Endpoints
/api/v1/sites Paginated directory listing. Natural results never include Pending (unratable) sites.
category · grade · q · sort (score | rank | new) · page
{
"items": [ { "domain": "github.com", "grade": "A", "score_total": 91,
"strategy_tag": "AI-Open", "verified": true, "scanned_at": "2026-11-10T11:40:00.000Z" } ],
"page": 1, "per_page": 24, "total": 8, "sort": "score"
} /api/v1/sites/:domain One site with its latest scan and the full evidence chain of that scan.
{
"site": { "domain": "github.com", "grade": "A", "score_total": 91 },
"scan": { "engine_version": "afr-1.1.0", "score_l1": 33, "score_l2": 38, "score_l3": 20 },
"evidence": [ { "check_id": "l1.robots.ai-policy", "status": "pass",
"points": 25, "max_points": 25, "evidence_ref": "GET /robots.txt" } ]
} /api/v1/sites/:domain/history All scans for a domain, newest first — feeds the score history chart.
/api/v1/stats Totals, verified count, Pending count, average score, and grade distribution.
{
"total": 8,
"verified": 4,
"pending": 0,
"avg_score": 58,
"grades": { "A": 1, "B": 2, "C": 2, "D": 2, "F": 1 }
} /api/v1/categories The category tree with per-category counts of rated sites.
/api/v1/leaderboard Top sites sorted by pure AFR score descending. Sponsored placements are never mixed in.
category · limit (≤ 50)
{
"category": null,
"items": [
{ "rank": 1, "domain": "github.com", "title": "GitHub · Where software is built",
"grade": "A", "score": 91, "category": "dev-tools", "strategy_tag": "AI-Open" }
]
} /api/v1/method The machine-readable AFR standard: layers, every sub-check with its points, and grade thresholds.
/badge/:domain.svg Rating badge image (SVG) for a domain — ring, grade letter, score. Cached one hour; unknown domains get a neutral gray badge.
/api/v1/submissions Request a scan of a site. Body: { "domain": "example.com", "note": "optional" }. Limited to 5 per IP per day.
// POST {"domain": "example.com", "note": "optional"}
{ "ok": true, "id": 1, "domain": "example.com", "status": "queued" } Errors
Errors are JSON objects with an error code. 400 for invalid parameters, 404 for unknown domains, 429 for rate-limited submissions. When the network is down, the service worker answers /api/* requests with 503 { "error": "offline" } and a friendly message.
{ "error": "not_found", "domain": "unknown.example" } Rate limits
GET endpoints are free of keys and limits beyond normal politeness — identify yourself, keep to about one request per second, and cache responses (see /agents.md). POST /api/v1/submissions allows 5 requests per IP per day. Badge images are cached upstream for one hour.
Machine-readable formats
- OpenAPI 3.1 spec — /openapi.json — this API described for code generators and tools.
- OpenAPI mirror — /.well-known/openapi.yaml — the same spec at the well-known location.
- AFR standard as JSON — /api/v1/method — layers, per-check points, and grade thresholds.
- llms.txt / llms-full.txt — Map of this directory for language-model readers.