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 lifecyclepending 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.