API reference

Build with Confirmail.

One endpoint to verify, clear reasons in every answer, and webhooks when the work is done.

Getting started

The Confirmail API verifies email addresses one by one or in bulk, finds addresses, checks domains and sends webhooks. Every request is JSON over HTTPS.

Base URLhttps://app.confirmail.io/api/v1
AuthenticationheaderAuthorization: Bearer rs_live_…
Rate limit120 requests per minute per key, with RateLimit-* headers

Create a key in your dashboard under API keys. Live keys (rs_live_) verify real addresses and use credits. Test keys (rs_test_) only accept @sandbox.test addresses and are free.

Verify one address

POST/v1/verify

Runs every check (syntax, domain, mailbox, catch-all, disposable, role, typo, provider). 1 credit, except unknown, invalid-format and sandbox results, which are free. GET /v1/verify?email=… works too.

emailstring, requiredThe address to verify.
1curl -X POST https://app.confirmail.io/api/v1/verify \2  -H "Authorization: Bearer rs_live_..." \3  -H "Content-Type: application/json" \4  -d '{"email":"jane@example.com"}'
Response
1{2  "email": "jane@example.com",3  "status": "valid",           // valid | invalid | risky | unknown4  "reason": "MAILBOX_EXISTS",5  "score": 96,6  "signals": ["FREE_PROVIDER"],7  "suggestion": null,          // "jane@gmail.com" when a typo is found8  "provider": "google",9  "gateway": null,             // e.g. "Mimecast", "Proofpoint"10  "catch_all_estimate": null,  // set on catch-all results11  "billed": true,12  "credits_remaining": 199913}

Catch-all estimate

When a domain accepts every address (ACCEPT_ALL), the mail server cannot confirm the mailbox. We still estimate it from the shape of the address, so you can keep the likely ones instead of dropping the whole domain.

Response (excerpt)
1"reason": "ACCEPT_ALL",2"catch_all_estimate": {3  "score": 80,                 // 0-100, likelihood the mailbox is deliverable4  "verdict": "likely_valid",   // likely_valid | uncertain | likely_invalid5  "factors": ["first.last name pattern"]6}

Signals LIKELY_DELIVERABLE and LIKELY_UNDELIVERABLE mirror the verdict. SECURE_GATEWAY means the domain sits behind the gateway named in gateway.

Bulk lists

POST/v1/batches

Creates a list and starts it. Credits are reserved for the addresses that need a check; duplicates are removed first and unknown results are refunded when the list finishes.

namestringA name for the list.
emailsstring[], requiredThe addresses to verify.
Create, follow, download
1# 1. create and start2curl -X POST https://app.confirmail.io/api/v1/batches -H "Authorization: Bearer KEY" \3  -H "Content-Type: application/json" \4  -d '{"name":"October list","emails":["a@x.com","b@y.com"]}'5 6# 2. progress7curl https://app.confirmail.io/api/v1/batches/BATCH_ID -H "Authorization: Bearer KEY"8 9# 3. results as JSON (paginated) or CSV10curl "https://app.confirmail.io/api/v1/batches/BATCH_ID/results?status=valid&limit=500" -H "Authorization: Bearer KEY"11curl -OJ "https://app.confirmail.io/api/v1/batches/BATCH_ID/export?status=valid" -H "Authorization: Bearer KEY"
GET /v1/batchesYour lists, newest first.
statusqueryFilter results: valid, invalid, risky, unknown.
cursor, limitqueryPagination of /results.

Email finder

POST/v1/find

Builds the usual patterns for a person at a company and verifies them until the mail server confirms one. 1 credit only when outcome is found.

first_namestring, requiredFirst name.
last_namestringLast name.
domainstring, requiredCompany domain, e.g. acme.com.
Request
1curl -X POST https://app.confirmail.io/api/v1/find -H "Authorization: Bearer KEY" \2  -H "Content-Type: application/json" \3  -d '{"first_name":"Jane","last_name":"Doe","domain":"acme.com"}'

Returns email, outcome (found, catch_all, unverified, not_found, no_mail) and confidence.

Domain health

GET/v1/domain-health?domain=acme.com

SPF, DKIM, DMARC, MX, MTA-STS, TLS-RPT and BIMI, with a score from 0 to 100 and a grade. Free.

Webhooks

Add a URL in the dashboard, or subscribe with your API key. Events: verification.completed, batch.completed, find.completed, find_job.completed, blacklist.listed, credits.low.

Each delivery is a JSON { event, created_at, data } with the event name in X-Confirmail-Event. URLs must be public https:// addresses; redirects are not followed. Verify the signature before trusting a delivery:

Node.js
1const sig = crypto.createHmac("sha256", WEBHOOK_SECRET).update(rawBody).digest("hex")2if (req.headers["x-confirmail-signature"] !== "sha256=" + sig) return res.status(401).end()

Zapier, Make, n8n

Automation tools subscribe a URL to an event when a scenario is turned on, unsubscribe when it is turned off, and fetch sample data in the exact webhook shape.

REST hooks
1# subscribe (returns the id and the signing secret)2curl -X POST https://app.confirmail.io/api/v1/webhooks -H "Authorization: Bearer KEY" \3  -H "Content-Type: application/json" \4  -d '{"url":"https://hooks.example.com/abc","event":"batch.completed","source":"zapier"}'5 6# unsubscribe7curl -X DELETE https://app.confirmail.io/api/v1/webhooks/WEBHOOK_ID -H "Authorization: Bearer KEY"8 9# latest items of an event (samples / polling)10curl "https://app.confirmail.io/api/v1/samples/verification.completed?limit=3" -H "Authorization: Bearer KEY"

Sign-up form widget

One line before </body> protects every email field of the page, including React and Next.js forms without a form tag. Create the public key under Signup form widget and limit it to your websites.

HTML
1<script src="https://app.confirmail.io/widget.js" data-key="rs_pub_..." defer></script>
data-selectorattributeCSS selector of the email fields (default: email inputs and fields named email).
data-block-submitattribute"false" to only show hints, never block.

Account

GET/v1/account

Returns the account email, the credit balance and the key name and mode. Handy to check a key.

Sandbox

With a test key, @sandbox.test addresses return a fixed result decided by the local part, without credits or network: valid@, invalid@, acceptall@, disposable@, full@, blocked@, timeout@.

Errors and limits

Error body
1{ "error": { "type": "api_error", "code": "insufficient_credits", "message": "…", "param": null } }
401Missing, invalid or revoked API key.
402insufficient_credits: buy a pack or a plan.
403test_key_live_address: a test key used on a real address.
429Rate limited: wait for RateLimit-Reset seconds.

Reason codes

MAILBOX_EXISTSThe mailbox exists
INVALID_SYNTAXNot a valid email format
DOMAIN_NOT_FOUNDThe domain does not exist
NO_MAIL_SERVERThe domain cannot receive email
NULL_MXThe domain refuses all email
UNROUTABLE_MAIL_SERVERMail server is unreachable by design
MAILBOX_NOT_FOUNDThe mailbox does not exist
MAILBOX_DISABLEDThe mailbox is disabled
ACCEPT_ALLCatch-all domain: cannot confirm the mailbox
DISPOSABLE_DOMAINDisposable email provider
MAILBOX_FULLThe mailbox is full
DNS_FAILUREDNS lookup failed
SMTP_UNREACHABLEMail server did not answer
SMTP_TIMEOUTMail server timed out
SMTP_BLOCKEDMail server refused our check
SMTP_TEMPORARY_FAILUREMail server asked to retry later
SMTP_PROTOCOL_ERRORUnreadable mail server answer
NOT_VERIFIEDMailbox check was not performed