REST API
Complete EmailVerify Pro REST API guide: authentication, single and bulk email verification, catch-all resolution, email finder, suppression lists, and webhooks across 152 endpoints.
View as Markdown →The REST API is the foundation — the CLI, the SDKs and the MCP server are all thin wrappers over it. Base URL:
https://emailverifypro.com
All responses are JSON. All requests that send a body use Content-Type: application/json. There are 152 endpoints; this page covers the ones almost everybody uses. The full reference lists the rest, and https://emailverifypro.com/openapi.json is the machine-readable spec.
Authentication
Pass your key in the X-API-Key header:
curl -H "X-API-Key: evp_your_key" "https://emailverifypro.com/validate?email=a@example.com"
Or as a query parameter, where headers are awkward:
curl "https://emailverifypro.com/validate?email=a@example.com&api_key=evp_your_key"
Warning. A key in a query string ends up in browser history, proxy logs and server access logs. Prefer the header.
Requests without a key still work and are rate limited by IP. A key raises your limits and attributes usage to your account. See API keys.
Verify a single address
GET /validate
The workhorse. Every signal layer, one address.
curl -H "X-API-Key: evp_your_key" \
"https://emailverifypro.com/validate?email=someone@example.com"
| Parameter | Type | Default | Purpose |
|---|---|---|---|
email | string | required | The address to verify |
smtp | bool | true | Perform the live SMTP probe. Turning this off is much faster but far less accurate |
rbl | bool | true | Check the MX IP against blacklists |
gravatar | bool | true | Look for a Gravatar as a signal the address is real |
breach | bool | false | Check breach databases — strong evidence an address existed |
web_presence | bool | true | Look for the address on the domain's website |
domain_age | bool | true | Domain registration age; very new domains are riskier |
enrich | bool | false | Add the ML prediction and an activity score |
suppression | bool | true | Check your suppression list first |
POST /validate
Same thing with a JSON body — use it when the address may contain characters awkward in a URL.
curl -X POST https://emailverifypro.com/validate \
-H "X-API-Key: evp_your_key" \
-H "Content-Type: application/json" \
-d '{"email":"someone@example.com","breach":true,"enrich":true}'
The response
{
"email": "someone@example.com",
"status": "valid",
"sub_status": "mailbox_verified",
"confidence_score": 99,
"deliverability": "deliverable",
"deliverability_score": {
"score": 96,
"grade": "A+",
"band": "excellent",
"can_send": true,
"recommendation": "Send",
"primary_risk": null,
"email_type": "personal",
"breakdown": {
"mx_found": 10,
"smtp_valid": 25,
"corporate_domain": 5,
"name_pattern": 5
}
},
"account": "someone",
"domain": "example.com",
"mx_found": true,
"mx_records": ["aspmx.l.google.com"],
"smtp_provider": "google",
"smtp_response_code": "250",
"catch_all": false,
"is_disposable": false,
"is_role": false,
"is_free": false,
"did_you_mean": null
}
| Field | Why you care |
|---|---|
deliverability_score.can_send | The decision. Boolean, already weighs every signal |
deliverability_score.score | 0–100, if you want your own threshold |
status | Raw SMTP verdict: valid, invalid, accept_all, unknown |
sub_status | Why — e.g. mailbox_verified, mailbox_not_found, catch_all_address |
catch_all | The domain accepts everything; per-address proof is impossible |
is_disposable | Temporary/burner provider |
is_role | support@, info@, sales@ — real, but not a person |
did_you_mean | Typo suggestion, e.g. gmial.com → gmail.com |
Verify many addresses
POST /validate/bulk — synchronous, up to 100
curl -X POST https://emailverifypro.com/validate/bulk \
-H "X-API-Key: evp_your_key" \
-H "Content-Type: application/json" \
-d '{
"emails": ["a@example.com", "b@example.com"],
"deduplicate": true,
"check_suppression": true,
"max_concurrent": 10
}'
{
"total": 2,
"processing_time_ms": 8652,
"summary": {"valid": 1, "invalid": 1},
"results": [
{"email": "a@example.com", "status": "valid", "confidence_score": 95},
{"email": "b@example.com", "status": "invalid", "sub_status": "mailbox_not_found"}
]
}
The whole call blocks until every address finishes, so it takes as long as the slowest one. For more than about 25 addresses, prefer the async endpoint.
POST /validate/bulk/async — a job you poll
curl -X POST https://emailverifypro.com/validate/bulk/async \
-H "X-API-Key: evp_your_key" \
-H "Content-Type: application/json" \
-d '{"emails": ["a@example.com", "b@example.com"]}'
{"job_id": "job_a1b2c3", "status": "queued", "total": 2}
curl -H "X-API-Key: evp_your_key" https://emailverifypro.com/jobs/job_a1b2c3
Poll every few seconds until status is completed, then read results. GET /jobs/{job_id}/dead-letter lists addresses that failed permanently, and POST /jobs/{job_id}/retry-dead-letter re-queues them.
POST /validate/bulk/turbo
Same shape as /validate/bulk, tuned for throughput over per-address depth. Use it when you are cleaning a very large list and can accept slightly lower confidence.
Faster, cheaper checks
| Endpoint | Cost | Use when |
|---|---|---|
GET /validate/syntax | free, instant | Form validation — is it even a well-formed address? |
GET /validate/quick | fast | DNS and MX only, no SMTP probe |
GET /validate/fast | fast | Cached result if present, otherwise a shallow check |
GET /validate | full | You are about to send mail to this address |
curl "https://emailverifypro.com/validate/syntax?email=not-an-email"
{"email": "not-an-email", "valid": false, "normalized": "", "did_you_mean": null}
Catch-all domains
A catch-all domain accepts mail for every address, so no verifier on earth can prove a specific mailbox exists there over SMTP. When status is accept_all, resolve it with additional signals:
curl -X POST https://emailverifypro.com/resolve-catchall \
-H "X-API-Key: evp_your_key" \
-H "Content-Type: application/json" \
-d '{"email":"jane@catchall-example.com"}'
This runs a nine-signal pipeline — Microsoft credential probing, LinkedIn presence, breach records, Gravatar, domain cohort behaviour and more — and returns a resolved verdict where it can.
Warning. Treat accept_all as its own risk tier, not as a pass or a fail. Roughly a quarter of business domains are catch-all.
Finding an address
curl -X POST https://emailverifypro.com/find-email \
-H "X-API-Key: evp_your_key" \
-H "Content-Type: application/json" \
-d '{"domain":"example.com","first_name":"Jane","last_name":"Doe"}'
Detects the domain's naming convention (first.last@, flast@, first@) from known addresses, then constructs and verifies the most likely candidates.
Related: GET /domain-formats/{domain} returns the learned pattern on its own.
Suppression list
Stop sending to addresses that bounced, complained or unsubscribed.
curl -X POST https://emailverifypro.com/suppression/add \
-H "X-API-Key: evp_your_key" \
-H "Content-Type: application/json" \
-d '{"email":"unsubscribed@example.com","reason":"unsubscribe"}'
curl -H "X-API-Key: evp_your_key" \
"https://emailverifypro.com/suppression/check?email=unsubscribed@example.com"
With check_suppression: true (the default), bulk verification skips suppressed addresses automatically.
Feedback improves accuracy
Report real outcomes and the model learns from them:
curl -X POST https://emailverifypro.com/bounce \
-H "Content-Type: application/json" \
-d '{"email":"bounced@example.com","bounce_type":"hard"}'
curl -X POST https://emailverifypro.com/delivered \
-H "Content-Type: application/json" \
-d '{"email":"delivered@example.com"}'
Your ESP can post these directly — there are ready-made receivers at /webhooks/sendgrid, /webhooks/ses, /webhooks/postmark and /webhooks/mailchimp.
Account and usage
curl -H "X-API-Key: evp_your_key" https://emailverifypro.com/me/usage # quota remaining
curl -H "X-API-Key: evp_your_key" https://emailverifypro.com/me/stats # verification statistics
curl -H "X-API-Key: evp_your_key" https://emailverifypro.com/me/recent-verifications
Errors
{"detail": "Invalid or revoked API key"}
| Code | Meaning | Do this |
|---|---|---|
200 | Success | — |
401 | Key missing, invalid or revoked | Check the key. If you just created it, wait up to 2 minutes |
404 | No such resource, or it belongs to another account | — |
422 | Invalid parameters | The body names the offending field |
429 | Rate limited | Back off and retry; the SDKs do this automatically |
500 | Server error | Retry once |
Full detail in errors and limits.
Machine-readable specs
| OpenAPI 3.1 | https://emailverifypro.com/openapi.json |
| Interactive explorer | https://emailverifypro.com/docs |
| Tooling manifest | https://emailverifypro.com/tooling |
| These docs as Markdown | https://emailverifypro.com/llms-full.txt |
Generate a client for any language straight from the spec:
npx @openapitools/openapi-generator-cli generate \
-i https://emailverifypro.com/openapi.json -g go -o ./emailverify-go