Every APIVerve endpoint speaks the same protocol: one header for auth, query parameters or a JSON body for input, and a three-key envelope on the way back. There is no per-API SDK to learn, no OAuth dance, and no per-endpoint quirk to memorise — which means the four minutes you spend on this page are the only four minutes you spend learning the platform. Everything after this is picking an endpoint.
The samples on this page already contain your real API key. Copy any of them and they will run as-is.
Before you begin
You need an HTTP client and nothing else. Every example below appears in curl, JavaScript, Python and PHP, and all four are the same HTTP request written four ways — pick whichever you read fastest. No prior experience with APIVerve is assumed, and no library is required at any point.
Get your API key
Create an account at dashboard.apiverve.com, open API keys, and click Reveal on your default key to copy it. Signup takes under two minutes, needs no card, and the key is generated the moment the account exists — there is no provisioning wait and no approval step.
A key is a plain string you send in a header. It identifies your account, meters your usage and carries your plan's limits, so treat it like a password: keep it server-side, and never commit it or ship it in browser JavaScript.
Store it in an environment variable rather than in source:
export APIVERVE_API_KEY="your-key-here"const key = process.env.APIVERVE_API_KEY;
if (!key) throw new Error('APIVERVE_API_KEY is not set');That guard is worth writing on day one. An undefined environment variable does not
produce a clean 401 — it produces a request with a malformed key, which the edge
rejects with an HTML 403 that your JSON parser will choke on. See
errors for why that failure looks so unlike the others.
Proxy the request through your own backend, or issue a scoped sub-key limited to the endpoints and origins you expect. Anything shipped to a client is public, however well minified.
Make your first request
Send the key in the x-api-key header. That is the only auth step, on every endpoint.
Inputs go in the query string for GET endpoints and in a JSON body for POST
endpoints.
curl 'https://api.apiverve.com/v1/emailvalidator?email=hi@example.com' \
-H "x-api-key: $APIVERVE_API_KEY"const res = await fetch(
'https://api.apiverve.com/v1/emailvalidator?email=hi@example.com',
{ headers: { 'x-api-key': process.env.APIVERVE_API_KEY } },
);
const body = await res.json();
console.log(body.data);import os, requests
res = requests.get(
"https://api.apiverve.com/v1/emailvalidator",
params={"email": "hi@example.com"},
headers={"x-api-key": os.environ["APIVERVE_API_KEY"]},
timeout=15,
)
print(res.json()["data"])<?php
$ch = curl_init('https://api.apiverve.com/v1/emailvalidator?email=hi@example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['x-api-key: ' . getenv('APIVERVE_API_KEY')]);
$body = json_decode(curl_exec($ch), true);
print_r($body['data']);The endpoint used here takes one parameter. Others take more:
| Parameter | Type | Description | |
|---|---|---|---|
email | string | Required | The address to validate. Must include a domain. |
deep | boolean | Optional | Perform an SMTP-level mailbox check. Costs one extra credit. |
timeout | integer | Optional | Milliseconds to wait before giving up. Defaults to 5000. |
Every endpoint's reference page carries the same table, generated from the schema the API actually validates against, so there is no hand-written copy to drift out of date.
The example on the right is live. Switch languages at the top of the panel and the choice follows you across every page in the docs.
Read the response
Every endpoint returns the same three top-level keys, so one response handler covers your whole integration:
{
"status": "ok",
"error": null,
"data": {
"valid": true,
"disposable": false,
"mx": true
}
}status—"ok"on success,"error"otherwise.error—nullon success, or a human-readable sentence explaining what to fix.data— the endpoint's payload. Shape varies per endpoint; everything else does not.
Check status rather than testing data for emptiness. A lookup that legitimately found
nothing is still a successful call: status stays "ok" and data carries the empty
result. That is an answer, not a failure, and it costs the same credit either way.
Fields marked premium in the reference are absent rather than
zeroed when your plan does not include them, so test for presence instead of comparing to
0. A fraud score of 0 means "definitely safe" — exactly the wrong thing to invent for
a field you are not receiving.
Other formats
JSON is the default. The same envelope is available as XML, YAML, CSV or Markdown through
the Accept header, which is occasionally useful for pasting a result into a config file
or an LLM prompt:
curl 'https://api.apiverve.com/v1/emailvalidator?email=hi@example.com' \
-H "x-api-key: $APIVERVE_API_KEY" \
-H 'Accept: text/markdown'The exact header values are in response format.
Handling failures
Read the HTTP status first to decide what kind of problem it is, then error for the
specific reason. The sentence names the parameter — it is not a code you have to look up.
{
"status": "error",
"error": "The 'email' parameter is required.",
"data": null
}| Status | Meaning | What to do |
|---|---|---|
400 | Input was rejected | Read error; it names the parameter. |
401 | Key is missing or invalid | Check the header name and the key value. |
403 | Key is valid but not allowed to make this call | Check scoping, IP allow-list, or whether the key was revoked. |
404 | No such endpoint on this door | Check the path, and that your plan includes it. |
429 | Rate limited, or out of credits | Back off; see rate limits. |
5xx | Our side failed | Retry with backoff. |
403 is not an authentication failure — 401 is the only status that means "we do not
accept this key". And 429 is two different problems wearing one number: read
x-api-remaining-credits from the response. Zero means the month is spent and retrying
cannot help; anything higher means slow down and try again.
Go to production
Three things separate a working call from a reliable integration.
Retry the right statuses. Back off on 429 and 5xx. Never retry a 400, 401,
403 or 404 unchanged — nothing about the next attempt will be different, and repeated
identical failures earn their own throttle at the edge.
async function withRetry(fn, tries = 3) {
for (let i = 0; i < tries; i++) {
try {
return await fn();
} catch (err) {
if (!err.retryable || i === tries - 1) throw err;
const wait = 2 ** i * 500 + Math.random() * 250; // jitter, so a fleet doesn't sync up
await new Promise((r) => setTimeout(r, wait));
}
}
}Read fields defensively. Premium fields are absent on plans that do not include them, and new fields get added over time. Code that assumes an exact response shape breaks on both.
Separate your environments. Use a different key per environment — a scoped sub-key for staging keeps a runaway test loop from spending production credits, and it makes the usage graph in analytics mean something. Rotating one key does not disturb the others; see key rotation.
Watch your usage
Every response carries your remaining balance in x-api-remaining-credits, so you can log
or alert on it without a second call. The dashboard shows the same
number over time, broken down per endpoint, which is usually how a runaway retry loop gets
noticed.
Next
The patterns on this page apply unchanged to every endpoint in the catalog, so the useful next step is picking one. All endpoints is the full list. Making requests covers uploads, timeouts, concurrency and caching, and the SDKs wrap all of it if you would rather not hand-write HTTP.
If you are replacing an integration that already exists somewhere else, migrations covers the cutover — what changes in your code, and how to prove the new answers match the old ones before anything depends on them.