InboxGuard · Schema
ScanResult
Scan response. The per-check objects are TOP-LEVEL properties — there is no `checks` wrapper and no per-check {status, summary} shape.
Email DeliverabilityDMARCDNS MonitoringAuthenticationSecurity
Properties
| Name | Type | Description |
|---|---|---|
| domain | string | |
| score | object | |
| scoringVersion | integer | Version of the scoring model that produced `score`. |
| spf | object | |
| dmarc | object | |
| ptr | object | |
| dkim | object | |
| mtaSts | object | |
| tlsRpt | object | |
| mxTls | object | |
| bimi | object | |
| blocklist | object | |
| dnssec | object | |
| remediations | array | Per-failing-check fix list (critical first). Each item is the concrete next action — the exact DNS record to publish plus whether the registrar auto-fix engine can apply it. Healthy checks contribute |
| durationMs | integer | |
| plan | object |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/inboxguard-io/json-schema/inboxguard-io-scan-result-schema.json",
"title": "ScanResult",
"description": "Scan response. The per-check objects are TOP-LEVEL properties — there is no `checks` wrapper and no per-check {status, summary} shape.",
"x-generated": "2026-11-12",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/inboxguard-io-openapi.json#/components/schemas/ScanResult",
"type": "object",
"properties": {
"domain": {
"type": "string"
},
"score": {
"$ref": "#/$defs/ScanScore"
},
"scoringVersion": {
"type": "integer",
"description": "Version of the scoring model that produced `score`."
},
"spf": {
"$ref": "#/$defs/DomainCheck"
},
"dmarc": {
"$ref": "#/$defs/DomainCheck"
},
"ptr": {
"$ref": "#/$defs/DomainCheck"
},
"dkim": {
"$ref": "#/$defs/DomainCheck"
},
"mtaSts": {
"$ref": "#/$defs/DomainCheck"
},
"tlsRpt": {
"$ref": "#/$defs/DomainCheck"
},
"mxTls": {
"$ref": "#/$defs/DomainCheck"
},
"bimi": {
"$ref": "#/$defs/DomainCheck"
},
"blocklist": {
"$ref": "#/$defs/DomainCheck"
},
"dnssec": {
"$ref": "#/$defs/DnssecResult"
},
"remediations": {
"type": "array",
"description": "Per-failing-check fix list (critical first). Each item is the concrete next action — the exact DNS record to publish plus whether the registrar auto-fix engine can apply it. Healthy checks contribute nothing, so this is empty when the domain is clean.",
"items": {
"$ref": "#/$defs/Remediation"
}
},
"durationMs": {
"type": "integer"
},
"plan": {
"type": "object",
"properties": {
"tier": {
"type": "string",
"description": "public (anonymous), free, entry, pro, or agency."
},
"trialing": {
"type": "boolean"
},
"blocklistsChecked": {
"description": "Number of blocklists checked, or 'all'.",
"anyOf": [
{
"type": "integer"
},
{
"type": "string"
}
]
}
}
}
},
"required": [
"domain",
"score",
"scoringVersion",
"spf",
"dmarc",
"ptr",
"dkim",
"mtaSts",
"tlsRpt",
"mxTls",
"bimi",
"blocklist",
"dnssec",
"remediations",
"durationMs",
"plan"
],
"$defs": {
"ComponentScore": {
"type": "object",
"description": "Scoring model v3 (2026-08-05) per-check applicability verdict. 'scored' = a real 0..weight number, exactly as before. 'not_applicable' = this check doesn't apply to this domain (e.g. MTA-STS/TLS-RPT on a domain confirmed to publish no MX) — excluded from both the score's numerator and denominator; render as neutral, remediation suppressed. 'undetermined' = couldn't be determined this scan (a DNS lookup failure, or — DKIM only — an ESP that mints an unenumerable per-tenant selector, e.g. Amazon SES Easy DKIM); same exclusion as not_applicable, but render as neutral/\"Unverified\", NEVER as a pass or failure. See https://inboxguard.io/llms-full.txt#scoring.",
"properties": {
"state": {
"type": "string",
"enum": [
"scored",
"not_applicable",
"undetermined"
]
},
"earned": {
"type": "number",
"description": "Points earned this scan. 0 whenever state != 'scored'."
},
"max": {
"type": "number",
"description": "Points counted toward the renormalized denominator this scan. 0 whenever state != 'scored'."
},
"weight": {
"type": "number",
"description": "The check's nominal/full weight, unaffected by applicability."
},
"reason": {
"type": "string",
"enum": [
"no_mx",
"null_mx",
"esp_selectors_not_enumerable",
"dns_lookup_failed",
"check_not_run"
],
"description": "Present only for not_applicable/undetermined."
}
},
"required": [
"state",
"earned",
"max",
"weight"
]
},
"DnssecResult": {
"type": "object",
"description": "DNSSEC + DANE/TLSA detection (INFORMATIONAL — does not feed the score). Always present on the live /scan-domain response.",
"properties": {
"domain": {
"type": "string"
},
"dsPresent": {
"type": "boolean",
"description": "DS record present at the parent — the chain of trust is anchored."
},
"dnskeyPresent": {
"type": "boolean",
"description": "Zone publishes DNSKEY records."
},
"enabled": {
"type": "boolean",
"description": "True only when the zone is signed AND anchored (DS + DNSKEY). DNSKEY without DS is treated as unsigned by validating receivers."
},
"dane": {
"type": "array",
"description": "Per-MX DANE/TLSA presence (TLSA at _25._tcp.<mxhost>). Empty when the domain has no MX.",
"items": {
"type": "object",
"properties": {
"mxHost": {
"type": "string"
},
"tlsaPresent": {
"type": "boolean"
}
},
"required": [
"mxHost",
"tlsaPresent"
]
}
},
"daneEnabled": {
"type": "boolean",
"description": "True when at least one MX host advertises DANE TLSA."
},
"checkError": {
"type": "boolean",
"description": "DNS resolution temp-failed; the result is \"unknown\", not \"off\". Re-scan to confirm."
},
"issues": {
"type": "array",
"items": {
"$ref": "#/$defs/Issue"
}
}
},
"required": [
"domain",
"dsPresent",
"dnskeyPresent",
"enabled",
"dane",
"daneEnabled",
"checkError",
"issues"
]
},
"DomainCheck": {
"type": "object",
"description": "Result of one authentication/transport/reputation check. Carries `healthy` (boolean) and `issues` (array of {severity, message}) plus check-specific fields — e.g. SPF `record`/`lookupCount`/`allQualifier`/`permerrors`, DMARC `policy`/`pct`/`rua`, DKIM `keys[]` (selector, keyLengthBits, …), PTR `mxIps[]`, MTA-STS `policy`, BIMI `logoUrl`/`vmcUrl`, blocklist `hits[]`/`targets[]`/`checked`/`errored`. Exceptions: `mxTls` has `status` ('unsupported'|'pass'|'fail'|'partial') instead of `healthy` plus `basis` ('live'|'policy'|'none') describing how the verdict was reached — when an outbound STARTTLS probe isn't available the verdict is derived from MTA-STS/DANE policy (basis 'policy'); and `bimi` uses `found`/`logoReachable`/`displayEligible`.",
"properties": {
"healthy": {
"type": "boolean",
"description": "Whether this check passed cleanly (absent on mxTls and bimi — see description)."
},
"status": {
"type": "string",
"enum": [
"unsupported",
"pass",
"fail",
"partial"
],
"description": "mxTls only — the transport-TLS verdict (used instead of `healthy`)."
},
"basis": {
"type": "string",
"enum": [
"live",
"policy",
"none"
],
"description": "mxTls only — how `status` was determined: 'live' (real STARTTLS handshake), 'policy' (derived from MTA-STS enforce/testing or DANE when a live probe isn't available — needs no outbound port 25), or 'none' (no probe and no enforcing policy)."
},
"issues": {
"type": "array",
"items": {
"$ref": "#/$defs/Issue"
},
"description": "Findings, each with severity and message."
}
},
"additionalProperties": true
},
"Issue": {
"type": "object",
"description": "One finding inside a check.",
"properties": {
"severity": {
"type": "string",
"enum": [
"info",
"warn",
"critical"
]
},
"message": {
"type": "string"
}
},
"required": [
"severity",
"message"
]
},
"Remediation": {
"type": "object",
"description": "One concrete fix for a failing/weak check, derived from the structured scan result.",
"properties": {
"check": {
"type": "string",
"enum": [
"spf",
"dmarc",
"dkim",
"ptr",
"mta-sts",
"tls-rpt",
"bimi",
"blocklist",
"dnssec"
]
},
"code": {
"type": "string",
"description": "Stable machine code, e.g. 'dmarc_missing'."
},
"severity": {
"type": "string",
"enum": [
"critical",
"warn",
"info"
]
},
"title": {
"type": "string"
},
"summary": {
"type": "string"
},
"steps": {
"type": "array",
"items": {
"type": "string"
}
},
"record": {
"$ref": "#/$defs/RemediationRecord"
},
"links": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"href": {
"type": "string",
"format": "uri"
}
},
"required": [
"label",
"href"
]
}
},
"effort": {
"type": "string",
"enum": [
"5 min",
"15 min",
"30 min",
"1 hour"
]
},
"autoFixable": {
"type": "boolean",
"description": "True when the registrar auto-fix engine (POST /domains/{id}/dns-apply) can publish this without customer input. SPF/DKIM/BIMI are guidance-only (false) even though a record is shown; a MISSING DMARC, the MTA-STS version TXT, and TLS-RPT are auto-fixable."
}
},
"required": [
"check",
"code",
"severity",
"title",
"summary",
"steps",
"autoFixable"
]
},
"RemediationRecord": {
"type": "object",
"description": "The exact DNS record to publish for a fix. Kept byte-for-byte identical to what the registrar auto-fix engine would write.",
"properties": {
"host": {
"type": "string",
"description": "Record name/host, e.g. '@' for the apex or '_dmarc.example.com'."
},
"type": {
"type": "string",
"enum": [
"TXT",
"CNAME",
"MX"
]
},
"value": {
"type": "string"
},
"note": {
"type": "string",
"description": "Optional caveat (e.g. replace placeholder senders, also host the MTA-STS policy file)."
}
},
"required": [
"host",
"type",
"value"
]
},
"ScanScore": {
"type": "object",
"description": "Overall deliverability score with a per-check point breakdown.",
"properties": {
"total": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"description": "Overall 0–100 score, renormalized over what's actually applicable (total = round(100 * earnedTotal / applicableMax))."
},
"grade": {
"type": "string",
"enum": [
"A",
"B",
"C",
"D",
"F"
]
},
"breakdown": {
"type": "object",
"description": "Points contributed by each check.",
"properties": {
"spf": {
"type": "number"
},
"dmarc": {
"type": "number"
},
"ptr": {
"type": "number"
},
"dkim": {
"type": "number"
},
"bimi": {
"type": "number"
},
"mtaSts": {
"type": "number"
},
"tlsRpt": {
"type": "number"
},
"blocklist": {
"type": "number"
}
}
},
"components": {
"type": "object",
"description": "Scoring model v3 (2026-08-05) — per-check applicability state. Absent on a cached response from before that date; treat absence exactly like every check being 'scored'.",
"properties": {
"spf": {
"$ref": "#/$defs/ComponentScore"
},
"dmarc": {
"$ref": "#/$defs/ComponentScore"
},
"ptr": {
"$ref": "#/$defs/ComponentScore"
},
"dkim": {
"$ref": "#/$defs/ComponentScore"
},
"bimi": {
"$ref": "#/$defs/ComponentScore"
},
"mtaSts": {
"$ref": "#/$defs/ComponentScore"
},
"tlsRpt": {
"$ref": "#/$defs/ComponentScore"
},
"blocklist": {
"$ref": "#/$defs/ComponentScore"
}
}
},
"earnedTotal": {
"type": "number",
"description": "Sum of `earned` across every `scored` component."
},
"applicableMax": {
"type": "number",
"description": "Sum of `max` across every `scored` component — `total`'s denominator."
},
"undeterminedMax": {
"type": "number",
"description": "Sum of `weight` across every `undetermined` component."
},
"degraded": {
"type": "boolean",
"description": "True when any component is `undetermined` because of an actual DNS resolver failure this scan (not a stable ESP-detection state) — a score delta on a degraded scan is scan-quality noise, not a real change."
}
},
"required": [
"total",
"grade",
"breakdown"
]
}
}
}
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
This JSON Schema
curl "https://apis.io/api/v1/json-schemas/inboxguard-io-scan-result"
All schemas
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.