CrawlCheck resolve answer (ResolveV1)
GET /api/v1/resolve?domain=: what an agent should know before acting on a domain. Signed with Ed25519 over sha256 of the canonical JSON of every field except sha256 and signature, message prefix crawlcheck-data-v1\n; verify offline with crawlcheck-verify.mjs.
Properties
| Name | Type | Description |
|---|---|---|
| kind | object | |
| v | object | |
| schema | string | |
| domain | string | |
| answered_at | string | |
| reading | string | |
| degraded | object | spec 1.4.0 (dg1): sources that could not be read when the answer was made: sources [{source, why}], reading, policy (the failure policy URL), policy_v. Present only when something was missing. |
| assurance | object | Present on just-in-time answers only. Full answers carry no assurance field. |
| disputes | object | spec 1.4.0: open (being re-measured), filed, ledger; open > 0 adds the doubt disputed to read and cite |
| status | object | withheld (dg1): the opt-out list could not be read, so nothing about the domain is served. partial (jit1): a domain CrawlCheck had never measured, read live the moment it was asked about; assurance is |
| why | string | |
| basis | object | Present when the answer comes from the daily census or a just-in-time read rather than a full scan record: kind, run, rank, measured_at, scope; just_in_time adds budget_ms, took_ms and not_read_in_bud |
| dns | object | jit1, just-in-time answers: A/AAAA/CNAME from Cloudflare DNS over HTTPS, rcode, exists, dnssec_validated (the resolver's AD flag) |
| tls | object | jit1, just-in-time answers: whether the homepage fetch completed over HTTPS with a trusted certificate, final host, HSTS header |
| upgrade | object | jit1, just-in-time answers: state queued, to full; the change feed records assurance partial → full when the full scan lands |
| measurement | object | |
| subject | object | |
| freshness | objectnull | observed_at, age_hours, fresh_until, stale, last_verified_at, fresh_policy (rsv3, provisional), plus latest_report_id / is_latest / newer_scan_exists |
| observers | object | |
| rights | objectnull | rgt1: one value per use (train, ground, summarize, cite, transact): allowed | denied | limited | restricted_by_terms | not_declared | unknown, each with decided_by {signal, url, evidence}, the signals |
| read_equivalence | objectnull | req1: whether the main text served to AI identities (GPTBot, ClaudeBot, PerplexityBot) equals what a browser receives on the homepage: verdict equivalent|minor_differences|different|not_served|unverif |
| identity | objectnull | ident1: who this domain is and how many independent sources confirm it (state confirmed | unconfirmed | claimed | disputed | unknown, name, independent_confirmations, confirmed_by[], confirm_with); pr |
| facts | objectnull | rfact1: the site's claims an outside source was seen to agree with, as triples {subject, predicate, value, evidence[], observed_at}; signed with the answer. not_facts counts the claims that are page-o |
| self_claims | objectnull | scl1: what the site says about itself (telephone, email, address, hours, prices, refund window, founded, years in business, API rate limits), claims[] each with type, value, status current|withdrawn, |
| content_clock | objectnull | clk2 (provisional): when the main content of the homepage (and of ?page= on the same site) last changed, from CrawlCheck's own reads: content_sha256, first_observed, main_content_last_changed {between |
| absences | array | sa1: what CrawlCheck looked for and did not find, each with what was requested (method, URL, status), the vantage, the time and a scope saying what the absence does and does not mean. Written only for |
| mcp_registry | object | rsv4 (provisional): remote MCP servers the official MCP Registry lists on this domain and what each endpoint answered to the MCP handshake (listed, observed, initialized, auth_required, drifted, serve |
| impersonation | object | spec 1.2.0: whether the domain looks built to be mistaken for a known brand (state, verdict, the brand frame it was compared against, and the technique when one is found) |
| control | object | spec 1.3.0: whether control of the domain has been proven to CrawlCheck: state proven | unproven; proofs [{by: licence_holder | registry_claim, method: dns_txt | meta_tag | well_known_file | cloudflar |
| transparency | object | spec 1.2.0: this answer's place in the append-only answer log: state (included or pending; pending with confirmed false means the lookup did not answer within the time budget and the proof URL settles |
| actions | object | rsv3 (provisional): read, cite, connect, transact, administer - each { decision: allow|warn|require_confirmation|block|unsupported, minimum_assurance, assurance_found[], needs, why, max_age_hours }, d |
| crawl_policy | object | |
| delivery | object | |
| machine_files | object | |
| capabilities | object | |
| entity | object | |
| findings | object | |
| confidence | objectnull | |
| contradictions | objectnull | |
| evidence | object | |
| sha256 | stringnull | |
| signature | objectnull | |
| unsigned | string |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://crawlcheck.io/schemas/resolve.json",
"title": "CrawlCheck resolve answer (ResolveV1)",
"description": "GET /api/v1/resolve?domain=: what an agent should know before acting on a domain. Signed with Ed25519 over sha256 of the canonical JSON of every field except sha256 and signature, message prefix crawlcheck-data-v1\\n; verify offline with crawlcheck-verify.mjs.",
"type": "object",
"required": [
"kind",
"v",
"domain",
"status",
"answered_at",
"sha256",
"signature"
],
"$defs": {
"section": {
"type": "object",
"required": [
"state",
"observed_at"
],
"properties": {
"state": {
"enum": [
"declared",
"observed",
"not_measured"
]
},
"observed_at": {
"type": [
"string",
"null"
]
},
"why": {
"type": "string"
}
}
}
},
"properties": {
"kind": {
"const": "crawlcheck-resolve"
},
"v": {
"const": 1
},
"schema": {
"type": "string"
},
"domain": {
"type": "string"
},
"answered_at": {
"type": "string"
},
"reading": {
"type": "string"
},
"degraded": {
"type": "object",
"description": "spec 1.4.0 (dg1): sources that could not be read when the answer was made: sources [{source, why}], reading, policy (the failure policy URL), policy_v. Present only when something was missing.",
"properties": {
"sources": {
"type": "array",
"items": {
"type": "object",
"required": [
"source",
"why"
]
}
},
"policy": {
"type": "string"
}
}
},
"assurance": {
"enum": [
"partial"
],
"description": "Present on just-in-time answers only. Full answers carry no assurance field."
},
"disputes": {
"type": "object",
"description": "spec 1.4.0: open (being re-measured), filed, ledger; open > 0 adds the doubt disputed to read and cite"
},
"status": {
"enum": [
"measured",
"partial",
"not_measured",
"opted_out",
"withheld"
],
"description": "withheld (dg1): the opt-out list could not be read, so nothing about the domain is served. partial (jit1): a domain CrawlCheck had never measured, read live the moment it was asked about; assurance is partial and upgrade says when the full scan replaces it"
},
"why": {
"type": "string"
},
"basis": {
"type": "object",
"description": "Present when the answer comes from the daily census or a just-in-time read rather than a full scan record: kind, run, rank, measured_at, scope; just_in_time adds budget_ms, took_ms and not_read_in_budget (paths not read in time, never reported absent)",
"properties": {
"kind": {
"enum": [
"census",
"just_in_time"
]
},
"run": {
"type": [
"integer",
"null"
]
},
"measured_at": {
"type": [
"string",
"null"
]
},
"scope": {
"type": "string"
},
"budget_ms": {
"type": "integer"
},
"took_ms": {
"type": "integer"
},
"not_read_in_budget": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"dns": {
"type": "object",
"description": "jit1, just-in-time answers: A/AAAA/CNAME from Cloudflare DNS over HTTPS, rcode, exists, dnssec_validated (the resolver's AD flag)"
},
"tls": {
"type": "object",
"description": "jit1, just-in-time answers: whether the homepage fetch completed over HTTPS with a trusted certificate, final host, HSTS header"
},
"upgrade": {
"type": "object",
"description": "jit1, just-in-time answers: state queued, to full; the change feed records assurance partial → full when the full scan lands"
},
"measurement": {
"type": "object",
"properties": {
"requested": {
"type": "boolean"
},
"first_request": {
"type": "boolean"
},
"how": {
"type": "string"
}
}
},
"subject": {
"type": "object"
},
"freshness": {
"type": [
"object",
"null"
],
"description": "observed_at, age_hours, fresh_until, stale, last_verified_at, fresh_policy (rsv3, provisional), plus latest_report_id / is_latest / newer_scan_exists"
},
"observers": {
"type": "object"
},
"rights": {
"type": [
"object",
"null"
],
"description": "rgt1: one value per use (train, ground, summarize, cite, transact): allowed | denied | limited | restricted_by_terms | not_declared | unknown, each with decided_by {signal, url, evidence}, the signals considered and the conflicts between them; merged from robots.txt per agent, Content-Signal, ai.txt, TDM-Rep, robots meta, X-Robots-Tag and the terms page"
},
"read_equivalence": {
"type": [
"object",
"null"
],
"description": "req1: whether the main text served to AI identities (GPTBot, ClaudeBot, PerplexityBot) equals what a browser receives on the homepage: verdict equivalent|minor_differences|different|not_served|unverifiable, per-identity text_ratio, instruction_like_text; api link holds the differing sentences. The cite action warns with served_text_differs"
},
"identity": {
"type": [
"object",
"null"
],
"description": "ident1: who this domain is and how many independent sources confirm it (state confirmed | unconfirmed | claimed | disputed | unknown, name, independent_confirmations, confirmed_by[], confirm_with); preflight names it in every receipt"
},
"facts": {
"type": [
"object",
"null"
],
"description": "rfact1: the site's claims an outside source was seen to agree with, as triples {subject, predicate, value, evidence[], observed_at}; signed with the answer. not_facts counts the claims that are page-only, unverified or contradicted."
},
"self_claims": {
"type": [
"object",
"null"
],
"description": "scl1: what the site says about itself (telephone, email, address, hours, prices, refund window, founded, years in business, API rate limits), claims[] each with type, value, status current|withdrawn, first_seen, last_seen; changes are in the change feed as section self_claims; api link for evidence and pages read"
},
"content_clock": {
"type": [
"object",
"null"
],
"description": "clk2 (provisional): when the main content of the homepage (and of ?page= on the same site) last changed, from CrawlCheck's own reads: content_sha256, first_observed, main_content_last_changed {between, and}, declared dates, api link"
},
"absences": {
"type": "array",
"description": "sa1: what CrawlCheck looked for and did not find, each with what was requested (method, URL, status), the vantage, the time and a scope saying what the absence does and does not mean. Written only for definite answers (404/410, a finished registry import, a completed field read)",
"items": {
"type": "object",
"required": [
"what",
"result",
"at",
"from",
"checked",
"scope"
]
}
},
"mcp_registry": {
"type": "object",
"description": "rsv4 (provisional): remote MCP servers the official MCP Registry lists on this domain and what each endpoint answered to the MCP handshake (listed, observed, initialized, auth_required, drifted, servers[])"
},
"impersonation": {
"type": "object",
"description": "spec 1.2.0: whether the domain looks built to be mistaken for a known brand (state, verdict, the brand frame it was compared against, and the technique when one is found)"
},
"control": {
"type": "object",
"description": "spec 1.3.0: whether control of the domain has been proven to CrawlCheck: state proven | unproven; proofs [{by: licence_holder | registry_claim, method: dns_txt | meta_tag | well_known_file | cloudflare_zone, how, since}]; organization {name, github, record} when its holder published one; claim (where to prove it) while unproven; why; note. Informational: it never changes a decision."
},
"transparency": {
"type": "object",
"description": "spec 1.2.0: this answer's place in the append-only answer log: state (included or pending; pending with confirmed false means the lookup did not answer within the time budget and the proof URL settles it), log_id, leaf_hash, batch, index, the inclusion path and the signed tree head it folds to"
},
"actions": {
"type": "object",
"description": "rsv3 (provisional): read, cite, connect, transact, administer - each { decision: allow|warn|require_confirmation|block|unsupported, minimum_assurance, assurance_found[], needs, why, max_age_hours }, decided from this answer at signing time"
},
"crawl_policy": {
"allOf": [
{
"$ref": "#/$defs/section"
}
],
"properties": {
"agents": {
"type": "array",
"items": {
"type": "object",
"required": [
"agent",
"allowed_homepage"
],
"properties": {
"agent": {
"type": "string"
},
"allowed_homepage": {
"type": "boolean"
},
"allowed_path": {
"type": "boolean"
},
"has_own_group": {
"type": "boolean"
},
"wildcard_rules_shadowed": {
"type": "boolean"
}
}
}
}
}
},
"delivery": {
"allOf": [
{
"$ref": "#/$defs/section"
}
],
"properties": {
"identities": {
"type": "array",
"items": {
"type": "object",
"required": [
"identity",
"status"
],
"properties": {
"identity": {
"type": "string"
},
"status": {
"type": [
"integer",
"null"
]
},
"words": {
"type": [
"integer",
"null"
]
},
"blocker": {
"type": [
"string",
"null"
]
},
"redirected_to": {
"type": [
"string",
"null"
]
}
}
}
}
}
},
"machine_files": {
"allOf": [
{
"$ref": "#/$defs/section"
}
],
"properties": {
"files": {
"type": "array",
"items": {
"type": "object",
"required": [
"path",
"status"
]
}
}
}
},
"capabilities": {
"allOf": [
{
"$ref": "#/$defs/section"
}
],
"properties": {
"declared": {
"type": "integer"
},
"verified": {
"type": "integer"
},
"mismatches": {
"type": "integer"
},
"certificate": {
"type": [
"object",
"null"
]
}
}
},
"entity": {
"allOf": [
{
"$ref": "#/$defs/section"
}
],
"properties": {
"links": {
"type": "array",
"items": {
"type": "object",
"required": [
"url",
"state"
]
}
}
}
},
"findings": {
"type": "object",
"required": [
"access",
"items"
],
"properties": {
"access": {
"type": "string"
},
"items": {
"type": "array"
}
}
},
"confidence": {
"type": [
"object",
"null"
]
},
"contradictions": {
"type": [
"object",
"null"
]
},
"evidence": {
"type": "object"
},
"sha256": {
"type": [
"string",
"null"
],
"pattern": "^[0-9a-f]{64}$"
},
"signature": {
"type": [
"object",
"null"
],
"properties": {
"alg": {
"const": "Ed25519"
},
"kid": {
"type": "string"
},
"message": {
"type": "string"
},
"sig": {
"type": "string"
}
}
},
"unsigned": {
"type": "string"
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
curl "https://apis.io/api/v1/json-schemas/crawlcheck-io-resolve"
curl "https://apis.io/api/v1/json-schemas?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.