API reference › Get started › Check a domain
Check a domain
/v1/checkspropgate check <domain> --remoteDiagnose any domain, against no account and no profile. This is the only
endpoint that needs no API key — it is what the checker on
propgate.dev calls, and it is the same engine as
propgate check and the sweeper.
It reads DNS and writes nothing. Nothing is registered, no state moves, and
no webhook fires. If what you want is to re-check a domain you have already
registered, that is
POST /v1/domains/:id/checks instead.
curl -s -X POST https://api.propgate.dev/v1/checks \
-H 'content-type: application/json' \
-d '{"domain":"example.com","checks":["spf"],"spfInclude":"_spf.google.com"}'Body
| Field | Type | Description |
|---|---|---|
| domain* | string | The domain to check. Must have at least two labels and must not be a public suffix. |
| checks | string[] | Which checks to run: delegation, spf, dkim, dmarc, mx, caa, ownership, cname. Defaults to all of them; a check with nothing to compare against is skipped rather than reported. |
| spfInclude | string | An include: token that must authorise this domain, expanded recursively the way an MTA would. |
| spfIp | string | A specific sending address to evaluate the record against. |
| dkimSelectors | string[] | Up to ten DKIM selectors to look up. |
| caaIssuer | string | A certificate authority the CAA tree must authorise. |
| ownership | object[] | Up to five ownership tokens, each { token, label? }. The token is compared byte for byte; omit the label for the apex. |
| cnames | object[] | Up to five aliases, each { label, target }. The target is resolved, so a provider that flattened the alias into address records passes rather than failing. |
| expectsMail | boolean | Tri-state, and deliberately not defaulted. Omit it and the check makes no claim; false asserts the domain receives no mail, which makes a null MX correct rather than a fault. |
{
"data": {
"object": "check",
"domain": "example.com",
"verdict": "fail",
"elapsedMs": 214,
"findings": [
{
"code": "SPF_SOURCE_NOT_AUTHORIZED",
"slug": "spf-source-not-authorized",
"severity": "error",
"summary": "This domain's SPF record does not authorise the sending service being set up, so its messages will fail SPF.",
"evidence": {
"detail": "add include:_spf.google.com before the all mechanism; added after it, the term never runs",
"observed": "no include: or redirect= terms at all",
"expected": "include:_spf.google.com"
}
}
],
"checks": [
{
"kind": "spf",
"verdict": "fail",
"findings": ["…"],
"lookups": [
{
"name": "example.com",
"type": 16,
"purpose": "the domain's SPF record",
"server": "10.10.0.10:53",
"status": "answered"
}
]
}
]
},
"error": null,
"meta": { "resolver": "10.10.0.10:53" }
}Every finding carries a diagnosis code, what was observed and
what was expected. lookups is the derivation: which queries were sent, to
which server, and what each returned. A verdict you cannot audit is a verdict
you have to take on faith.
Rate limit
20 checks a minute per address, keyed on X-Forwarded-For. A check costs
up to about twenty upstream queries aimed at whichever authoritative servers
the caller names, so an unauthenticated endpoint is sized against other
people's infrastructure rather than ours.
HTTP/1.1 429 Too Many Requests
retry-after: 43
{"data":null,"error":{"message":"too many checks; try again in 43s"},"meta":null}If you are checking domains on a schedule, register them instead and let the sweeper do it — that is what it is for, and it does not come through here.