Test mode
API keys that begin with ev_test_ are test-mode keys. They return instant, canned results
without touching DNS or SMTP, cost zero credits, and are designed for integration tests
and CI pipelines.
On this page
How test mode works
The outcome returned depends on the local part of the email address submitted (everything
before + or @, lowercased). Subaddress tags (e.g. invalid+foo@example.com) are
ignored — only the base local part is matched.
The verdict is result.outcome. (Top-level status is the check's lifecycle — pending or
complete — and never carries a verdict.)
| Local part | result.outcome |
result.sub_status |
|---|---|---|
valid (or anything not listed below) |
deliverable |
"" |
invalid |
invalid |
mailbox_not_found |
catch_all |
catch-all |
accept_all |
unknown |
unknown |
no_dns_entries |
disposable |
invalid |
disposable |
role |
deliverable |
role_based |
Examples
valid@any-domain.com → outcome: deliverable, sub_status: ""
invalid@any-domain.com → outcome: invalid, sub_status: mailbox_not_found
catch_all@any-domain.com → outcome: catch-all, sub_status: accept_all
disposable@any-domain.com → outcome: invalid, sub_status: disposable
role@any-domain.com → outcome: deliverable, sub_status: role_based
unknown@any-domain.com → outcome: unknown, sub_status: no_dns_entries
Subaddress tagging lets you exercise multiple outcomes in the same test without changing the recipient domain:
valid+01@example.com → deliverable
invalid+01@example.com → invalid
Batch test mode
A ev_test_ key works on POST /api/v1/verify/batch exactly like a live key, but the job
runs for free (charged: 0), skips DNS and SMTP entirely, and completes within seconds. Each
row's outcome is derived from the same local-part convention as single verify (everything
before + or @, lowercased) — the values are canned, produced without running the live
validation pipeline, so a test batch matches single verify exactly. The result file columns
are Outcome and Risk:
| Local part | Outcome |
Risk |
Flags |
|---|---|---|---|
valid (or anything not listed) |
deliverable |
none |
— |
role |
deliverable |
medium |
role |
catch_all |
catch-all |
medium |
catch-all |
invalid |
invalid |
high |
— |
disposable |
invalid |
high |
disposable |
unknown |
unknown |
low |
— |
Test batches are capped at 1,000 valid rows. A file over the cap returns
400 with { "code": "too_many_rows" } — no job is created and no credits are touched.
(too_many_rows is the machine-readable code; error carries human-facing prose. Branch on
code, never on error — see Errors.)
Upload and download a test batch
Upload a CSV with a test key, poll for completion, then download the (real, pre-signed) result file:
# 1. Upload — returns { "job_id": "...", "charged": 0, "status": "processing" }
curl -X POST https://api.emailvalidator.ai/api/v1/verify/batch \
-H "X-Api-Key: ev_test_your_key" \
-F "file=@emails.csv"
# 2. Poll until status is "complete" — the response then carries csv_url / json_url
curl https://api.emailvalidator.ai/api/v1/verify/batch/7a4e2c1b-... \
-H "X-Api-Key: ev_test_your_key"
# 3. Download the result CSV from the pre-signed URL
curl -o results.csv "https://storage.example.com/results/...?X-Amz-Expires=..."
Supply a callback_url on the upload to receive a real signed batch.completed webhook with
the pre-signed download URLs — the same shape a live batch delivers — so you can test your
upload → await webhook → download → parse loop end to end.
Test batches cost zero credits and do not affect your member dashboard lifetime stats (Emails validated / Bounces avoided).
Full endpoint support
Test-mode keys work with all endpoints — single verify, batch, webhooks, and SSE — so you can run a full end-to-end integration test without spending credits or waiting for real SMTP probes.
Test and live data never mix
A test-mode key can read only test-mode resources, and a live key only live ones. The listings
(GET /api/v1/verify, GET /api/v1/verify/batch) return just your key's own mode, and fetching
another mode's id by hand answers 404 not_found — with no pre-signed download URL, and nothing
in the body confirming the id exists.
That is the guarantee that makes an ev_test_ key safe to leave in CI: it cannot list your real
verifications, and it cannot download a real result file. It also works the other way — a live
listing never has canned sandbox verdicts mixed into it.
Every verification and batch job carries a livemode boolean (true = live, false =
sandbox), so a response you stored or logged says for itself which mode produced it.
Switching between test and live mode
Use a ev_test_ key in your CI environment and a live ev_ key in production. There is
no other configuration change required — the same request shape works for both.
Resources do not carry over: a job you created with the test key is not visible to the live key, and vice versa. Ids are per-mode.