A REST API and a remote MCP server for ZenVerifier. Same credits, same results and the same 30-day rules as the dashboard, with keys scoped to exactly what they need.
Base URL https://www.zenverifier.com/api/v1. JSON in, JSON out, HTTPS only.
Create a key. In the dashboard, open API & MCP in the sidebar and create a key. Owners and admins can do this. The Server integration — verify + lists preset covers everything below. The key is shown once, so put it straight into your secret store.
Every request carries an API key in the Authorization header:
header
Authorization: Bearer zv_live_YOUR_KEY
A key belongs to one workspace and sees only that workspace’s lists, history and credits.
Keys start with zv_live_ and are shown once, when created. We store only a SHA-256 hash, so a lost key can’t be recovered: roll it or create a new one.
Send keys only in the Authorization header, never in a URL or query string. The API has no CORS support on purpose: call it from your servers, not from a browser.
If the person who created a key leaves the workspace, the key stops working.
Owners and admins get an email whenever a key is created, rolled or revoked. The email shows the key’s prefix (zv_live_ab12), never the key.
Scopes
A key can only do what its scopes allow. read:* covers every …:read scope and * covers everything. Write scopes don’t include the matching read scope.
Scope
Allows
account:read
Read workspace plan and credit balance
verify:write
Verify single emails (spends credits)
verifications:read
Read single-verification history
lists:read
Read bulk lists, status and results
lists:write
Create bulk lists (spends credits)
mcp:access
Connect AI agents over MCP (tools still limited by the other scopes)
read:*
Read everything
*
Full access
Presets
The dashboard creates keys from these presets. The first one is the default. The last column shows which MCP tools a key made from the preset can use.
Keys expire never, or after 30, 90 or 365 days. Owners and admins get an email 7 days before a key expires.
Roll issues a new key with the same name, scopes and expiry. The old key keeps working for 24 more hours and then stops, so you can swap keys without downtime.
Revoke stops a key immediately, including a rolled key that’s still in its 24-hour grace period.
Billing
Credits & caching
The API and MCP spend the same credits as the dashboard, under the same rules.
Single checks
POST /api/v1/verify · MCP verify_email, verify_emails
Checking the same address again in the same workspace within 30 days is free: you get the stored result back with charged: 0.
Otherwise it costs 1 credit, including when we answer from our shared cache of recent results (cached: true, charged: 1).
The credit is reserved before the check runs. If the check can’t complete (engine_unavailable), it’s refunded.
If a check would cost a credit and your balance is empty, you get 402 insufficient_credits and nothing runs.
Bulk lists
POST /api/v1/lists · MCP create_list
1 credit per unique email. Duplicates are removed first and aren’t charged.
Credits are reserved when the list is submitted. If your balance can’t cover the whole list, you get 402 and no list is created.
If the list can’t start, the reservation is refunded.
Emails answered from the shared cache still count. The free 30-day re-check applies to single checks only.
Single objects come back as { "data": … }. Collections are paginated by page number and add a pagination object. Every response carries Cache-Control: no-store. Responses to authenticated requests also carry the rate-limit headers (401 and 403 don’t).
planSource says where the plan comes from: direct (paid to ZenVerifier, or the free plan), outboundpass (included with an OutboundPass membership) or outboundpass_revoked (the membership ended and the workspace moved to the free plan).
POST/api/v1/verify
scope · verify:writespends credits
Verify one email address and wait for the answer. Costs 1 credit, or nothing if this workspace checked the same address in the last 30 days.
Body field
Type
Description
email
string
Required. The address to check. Trimmed and lower-cased first.
Start a bulk verification. Send JSON with an array of emails, or upload a file as multipart form data and we pick out every email address in it. Addresses are trimmed, lower-cased and de-duplicated, up to 50,000 unique emails per list. 1 credit per unique email is reserved when the list is submitted. Returns 201 straight away; the list runs in the background.
Body field
Type
Description
emails
string[]
JSON body. Required unless you send a file.
file
file
Multipart form data. A CSV or plain-text file. Required unless you send emails.
name
string
Optional label shown in the dashboard.
Header
Description
Idempotency-Key
Optional, 1–255 characters. Makes retries safe. See Idempotency.
Status, progress and result counts for one list. While a list is running, each read fetches fresh progress at most every 15 seconds, so poll every 15–30 seconds.
partial is true when part of the results couldn’t be loaded on this request. Retry the request rather than treating those rows as the complete list. If it stays true across retries, that part is no longer available. Contact support.
GET/api/v1/lists/:id/download
scope · lists:read
The results of a finished list as a CSV attachment, the same files the dashboard offers. Columns: email,result,quality,subresult,free,role,didyoumean.
Query parameter
Type
Description
filter
string
ok (deliverable only) · ok_and_catch_all (default) · unknown · invalid · all (every row).
Emails answered from recent results instead of fresh checks.
creditsCharged
integer
Credits charged for this list.
error
string | null
Why the list failed, when status is failed.
createdAt
ISO 8601
When the list was submitted.
finishedAt
ISO 8601 | null
When it finished.
expiresAt
ISO 8601
When the list and its results are deleted (createdAt + 30 days).
Reference
Result values
Every verification and every list row has one result. List counts use the same five buckets (catch_all is catchAll there).
result
Meaning
ok
Deliverable. The mailbox exists and accepts mail.
catch_all
The domain accepts mail for any address, so this mailbox can’t be confirmed. Send with care.
invalid
The address doesn’t exist or can’t receive mail. Remove it.
disposable
A throwaway or temporary inbox provider.
unknown
No definitive answer this time, usually a slow or greylisting mail server.
Guide
Bulk lists
Lists run in the background. Up to 50,000 unique emails per list over the API (5,000 over MCP); split anything bigger.
Submit with POST /api/v1/lists, as JSON or a file upload. Send an Idempotency-Key so a retry can’t create (and charge for) the list twice. You get the list back with status: "queued".
PollGET /api/v1/lists/:id every 15–30 seconds until status is finished (or failed, with the reason in error). progress goes from 0 to 100.
Collect the rows as JSON from /results (filter by result, paginate) or as a CSV from /download.
Lists made over the API or MCP show up in the dashboard too, and createdVia tells you where each one came from. Results are deleted 30 days after the list was created, so collect them before expiresAt.
Reference
Errors
Errors use standard HTTP status codes and one JSON shape: { "error": code, "message": text, "field"?: name }, sometimes with extra fields (for example balance). Branch on error. message is written for people and may change.
A parameter failed validation. field names the parameter.
401
unauthorized
Missing or malformed Authorization header, or the key is invalid, expired or revoked.
402
insufficient_credits
Not enough credits. The body adds balance and needed (bulk lists also missing). Nothing was charged.
403
forbidden
The key doesn’t have the scope this endpoint needs. The message names it.
404
not_found
No such list or verification in this key’s workspace.
409
list_not_finished
The list is still running. Poll GET /api/v1/lists/:id until status is finished.
409
no_results
The list finished but there are no results to return.
409
idempotency_in_progress
A request with this Idempotency-Key is still running. Retry shortly.
413
payload_too_large
More than 50,000 unique emails in one list. Split it.
422
idempotency_key_reused
This Idempotency-Key was already used with a different request body.
429
rate_limited
Over the per-minute limit for this key. Wait for Retry-After.
500
internal_error
Something unexpected went wrong on our side. Safe to retry.
502
engine_unavailable
The verification engine couldn’t be reached. Any credits reserved for the request are refunded. Retry shortly.
Limits
Rate limits
Each key gets 120 requests per minute by default, counted in fixed one-minute windows. MCP tool calls count against the same budget, one request per call, except verify_emails, which counts one per distinct address. Over the limit, the API answers 429 rate_limited and MCP tools return a rate_limited error. Wait Retry-After seconds, then carry on.
Header
Meaning
X-RateLimit-Limit
Requests allowed per minute for this key.
X-RateLimit-Remaining
Requests left in the current minute.
X-RateLimit-Reset
When the window resets, as a Unix timestamp in seconds.
POST /api/v1/lists spends credits, so retries need care. Send an Idempotency-Key header: 1–255 characters, one per list you mean to create (a UUID works).
Same key and same body after the first request finished: you get the original response again, with Idempotent-Replayed: true. No second list, no second charge.
Same key while the first request is still running: 409 idempotency_in_progress.
Same key with a different body: 422 idempotency_key_reused.
If the first request failed with an error, the key is released and you can retry with it.
Keys are remembered for 24 hours.
Over MCP, create_list takes the same thing as its idempotency_key argument.
Single checks don’t need a key: re-checking an address within 30 days is free.
AI agents
MCP server
ZenVerifier runs a remote Model Context Protocol server, so Claude, Cursor and other MCP clients can check addresses and run lists for you, using the same API keys, credits and rate limits.
Endpoint
https://www.zenverifier.com/api/mcp
Transport
Streamable HTTP, stateless, JSON responses. POST only.
Auth
Authorization: Bearer zv_live_… with the mcp:access scope. Use an “AI agent (MCP)” preset.
The quickest route: in the dashboard, API & MCP → Generate key & copy config creates a key and copies your client’s config with the key filled in. To set it up by hand, replace zv_live_YOUR_KEY below with your key.
mcp:access lets a key connect; its other scopes decide which tools it sees. A read-only agent key can look up lists and history but can’t spend credits. Tool errors come back as tool results with isError: true and the same codes as the REST API.
Tool
Scope
Arguments
What it does
get_account
account:read
none
Get account. Workspace name, plan, where the plan comes from (planSource) and current credit balance.
verify_emailspends credits
verify:write
email
Verify one email. Verify a single email address. Costs 1 credit unless this workspace checked the same address in the last 30 days (then free).
verify_emailsspends credits
verify:write
emails (1–10)
Verify up to 10 emails. Verify up to 10 email addresses in one call. Same pricing as verify_email, per address; each distinct address also counts as one request against the rate limit. For more, use create_list.
Create bulk list. Start a bulk verification for up to 5,000 emails. Reserves 1 credit per unique email up front. Runs asynchronously: poll get_list until status is finished, then read get_list_results.
list_lists
lists:read
status?, page?, page_size?
List bulk lists. Bulk lists in this workspace, newest first, with status and result counts.
get_list
lists:read
list_id
Get list status. Status, progress and result counts for one bulk list.
Get list results. Per-email results of a finished list, filterable by result (ok, catch_all, invalid, disposable, unknown), paginated.
The first time a key makes an MCP call, owners and admins get an email. Every call is logged (tool, client, status, duration) and the latest ones show under API & MCP in the dashboard. Call logs are kept for 90 days.
Give each client its own key, so you can revoke one without breaking the others. Only paste keys into clients you trust.
Privacy
Data retention
Bulk lists and their results are deleted 30 days after the list was created. Every list carries expiresAt; after that it returns 404 not_found.
API keys are stored only as hashes. The full key is never logged and never emailed.