API reference
Deliverability API
Check a sending domain's DNS authentication and IP reputation, then retrieve checks owned by your account. Send your API key in the X-Api-Key header on every request.
Run a deliverability check
/v1/deliverability/checkInspect MX, SPF, DKIM, DMARC, reverse DNS and supported DNS blocklists. A new check costs 10 credits.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
domain | string | Required | Sending domain, such as example.com |
sending_ip | string | Optional | IPv4 address for PTR and blocklist checks. If omitted, PTR is skipped and blocklists use an IP resolved from the domain's MX records. |
refresh | boolean | Optional | Set to true to bypass the 24-hour cache and buy a new 10-credit check. |
These are the only accepted fields. Unknown fields and a non-boolean refresh return HTTP 400 before any history lookup, DNS work or credit movement. sending_ip accepts IPv4 only; null, blank, hostname and IPv6 values are rejected before charging. Omit the field to use MX discovery.
curl -X POST https://api.kawaa.com/v1/deliverability/check \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"domain": "example.com",
"sending_ip": "203.0.113.10"
}'{
"success": true,
"data": {
"domain": "example.com",
"score": 92,
"grade": "A",
"checked_at": "2026-09-14T12:00:00.000Z",
"check_id": "38c271db-97c4-4c0f-88df-a975027240c4",
"dns": {
"mx_records": [{ "priority": 10, "host": "mail.example.com", "ip": null }],
"has_valid_mx": true,
"mx_score": 100
},
"authentication": {
"spf": { "status": "pass", "record": "v=spf1 -all", "score": 100, "issues": [] },
"dkim": { "status": "pass", "selectors_found": ["default"], "score": 100, "issues": [] },
"dmarc": { "status": "pass", "record": "v=DMARC1; p=reject", "policy": "reject", "score": 100, "issues": [] }
},
"reputation": {
"score": 100,
"blacklists_checked": 9,
"blacklists_inconclusive": 3,
"blacklists_skipped": 0,
"blacklists_total": 12,
"blacklists_listed": 0,
"listed_on": []
},
"server": {
"accepts_mail": null,
"response_time_ms": null,
"supports_tls": null,
"tls_version": null,
"reverse_dns": "mail.example.com"
},
"spam_assessment": { "score": 8, "spam_likelihood": "low", "factors": [] },
"recommendations": [],
"credits_used": 10,
"credits_remaining": 490
}
}Cache and charging: a matching domain and sending-IP result from the previous 24 hours returns with cached: true and costs 0 credits, even when the account has fewer than 10 credits. Set refresh: true only when you intend to purchase a new check.
Safe failures: if the result history cannot be read, the API returns 503 before charging. If every DNS lookup times out, it attempts to refund the 10-credit debit and returns 503. Other failures after a debit also attempt a refund and return 500.
Measured scope: the API does not probe an SMTP server today. The server acceptance, response-time and TLS fields are null because they are not measured, not because those checks failed. A reputation score of null likewise means no blocklist returned a verdict.
Safe retries with the Idempotency-Key header
A new check is charged before its DNS work starts, so a request that times out or fails with a 5xx on the way back may already have been charged. To retry it safely, send an optional Idempotency-Key header: any opaque token of 1–255 printable ASCII characters with no spaces (a UUID is fine), unique per logical request, and send the same key again when you retry.
curl -X POST https://api.kawaa.com/v1/deliverability/check \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Idempotency-Key: 6f1c2a4e-3b7d-4e0a-9c11-2d8f5a7b9e01" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com", "refresh": true}'- A repeat after the check was stored answers 200 with the original
check_idand result,"idempotent_replay": true,"credits_used": 0and thecredits_remainingrecorded right after the original charge (left out if that record cannot be read). If the first attempt was paid but has not stored its result yet — it is still running, or its connection dropped — the repeat runs that paid check again without charging and returns the result, whatever your balance. - The debit and the key's claim commit together, so two requests racing with the same key are charged once. A refund and the key's release also commit together: once an attempt is refunded (every DNS lookup timed out, or the result could not be stored), the same key buys a new 10-credit check on its next use, and a refunded attempt is never refunded twice.
- Reusing a key with a different
domain,sending_iporrefreshvalue returns409 IDEMPOTENCY_KEY_CONFLICTbefore anything is charged, and a malformed key returns400 INVALID_IDEMPOTENCY_KEY. Keys are scoped to your account and to this endpoint, and are remembered for 30 days. - The 24-hour cache still applies first: without
refresh, a keyed request for a domain you checked recently gets the free cached result, and that key keeps replaying the same result (withcached: true) for its 30 days even after the cache window passes. Without the header the endpoint behaves exactly as before.
List check history
/v1/deliverability/checks?limit=20The rows considered by this request are sorted newest first. limit defaults to 20 and is capped at 100. The service reads at most 20 history pages. When truncated is false, all of your history was considered; when it is true, rows outside that bounded read were not considered and may be newer or older than the rows returned.
{
"success": true,
"data": {
"checks": [
{
"check_id": "38c271db-97c4-4c0f-88df-a975027240c4",
"domain": "example.com",
"sending_ip": "203.0.113.10",
"score": 92,
"grade": "A",
"checked_at": "2026-09-14T12:00:00.000Z"
}
],
"count": 1,
"total": 1,
"truncated": false
}
}Get a check
/v1/deliverability/checks/{id}Return one check with the same detailed result sections shown above. A missing ID, or an ID owned by another account, returns HTTP 404 without revealing whether another account has that record.