Skip to content

API reference

Base URL https://app.emailshield.co/api. Every request needs the header X-API-Key: evf_…. Request bodies are JSON (Content-Type: application/json).

Verifies one address and returns the answer in the response. Waits up to 30 seconds; if there’s no answer by then you get 408 and the credit is refunded. Costs 1 credit.

Body

FieldType
emailstringRequired. The address to verify.
check_smtpbooleanDefault true. Ask the mail server. Leave it on.

Response 200

FieldType
emailstring
statusstringvalid, invalid, or risky (catch-all or disposable)
validboolean
scorenumberConfidence, 0 to 1
reasonstringPlain-English reason, e.g. Mailbox confirmed
detailsobjectSee Reading a result
credits_usedinteger1
credits_remainingintegerPlan credits left (see note below)
processed_atstringISO 8601 time

Submits a list as a background job and returns 202 straight away. Costs 1 credit per unique address, charged now; Unknown results are refunded when the job finishes.

Body

FieldType
emailsstring[]Required. 1 to 50,000 addresses. Duplicates (ignoring case) are removed before charging. Every item must be a syntactically valid address, or the whole call fails with 422.
namestringOptional. The list name shown in the dashboard (up to 255 characters).
webhook_urlstringOptional. HTTPS URL we POST to when the job finishes. See Webhooks.
prioritystringnormal (default), high or urgent.
check_smtpbooleanDefault true.

Response 202

{
"job_id": "3f1c2a4e-…",
"status": "queued",
"total_emails": 2,
"estimated_seconds": 0,
"credits_used": 2,
"credits_remaining": 48997,
"created_at": "2026-10-09T12:01:00Z"
}

estimated_seconds is a rough guess; don’t build timeouts on it.

Job progress and totals. This is the cheap endpoint to poll.

FieldType
job_idstring
statusstringqueued, processing, completed, failed, interrupted or cancelled
terminalbooleantrue when the job has stopped. Stop polling when this is true.
total_emailsinteger
processedintegerAddresses with a final answer so far
progress_percentnumber
verdictsobjectCounts by verdict: valid, invalid, catch_all, risky, role_based, disposable, unknown
bucketsobjectCounts by group: safe_to_send, risky, invalid
created_at, started_at, completed_atstringISO 8601 times
errorstring | nullSet when the job failed

valid_count and invalid_count are also returned for older integrations; use verdicts and buckets instead.

The answers, page by page. Rows appear while the job runs — only final answers are stored — so you can start reading before it finishes.

Query
pageintegerDefault 1
per_pageintegerDefault 100, maximum 1000
{
"job_id": "3f1c2a4e-…",
"status": "completed",
"total": 2,
"page": 1,
"per_page": 100,
"has_more": false,
"results": [
{
"email": "jane.doe@example.com",
"status": "valid",
"valid": true,
"score": 0.95,
"reason": "Mailbox confirmed",
"details": {"primary_label": "valid", "tags": [], "label_reasons": ["Mailbox confirmed"]}
},
{
"email": "info@example.org",
"status": "invalid",
"valid": false,
"score": 0.5,
"reason": "Domain accepts all addresses",
"details": {
"primary_label": "catch_all",
"tags": [{"label": "role", "confidence": 0.8}],
"label_reasons": ["Domain accepts all addresses", "Role-based address"],
"safe_to_send": "risky",
"safe_to_send_score": 22
}
}
]
}

Your recent jobs, newest first.

Query
statusstringOptional filter, e.g. completed
limitintegerDefault 20, maximum 100
offsetintegerDefault 0

Returns {"jobs": [{"job_id", "status", "total_emails", "processed", "progress_percent", "created_at"}], "limit", "offset"}.

The verdict lives in details:

Field
primary_labelvalid, invalid, catch_all, inbox_full, disabled, unknown or not_verified
tagsList of {"label", "confidence"} with label one of spam_trap, disposable, role
label_reasonsPlain-English reasons, e.g. Mailbox confirmed, Domain has no mail server
safe_to_send, safe_to_send_score, safe_to_send_reasonsCatch-all rows only: the send-risk rating

details can carry other fields too; treat anything not listed here as informational and subject to change.

To match the dashboard’s categories, apply tags first, then the label:

If…Dashboard categoryGroup
tags contain spam_trapSpam TrapInvalid
tags contain disposableDisposableInvalid
tags contain roleRoleRisky
primary_label is validValidSafe to send
primary_label is catch_allCatch-AllRisky
primary_label is inbox_fullInbox FullRisky
primary_label is invalid or disabledInvalid / Disabled / No Mail ServerInvalid
primary_label is unknown or not_verifiedUnknown / Not Verified (refunded)Risky

credits, credits_used_today (last 24 hours), credits_used_this_month (last 30 days), renewal_date.

plan, credits, credits_used_today and a few account fields.

status, plan, credits, renewal_date, has_billing, is_trial, trial_expired.

Revokes a key. Returns 204, or 404 if there’s no such key. Keys are created in the app under Profile → API.