{"$schema":"https://json-schema.org/draft/2020-12/schema","$id":"https://crawlcheck.io/api/v1/schema","title":"CrawlCheck public API v1","description":"Stable response formats for /api/v1. Fields are added, never renamed or removed, within a major version; anything not listed here is not part of the contract. The unversioned /api/scan returns the internal record and may change without notice.","$defs":{"PublicReportV1":{"type":"object","additionalProperties":false,"required":["schema","version","id","domain","scanned_at","grade","overall","sections","findings","proof"],"properties":{"schema":{"type":"string"},"version":{"const":"1.0"},"id":{"type":["string","null"]},"domain":{"type":["string","null"]},"path":{"type":["string","null"]},"scanned_host":{"type":["string","null"]},"scanned_at":{"type":["string","null"]},"score_version":{"type":["number","null"]},"grade":{"type":["string","null"]},"overall":{"type":["number","null"]},"grade_detail":{"type":"object","properties":{"capped":{"type":"boolean"},"cap":{"type":["string","null"]},"cap_reason":{"type":["string","null"]}}},"sections":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"title":{"type":["string","null"]},"score":{"type":["number","null"],"description":"null means not measured, never zero"}}}},"findings":{"type":"array","items":{"type":"object","properties":{"code":{"type":["string","null"]},"path":{"type":["string","null"]},"severity":{"type":["number","null"]},"title":{"type":["string","null"]},"detail":{"type":["string","null"]},"meaning":{"type":["string","null"]},"evidence":{"type":["string","null"],"maxLength":500},"fid":{"type":["string","null"]},"decision_id":{"type":["string","null"]},"graph":{"type":["string","null"]},"locked":{"type":"boolean","description":"true on an unlicensed read for every finding but the top one: title, severity and path are present, the rest is withheld"},"fingerprint":{"type":["string","null"],"description":"code|path; stable across scans of the same domain; null on a locked finding"},"state":{"type":["string","null"],"enum":["new","persisted","worsened","improved","regressed","resolved","rule-changed",null],"description":"lifecycle on this scan; null when the domain has no stored history"},"first_seen":{"type":["string","null"]},"scans_seen":{"type":["number","null"]},"recurrences":{"type":["number","null"]},"valid_time":{"type":["object","null"],"description":"bitemporal: when the condition held on the site (valid_from / valid_to as after-by intervals between observations; null ends are unknown or still open) and when CrawlCheck recorded it (recorded_at, superseded_at)"}}}},"findings_withheld":{"type":["string","null"],"description":"Set on an unlicensed read: every finding is listed by title, severity and path; detail, evidence and code beyond the top one are withheld"},"findings_summary":{"type":["object","null"],"properties":{"total":{"type":["number","null"]},"serious":{"type":["number","null"]},"by_severity":{"type":["object","null"]}}},"provenance":{"type":["object","null"],"description":"Observer build, vantage, rule version, observed and stored times, sealed manifest"},"score_ledger":{"type":["object","null"],"description":"What each decision moved. rows[]: every failing scored row with points = the score recomputed with that row passing minus the score now (same formula, Reach + 15 ceiling included), points_section_average, and why a row moves nothing; withheld (rows_withheld) where the fix list is. Findings move no points: each finding's score_effect states the letter cap it sets, whether it binds, and the letter without it."},"confidence":{"type":["object","null"],"description":"Counts and ratios behind the reading: sections_scored, identities_answered, fetches_kept, stage_failures, non_observations, vantages. No composite number, because the parts do not combine into one honestly"},"bitemporal":{"type":["object","null"],"description":"Each stated fact with two times: when CrawlCheck observed it (observed_from, observed_last, removed_at) and when the site says it became true (valid time, null when the site does not say)"},"non_observations":{"type":["array","null"],"maxItems":80,"items":{"type":"object","properties":{"subject":{"type":["string","null"]},"state":{"type":["string","null"]},"reason":{"type":["string","null"]},"attempted":{"type":["boolean","null"]}}},"description":"What was not measured on this scan and why; an unmeasured subject is never scored as a pass or a fail"},"fact_lineage":{"type":["object","null"],"description":"Each business fact (name, phone, address, email, founder) with every value the site stated and where it stated it, and whether the statements agree"},"checks":{"type":"array","items":{"type":"object","properties":{"path":{"type":["string","null"]},"status":{"type":["number","null"]},"bytes":{"type":["number","null"]}}}},"agentview":{"type":"array","items":{"type":"object","properties":{"label":{"type":["string","null"]},"status":{"type":["number","null"]},"words":{"type":["number","null"]}}}},"nap":{"type":["object","null"]},"headroom":{"type":["object","null"],"properties":{"gain":{"type":["number","null"]},"failing":{"type":["number","null"]}}},"history":{"type":"array","items":{"type":"object","properties":{"at":{"type":["string","null"]},"overall":{"type":["number","null"]},"score_version":{"type":["number","null"]}}}},"proof":{"type":"object","properties":{"digest":{"type":["string","null"]},"algorithm":{"type":["string","null"]},"anchored":{"type":["string","null"]},"verify":{"type":["string","null"]}}},"links":{"type":"object"}},"examples":[{"schema":"https://crawlcheck.io/api/v1/schema#PublicReportV1","version":"1.0","id":"qw0tlfel5v","domain":"crawlcheck.io","path":"/","scanned_host":"crawlcheck.io","scanned_at":"2026-10-01T00:47:22.513Z","score_version":26,"grade":"A","overall":98,"grade_detail":{"capped":false,"cap":null,"cap_reason":null},"sections":[{}],"findings":[],"findings_withheld":null,"score_ledger":{"score":98,"letter":"A","cap":null,"capped":false,"held_at_reach":false,"matches_record":true,"rows":[],"rows_withheld":3,"method":"Points per row: the score recomputed with that one row passing, minus the score…"},"findings_summary":null,"provenance":{"v":1,"observer":"crawlcheck-worker","observer_build":"12ef3944-55a9-4ed3-89ce-74cd335f3bfd","observer_tag":"fd25067219215063","vantage":{},"rulepack":"sv26","audit_version":4,"meg_v":3,"scope":"full","observed_at":"2026-10-01T00:47:22.513Z","stored_at":"2026-10-01T00:47:38.932Z","artifacts":"manifest:3a3c742064416f0031b4cfefc494f7939adf2e36a606d68440421f998d9bc0d4","findings":0,"decisions":0,"manifest_signature":{}},"confidence":{"v":1,"sections_scored":{},"identities_answered":{},"fetches_kept":{},"stage_failures":0,"non_observations":6,"non_observations_attempted":2,"vantages":1,"refused":false,"note":"counts and ratios only - there is no composite confidence number, because the p…"},"bitemporal":{"v":1,"recorded_at":"2026-10-01T00:47:22.513Z","axes":{},"facts":[]},"non_observations":[{}],"checks":[{}],"agentview":[{}],"nap":{"phones":[],"addresses":[],"citations":[],"verified":[],"hours":[],"conflicts":{},"lineage":{}},"fact_lineage":{"v":1,"scored":false,"facts":[],"disagree":[],"single_source":[],"subject":{},"read":{}},"headroom":{"gain":2,"failing":3},"history":[{}],"proof":{"digest":"0c329e45045d659a4ec3dbe4584ac17f01ee82735467f8cde2856493079825b8","algorithm":"sha256 over the canonical measurement subject described at https://crawlcheck.i…","anchored":"daily, OpenTimestamps to Bitcoin","verify":"https://crawlcheck.io/proof"},"links":{"report":"https://crawlcheck.io/r/qw0tlfel5v","graph":"https://crawlcheck.io/api/graph/qw0tlfel5v","raw":"https://crawlcheck.io/r/qw0tlfel5v.raw.json","schema":"https://crawlcheck.io/api/v1/schema","docs":"https://crawlcheck.io/docs/api#api-v-scan"}}]},"MachineRecordV1":{"type":"object","required":["kind","version","subject","observation","findings","capabilities","evidence","access"],"description":"One observation in one shape (GET /api/v1/machine-record, MCP machine_record): subject, observation, findings (top in full without a licence; the rest locked), capabilities with safety class and verification state, evidence roots and verifier links","properties":{"kind":{"const":"crawlcheck-machine-record"},"version":{"type":"string"},"subject":{"type":"object"},"observation":{"type":"object"},"findings":{"type":"array","description":"each open finding carries trust {freshness, confidence {level, means, basis[]}, contradictions[]}"},"freshness":{"type":"object","description":"observed_at, age_hours, latest_report_id, is_latest, newer_scan_exists, last_second_reading_at"},"score_ledger":{"type":["object","null"],"description":"score, letter, cap and the points each failing row moves (rows open with a licence); each open finding carries score_effect {points: 0, cap, binding, letter_without_it, says}"},"confidence":{"type":"object","description":"counts and ratios plus vantages; no composite number; levels: contested | cross_vantage_confirmed | reproduced | single_reading"},"contradictions":{"type":"object","description":"site (the site contradicts itself) and between_networks_open (observers disagree), for findings this caller can open"},"findings_summary":{"type":["object","null"]},"findings_withheld":{"type":["string","null"]},"capabilities":{"type":"object"},"evidence":{"type":"object"},"access":{"type":"object"}},"examples":[{"schema":"https://crawlcheck.io/api/v1/schema#MachineRecordV1","version":"1.0","kind":"crawlcheck-machine-record","subject":{"domain":"wikipedia.org","host":"www.wikipedia.org","path":"/","report_id":"evuew4dyje","scanned_at":"2026-10-01T00:47:02.058Z","score_version":26},"observation":{"grade":"D","overall":53,"refused":false,"unscored_reason":null,"trace_id":"0fc371afddbba3d58a9555fb798968c6","observer":{},"identity_basis":"every identity was sent by CrawlCheck from its own network; none is the named o…"},"findings":[{}],"findings_summary":{"total":5,"serious":1,"by_severity":{}},"findings_withheld":"Every finding is listed by title, severity and path. The top one carries its co…","capabilities":{"observed":true,"sources":[],"declared":0,"by_safety_class":{},"by_verification":{},"verified":[],"mismatches":[],"verification":null,"items":[],"reading":"verified means CrawlCheck called it and the response matched what the site decl…"},"observers":{"registry":"https://crawlcheck.io/.well-known/crawlcheck-observers.json","count_for_this_domain":2,"side_by_side":{}},"freshness":{"observed_at":"2026-10-01T00:47:02.058Z","age_hours":0,"latest_report_id":"evuew4dyje","is_latest":true,"newer_scan_exists":false,"last_second_reading_at":"2026-09-30T15:55:13.473Z","note":"observed_at is when CrawlCheck fetched the site; nothing here says the site is …"},"confidence":{"v":1,"sections_scored":{},"identities_answered":{},"fetches_kept":{},"stage_failures":0,"non_observations":14,"non_observations_attempted":8,"vantages":1,"refused":false,"note":"counts and ratios only - there is no composite confidence number, because the p…","vantages_note":"CrawlCheck’s network plus every independent observer that read this URL within …","levels":{}},"contradictions":{"site":[],"between_networks_open":[],"locked_findings_not_shown":4},"evidence":{"manifest_sha256":"9bc892a9b74d9a116e5cc5bd992a7f71a28679d1508e91bf1d8cad2397c5be4a","manifest_version":3,"signed":true,"signing_kid":"hcIAczGf-8EFBnkunmZlvFWnD2nHHeHeC9cM4BTiBVo","roots":{},"experiences":22,"verify":"https://crawlcheck.io/api/verify?id=evuew4dyje","bundle":"https://crawlcheck.io/api/bundle?id=evuew4dyje","offline_verifier":"https://crawlcheck.io/crawlcheck-verify.mjs","prov":null},"score_ledger":{"score":53,"letter":"D","cap":"C","capped":false,"held_at_reach":false,"matches_record":true,"rows":[],"rows_withheld":26,"method":"Points per row: the score recomputed with that one row passing, minus the score…"},"access":{"level":"public","rule":"the top finding in full; the rest by title, severity and path (a licence for th…"}}]},"ErrorV1":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"status":{"type":"integer"},"message":{"type":"string"}}}}}}}