Email Verifier REST API Reference
Base URL (production):
https://email-verifier-v61-production-gateway.emaily.workers.devAll /v1/* endpoints require authentication with an API key:
Authorization: Bearer ev_live_<your-api-key>Auth before routing: requests under/v1/*are authenticated before path matching, so an invalid or missing key yields401even for unknown or malformed paths (e.g./v1//returns401, not404).
Response conventions
- Every response carries tracing headers:
X-Request-Id— correlates a request with its structured log events.X-Response-Time— request duration in milliseconds.- Paid endpoints include a
billingobject and quota headers. - Errors return JSON with an
errorcode andmessage. Client code should branch on theerrorcode, not the HTTP status alone. - Reaching a rate limit or monthly quota returns HTTP 429 with a
Retry-Afterheader (andretry_after_secondsin the body).
Common error codes
| HTTP | error | Meaning |
|---|---|---|
| 400 | invalid_json | Request body is not valid JSON. |
| 400 | invalid_request | Request body is not a JSON object. |
| 400 | invalid_email | email is not a string in the expected length range. |
| 400 | invalid_dkim_selectors | Too many / too long DKIM selectors (max 8, each ≤ 63 chars). |
| 400 | invalid_query_parameter | A boolean query param was not true/false/1/0/yes/no. |
| 400 | invalid_domain | Invalid domain (too short/long or bad encoding). |
| 401 | unauthorized | Missing/invalid Authorization header. |
| 404 | not_found | Unknown REST endpoint. |
| 405 | method_not_allowed | Wrong HTTP method for the path (Allow header set). |
| 429 | rate_limit_exceeded | Per-key rate limit (scope: minute, day, credits_minute, credits_day). |
| 429 | monthly_quota_exceeded | Monthly credit quota exhausted (upgrade_required: true). |
| 409 | batch_not_cancellable | Batch already in a terminal state. |
| 409 | export_not_ready | Export not yet assembled. |
| 500 | service_misconfigured | A required service component is missing or misconfigured. |
| 500 | internal_error | Unhandled failure. |
Endpoints
GET /health — service status (no auth)
curl https://email-verifier-v61-production-gateway.emaily.workers.dev/health{
"status": "ok",
"version": "6.1.0",
"environment": "production",
"checks": { "core": "ok" }
}Returns 503 with status: "degraded" if a required core dependency is unavailable.
GET /v1/capabilities — capability declaration (free)
curl -H "Authorization: Bearer ev_live_..." \
https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/capabilitiesReturns the service version, the list of MCP tools, REST endpoints, the available plan mapping, and explicit can_check / cannot_check_without_smtp_or_external_reputation_data lists. Use this at runtime to discover what the service can and cannot do.
GET /v1/usage — quota status (free)
curl -H "Authorization: Bearer ev_live_..." \
https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/usage{
"account": "you@example.com",
"plan": "developer",
"period": "2026-08",
"used": 0,
"limit": 10000,
"remaining": 10000,
"reserved": 0
}POST /v1/syntax — syntax only (free)
Walks no network; pure local parse + normalization.
curl -X POST https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/syntax \
-H "Authorization: Bearer ev_live_..." -H "Content-Type: application/json" \
-d '{"email":"alice@example.com"}'Body:
email(string, 1–254 chars). Required.
Returns { email, valid, normalized, local, domain, ...flags, billing }.
POST /v1/verify — verify one email (1 credit)
curl -X POST https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/verify \
-H "Authorization: Bearer ev_live_..." -H "Content-Type: application/json" \
-d '{"email":"alice@example.com","include_policy_checks":true}'Body:
email(string, 3–254 chars). Required.include_policy_checks(boolean, optional, defaulttrue). Also query SPF and DMARC. Disable for fewer DNS requests (false).
Returns the full verification result (see Verification result schema below) plus a billing object.
POST /v1/verify-batch — verify up to 10 (N credits)
curl -X POST https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/verify-batch \
-H "Authorization: Bearer ev_live_..." -H "Content-Type: application/json" \
-d '{"emails":["alice@example.com","admin@example.org"],"include_policy_checks":false}'Body:
emails(array of strings, 1–10 items, each 3–254 chars). Required.include_policy_checks(boolean, optional, defaultfalse).
Policy checks are limited to 3 addresses per batch for Workers-Free subrequest safety. Returns { summary, results, billing }.
GET /v1/domain/:domain — deep domain inspection (1 credit)
curl "https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/domain/example.com?try_common_dkim_selectors=true&fetch_mta_sts_policy=true" \
-H "Authorization: Bearer ev_live_..."Query parameters (all optional):
dkim_selectors— comma-separated selectors (max 8, each ≤ 63 chars).try_common_dkim_selectors— boolean (true/false/1/0/yes/no).fetch_mta_sts_policy— boolean; fetch the standards-defined MTA-STS policy file.
Returns MX/SPF/DMARC/MTA-STS/TLS-RPT/DANE/DKIM/BIMI analysis plus a billing object.
Async batches
POST /v1/batches — submit a batch (N credits)
curl -X POST https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/batches \
-H "Authorization: Bearer ev_live_..." -H "Content-Type: application/json" \
-d '{"emails":["alice@example.com","bob@example.org"]}'Body:
emails(array of strings, 3–254 chars each). Required.include_policy_checks(boolean, optional, defaultfalse).
Optional header:
Idempotency-Key— replaying the same key returns the samebatch_id; concurrent replays are safe (exactly one submission wins; losers get503withretryable: trueand nobatch_id).
Returns 202 with:
batch_idemail_count,total_creditschunk_size(dynamic chunking, bounded for Workers-Free subrequest safety)billing(credits reserved, plan usage).
GET /v1/batches?limit=N — list batches (free)
curl -H "Authorization: Bearer ev_live_..." \
"https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/batches?limit=20"limit 1–100, default 20. Returns the account's recent batches, newest first, each with status, chunk progress, email count, charged credits, and creation time.
GET /v1/batches/:id — batch status (free)
curl -H "Authorization: Bearer ev_live_..." \
https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/batches/<batch_id>Includes status, progress (total_chunks, completed_chunks), counts, billing (reserved_credits, charged_credits), and results.export_ready.
GET /v1/batches/:id/results — stream results
curl -H "Authorization: Bearer ev_live_..." \
https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/batches/<batch_id>/resultsStreams unique results once the batch is terminal.
GET /v1/batches/:id/export — combined export file
curl -OJ -H "Authorization: Bearer ev_live_..." \
https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/batches/<batch_id>/exportStreams the assembled export.json (all unique results in one file) once results.export_ready is true. Returns 409 export_not_ready while assembly is still in progress.
POST /v1/batches/:id/cancel — cancel a running batch
curl -X POST -H "Authorization: Bearer ev_live_..." \
https://email-verifier-v61-production-gateway.emaily.workers.dev/v1/batches/<batch_id>/cancelMarks unfinished chunks dead_letter (CANCELLED_BY_CUSTOMER), sets the job to cancelled (terminal), settles consumed credits, releases the rest, and deletes the batch input data from storage. Finished chunks stay readable until expiry. Returns 409 batch_not_cancellable for terminal batches.
Batch terminal states: completed, partially_completed, failed, cancelled, expired.
Verification result schema
The verify_email / verify_emails endpoints and the equivalent MCP tools share this shape:
| Field | Type | Notes |
|---|---|---|
email | string | Address as supplied. |
normalized_email | string | null | Local-part normalized + punycode domain. |
verdict | string | domain_deliverable | risky | invalid | unknown. |
confidence | string | high | medium | low. |
score | number | 0–1 heuristic score. |
risk_flags | string[] | e.g. disposable, role_account, no_reply, free_provider, typo_domain. |
checks | object | syntax_valid, domain, domain_dns_exists, mx_found, mx_count, null_mx, implicit_mx_fallback, spf_found, spf_valid, dmarc_found, dmarc_valid, dmarc_policy, disposable, role_account, no_reply_account, … |
suggested_correction | string | null | When a common domain typo is detected. |
billing | object | plan, credits_charged, period, used, reserved, remaining. |
Verdict meanings:
domain_deliverable— syntax pass + MX (or implicit A/AAAA) present; the domain accepts mail.risky— deliverable at the domain level but with risk flags (disposable, role, free provider, weak/no auth, typo suspicion).invalid— syntax failure, no MX, null MX, or a hard disqualifier.unknown— verdict could not be determined (always the case for mailbox existence and catch-all behavior, which cannot be verified without SMTP).
Plans & limits
Credits and request limits are enforced per API key.
| Plan | Monthly credits | Requests/min | Requests/day | Credits/min | Credits/day |
|---|---|---|---|---|---|
| free | 500 | 30 | 25 | 60 | 50 |
| developer | 10,000 | 300 | 300 | 600 | 700 |
| pro | 50,000 | 1,500 | 1,200 | 2,500 | 3,000 |
| agency | 250,000 | 15,000 | 6,000 | 5,000 | 12,000 |
Monthly credit usage resets on a calendar month (UTC) boundary. All limits surface as HTTP 429 — always read the error code and scope from the body to tell them apart.