API documentation
Check email addresses, phone numbers and IP addresses with one REST API. Every response is JSON, every check returns a valid flag and a 0–100 risk_score, and you pay per check with prepaid credits.
Quick start
- Create an account.
- Create an API key on the API keys page. It's shown once, so store it somewhere safe.
- Send your first request:
curl -X POST https://api.verified.net/v1/email \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"address": "jane.doe@gmail.com"}'
Python
import requests
r = requests.post(
"https://api.verified.net/v1/email",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"address": "jane.doe@gmail.com"},
timeout=30,
)
r.raise_for_status()
result = r.json()
print(result["valid"], result["risk_score"])Node.js
const r = await fetch("https://api.verified.net/v1/email", {
method: "POST",
headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ address: "jane.doe@gmail.com" }),
});
const result = await r.json();
console.log(result.valid, result.risk_score);PHP
$ch = curl_init("https://api.verified.net/v1/email");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode(["address" => "jane.doe@gmail.com"]),
]);
$result = json_decode(curl_exec($ch), true);
echo $result["valid"] ? "valid" : "invalid", " ", $result["risk_score"];The base URL is https://api.verified.net. Use POST with a JSON body: values then stay out of URLs and server logs. Every lookup endpoint also accepts GET with a query parameter for quick tests.
Authentication
Send your API key in the Authorization header on every request:
Authorization: Bearer YOUR_API_KEY
Keys start with vfy_live_. Treat them like passwords: keep them on your server, never in a web page or mobile app. You can create several keys (for example one per application) and revoke any of them on the API keys page. A missing, invalid or revoked key gets 401 unauthorized.
Credits
Each check uses prepaid credits from your account balance:
| Check | Credits |
|---|---|
| 1 | |
| Phone | 1 |
| Carrier and porting | 3 |
| IP address | 1 |
| Contact verification | 1, also when no record is found |
| Reverse phone, Standard | 10 when a caller ID name is found, otherwise 0 |
| Reverse phone, Premium | 25 when contacts are found, 10 when only a caller ID name is found, otherwise 0 |
| Reverse email | 10 when contacts are found, otherwise 0 |
- Invalid input is free. A malformed email, an unparseable phone number, or an invalid or private IP address returns a full response with
credits_charged: 0. - Every response says what it cost in
credits_charged. - Repeats are free for 7 days. If you check the same value again within 7 days (same account, same type), you get the earlier answer with
cached: true,credits_charged: 0andrepeat_of(the earlier lookup's id). Send"bypass_cache": trueto look it up fresh instead, charged as usual. - When your balance is too low, the API answers
402 insufficient_creditsand charges nothing. Buy credits in the dashboard; they don't expire.
Rate limits
Limits apply per API key, in fixed windows:
| Requests | Limit |
|---|---|
| Email, phone, IP, contact verification, account, bulk jobs | 200 per 10 seconds (about 1,200 per minute) |
| Live lookups: carrier and porting, reverse phone, reverse email | 1,000 per minute |
Responses carry these headers:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed in the current window for this key. |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Seconds until the window resets. |
X-RateLimit-Window | The window length: 10s or 60s. |
Over the limit you get 429 rate_limited with a Retry-After header (seconds until the window resets). Wait that long, then retry. For large lists, use bulk jobs: one request checks up to 100,000 values. Need a higher limit? Contact us.
Every response has an X-Request-Id header. Include it when you contact support.
Errors
A check that ran always returns 200, even when the value is invalid: read valid and risk_score. Errors use other status codes and one format:
{
"error": {
"code": "unauthorized",
"message": "Send your API key as 'Authorization: Bearer <key>'.",
"request_id": "6f1c0e9b2a7d4e5f8a9b0c1d"
}
}
| Status | Code | When |
|---|---|---|
| 400 | invalid_type, invalid_items, invalid_country, invalid_body, missing_file, empty_file, column_not_found | A bulk job request isn't usable. The message says why. |
| 401 | unauthorized | Missing, invalid or revoked API key. |
| 402 | insufficient_credits | Your balance doesn't cover the request. Nothing was charged. |
| 404 | not_found | The bulk job doesn't exist or belongs to another account. |
| 413 | file_too_large, too_many_rows | A bulk upload is over 20 MB or 100,000 rows. |
| 422 | invalid_request | A required field is missing or has the wrong type, e.g. "address: Field required". |
| 429 | rate_limited | Too many requests this minute. See rate limits. |
| 400 | invalid_webhook_url, invalid_idempotency_key, invalid_tier | A bulk job option isn't usable. |
| 503 | carrier_unavailable | Live carrier data couldn't be fetched. Nothing was charged; retry shortly. |
| 5xx | Something went wrong on our side. Retry with a short delay; you're not charged for failed requests. |
Recommendation
Email, phone and IP results include one field to act on:
"recommendation": {"action": "review", "reasons": ["catch_all", "role_account"]}
action is accept, review or reject. reasons list why, for example disposable, mailbox_not_found, no_mail_server, catch_all, role_account, possible_typo, unassigned_range, voip, tor_exit, datacenter, high_risk_score (70+) or elevated_risk_score (30+). Invalid input is always reject, with the reason as its reason.
Checks syntax, the domain's mail servers (MX), disposable and role addresses, free email providers and likely typos.
| Body field | Type | |
|---|---|---|
address | string, required | The email address, up to 320 characters. |
GET form: /v1/email?address=…
curl -X POST https://api.verified.net/v1/email \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"address": "jane.doe@gmial.com"}'
{
"id": "34072140-2672-41b4-bf9c-c6eaa189c1c6",
"credits_charged": 1,
"cached": false,
"created_at": "2026-10-16T06:12:14.902101+00:00",
"email": "jane.doe@gmial.com",
"normalized": "jane.doe@gmial.com",
"valid": true,
"deliverability": "unknown",
"risk_score": 0,
"did_you_mean": "jane.doe@gmail.com",
"checks": {
"syntax": true,
"mx_found": true,
"smtp_status": "skipped",
"catch_all": null,
"disposable": false,
"role_account": false,
"free_provider": false
},
"whois_history": {
"known": false
}
}
| Field | Meaning |
|---|---|
valid | false if the syntax is wrong or the domain can't receive mail. |
deliverability | undeliverable (bad syntax, no mail server, or the mailbox doesn't exist), risky (disposable, or a catch-all domain that accepts any address), deliverable (mailbox confirmed) or unknown (the domain accepts mail, but the mailbox wasn't confirmed). |
risk_score | 0 (low) to 100 (high). 95 for a domain with no mail server, 100 for bad syntax; disposable domains add 60, role addresses 10. |
did_you_mean | A suggested correction for a likely typo in a common domain, or null. |
checks.mx_found | true, false, or null if DNS didn't answer in time (that result isn't cached). |
checks.smtp_status | Mailbox check against the mail server: accepted, rejected (the mailbox doesn't exist), inconclusive (the server deferred or refused for a policy reason), unreachable or skipped. Some providers are never checked because they accept every address or don't allow checks (for example Outlook/Hotmail, Yahoo, AOL and iCloud), and checks are rate limited per mail provider; those return skipped and deliverability unknown. Bulk jobs don't run mailbox checks yet; their results show skipped. |
checks.disposable | The domain is a known throwaway email service. |
checks.role_account | A shared address such as info@, support@ or sales@. |
checks.free_provider | A free mailbox provider such as Gmail, Yahoo or Outlook. |
whois_history | Domain-level history from our WHOIS records: {"known": false}, or known, appearances, contact_versions, contact_changes and registrant_portfolio (how many domains the same registrant held: 1, 2-9, 10-99, 100-999, 1000+). Informational; it doesn't change risk_score. No registrant names, emails or phone numbers are ever returned. |
Phone
Parses and normalizes a number to E.164, checks it's valid for its country, and returns the line type, region and time zones. For US numbers it also returns the carrier the number's range was assigned to, its rate center and LATA.
| Body field | Type | |
|---|---|---|
number | string, required | The phone number in any common format. phone_number is accepted too. |
default_country | string, optional | Two-letter country code (e.g. US) for numbers written without a + country code. |
GET form: /v1/phone?number=%2B14155552671 (encode + as %2B).
curl -X POST https://api.verified.net/v1/phone \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"number": "(202) 456-1111", "default_country": "US"}'
{
"id": "d3e80dee-fdbd-49c9-bef5-2755ce9fee2d",
"credits_charged": 1,
"cached": false,
"created_at": "2026-10-16T23:59:37.560245+00:00",
"number": "(202) 456-1111",
"normalized": "+12024561111",
"e164": "+12024561111",
"valid": true,
"reason": null,
"country": "US",
"country_calling_code": 1,
"region": "Washington D.C.",
"timezones": ["America/New_York"],
"national_format": "(202) 456-1111",
"international_format": "+1 202-456-1111",
"line_type": "landline",
"assignment": {
"assigned": true,
"carrier": "VERIZON WASHINGTON DC, INC.",
"ocn": "9211",
"carrier_type": "landline",
"rate_center": "WASHINGTON ZONE 1",
"state": "DC",
"lata": "236"
},
"local_time": "2026-10-16T19:59:00-04:00",
"voip": false,
"risk_score": 0,
"spam_reports": 0,
"recommendation": {
"action": "accept",
"reasons": []
}
}
| Field | Meaning |
|---|---|
valid / reason | When valid is false, reason is missing_country_code (no + and no default_country), unparseable or invalid_number. These are free. |
e164 | The number in E.164 format, e.g. +14155552671. |
line_type | mobile, landline, fixed_or_mobile (the numbering plan doesn't tell them apart; for US numbers we use the range holder's carrier type instead, so this mostly appears for Canada), toll_free, premium, shared_cost, voip, other or unknown. |
region, timezones | Where the number was assigned, from numbering-plan data (not the caller's live location). |
assignment | US numbers only, otherwise null. Who the number's range (its thousands-block, or else its prefix) was assigned to, from the official numbering administrator's (NANPA) daily reports: carrier and ocn (Operating Company Number), carrier_type (wireless, landline, voip, pager or null if unknown), rate_center, state and lata. This is the original assignment: a number ported to another carrier still shows the range holder. assigned: false means the block is unassigned, so no number in it should be in service. |
spam_reports, spam | US numbers: consumer complaints about calls from this number in the last 12 months, from the FTC's public Do Not Call complaint data (unverified reports). spam has reports, robocall_reports, last_reported, top_subject and source. One report raises risk_score to 50, two to 60, three or more to 70 (10 or more: 80), and the recommendation lists spam_reports. Outside the US: spam_reports 0. |
local_time | The current time in the number's first time zone (ISO 8601). |
voip | true for an internet phone service (VoIP) number, false for mobile or landline, null if unknown. Based on the original assignment; for the current carrier's line type use carrier and porting. |
risk_score | 0–100, from the line type and our own abuse reports. |
Carrier and porting
US and Canadian numbers: the carrier serving the number today, whether it was ported away from its original carrier, and its current line type, from a live number-portability lookup. 3 credits. If the live data can't be fetched you get 503 carrier_unavailable and aren't charged.
| Body field | Type | |
|---|---|---|
number | string, required | The phone number. Without a + country code it's read as US. |
default_country | string | Two-letter country for numbers without a country code. Default US. |
bypass_cache | boolean | Look it up fresh instead of returning a free repeat. |
curl -X POST https://api.verified.net/v1/carrier \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"number": "+1 202 456 1111"}'
{
"id": "9e883413-1444-428c-ab60-ad3e2cc61a61",
"credits_charged": 3,
"cached": false,
"created_at": "2026-10-16T23:59:37.652425+00:00",
"number": "+1 202 456 1111",
"normalized": "+12024561111",
"valid": true,
"reason": null,
"risk_score": null,
"current_carrier": {
"name": "VERIZON WASHINGTON DC, INC.",
"ocn": "9211",
"spid": null
},
"original_carrier": {
"name": "VERIZON WASHINGTON DC, INC.",
"ocn": "9211"
},
"ported": false,
"ported_date": null,
"line_type": "landline",
"voip": false,
"lrn": null,
"routing": {
"city": "WSHNGTNZN1",
"state": null
}
}
| Field | Meaning |
|---|---|
current_carrier | name, ocn and spid of the carrier serving the number now. |
original_carrier | Who the number's range was assigned to (NANPA). |
ported, ported_date | Whether the number moved to another carrier, and when (the date isn't always known). When the portability database doesn't say, we compare the current and original OCN. |
as_of | When this carrier data was fetched from the carrier network. Answers are reused for up to 7 days (use bypass_cache for a fresh one); if the network can't be reached, the newest saved answer is returned with its older as_of. |
line_type, voip | The current line type (mobile, landline, voip, ...) and whether it's VoIP. |
lrn, routing | The Local Routing Number (the last digits may be masked) and its city and state. |
IP address
Location (country, region, city), network owner, Tor exit nodes and datacenter or cloud hosting, with a risk score. IPv4 and IPv6.
| Body field | Type | |
|---|---|---|
ip | string, required | The IP address. ip_address is accepted too. |
GET form: /v1/ip?ip=8.8.8.8
curl -X POST https://api.verified.net/v1/ip \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ip": "8.8.8.8"}'
{
"id": "b28208b9-398a-44ec-a55b-4a260a01084e",
"credits_charged": 1,
"cached": false,
"created_at": "2026-10-16T06:12:15.119826+00:00",
"ip": "8.8.8.8",
"normalized": "8.8.8.8",
"version": 4,
"valid": true,
"reason": null,
"location": {
"continent": "NA",
"country_code": "US",
"country": "United States",
"region": "California",
"city": "Mountain View",
"latitude": 37.422,
"longitude": -122.085
},
"network": {
"asn": 15169,
"organization": "Google LLC"
},
"checks": {
"tor_exit": false,
"datacenter": true,
"hosting_provider": "Google LLC",
"blocklisted": false
},
"risk_score": 40
}
| Field | Meaning |
|---|---|
valid / reason | When valid is false, reason is invalid_format, or private, loopback, link_local, multicast, unspecified or reserved for addresses that aren't on the public internet. These are free. |
location | City-level and approximate. Coordinates are a city center, not a street address. |
network | The autonomous system number and organization that announces the address. |
checks.tor_exit | A current Tor exit node (list refreshed daily). |
checks.datacenter / hosting_provider | The address belongs to a cloud or hosting provider, not a home or mobile network. hosting_provider is aws, gcp, oracle or digitalocean for their published ranges, otherwise the network's name. |
risk_score | 85 for Tor exits, 40 for datacenter addresses, otherwise 0. |
IP geolocation by DB-IP. VPN detection isn't included yet.
Contact verification
Checks whether a name and/or phone number match the domain registration (WHOIS) records that list an email address as the contact. Useful to confirm that a business contact belongs together. The answer is a match level only: we never return the names or phone numbers on file. Our records are historical and US only, and we leave out privacy services, domain resellers, placeholder names like "Domain Admin", and people who opted out.
| Body field | Type | |
|---|---|---|
email | string, required | The email address to look up. |
name | string | Person or business name to compare. Word order, accents, punctuation, titles (Mr, Dr), suffixes (Jr) and company forms (Inc, LLC) are ignored. |
phone | string | Phone number to compare. Without a + country code it's read as a US number. |
default_country | string | Two-letter country for phone numbers without a country code. Default US. |
Send name, phone or both. POST only, so names and numbers stay out of URLs and logs.
curl -X POST https://api.verified.net/v1/contact \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "jane@example.com", "name": "Jane Q. Doe", "phone": "+1 415 555 0100"}'
{
"id": "168aaadd-ea4a-4e40-888a-df653d3f6892",
"credits_charged": 1,
"cached": false,
"created_at": "2026-10-16T20:08:01.469440+00:00",
"email": "jane@example.com",
"name": "Jane Q. Doe",
"phone": "+1 415 555 0100",
"valid": true,
"reason": null,
"normalized": "jane@example.com",
"risk_score": null,
"found": true,
"name_match": "partial",
"phone_match": "match",
"matched_on": "current"
}
Here the record says "Jane Doe": the extra middle initial makes the name a partial match.
| Field | Meaning |
|---|---|
valid / reason | When valid is false, reason is invalid_email, name_or_phone_required, invalid_name (no usable words) or invalid_phone. These are free. |
found | We hold usable registrant records for this email. When false, the match fields are null. |
name_match | match: the same words. partial: a missing middle name, or the same last name and first initial (J Doe, Jan Doe). no_match. null if you sent no name. |
phone_match | match (the same number) or no_match. null if you sent no phone. |
matched_on | current: the domain's most recent contact record we hold. previous: an older version of it. An email can be the contact on many domains; the answer comes from the record that matches best. |
risk_score | Always null for contact checks. |
Reverse lookup
Find the person or business behind a phone number or an email address. You're charged only when something is found. Contacts come from historical domain registration (WHOIS) records: names, emails and phone numbers that registrants published, without privacy services, domain resellers, placeholder names or people who opted out. The records are several years old and US only.
Reverse phone
| Body field | Type | |
|---|---|---|
phone | string, required | A US or Canadian number. Without a + country code it's read as US. number is accepted too. |
tier | string | standard (default): caller ID name. premium: caller ID name plus registrant contacts. |
default_country | string | Two-letter country for numbers without a country code. Default US. |
curl -X POST https://api.verified.net/v1/reverse/phone \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"phone": "+1 202 456 1111", "tier": "standard"}'
{
"id": "40e112bd-3d59-47ac-8fcf-69e54c518f90",
"credits_charged": 10,
"cached": false,
"created_at": "2026-10-16T22:32:23.806855+00:00",
"phone": "+1 202 456 1111",
"tier": "standard",
"normalized": "+12024561111",
"valid": true,
"reason": null,
"risk_score": null,
"found": true,
"caller_id": {
"name": "THE WHITE HOUSE"
},
"contacts": null
}
Reverse email
| Body field | Type | |
|---|---|---|
email | string, required | The email address. |
curl -X POST https://api.verified.net/v1/reverse/email \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "jane@example.com"}'
| Field | Meaning |
|---|---|
found | Whether anything was found. When false, credits_charged is 0. |
caller_id.name | Reverse phone: the caller ID name (CNAM) registered for the number, or caller_id: null. Generic values like "WIRELESS CALLER" or a state name are left out. |
caller_id.as_of | When the caller ID name was fetched. Caller ID names are reused for up to 30 days. |
contacts | Up to 5 registrant contacts: name, email, phone, current (true: a domain's most recent contact record we hold; false: an older one) and domains (on how many domains this contact appears). Reverse phone Standard returns contacts: null. |
valid / reason | Free when valid is false: invalid_number, missing_country_code, unsupported_country (not US or Canada) or invalid_email. |
Your balance must cover the most a lookup can cost (Premium: 25 credits), or the API answers 402 insufficient_credits.
Account
Free. Your balance, usage (today and the last 30 days, UTC) and the API key you're using.
curl https://api.verified.net/v1/account -H "Authorization: Bearer YOUR_API_KEY"
{
"email": "you@example.com",
"email_verified": true,
"created_at": "2026-10-15T18:02:11.412873+00:00",
"credits": {"balance": 19880},
"usage": {
"today": {"lookups": 42, "credits": 51},
"last_30_days": {"lookups": 1210, "credits": 1655}
},
"api_key": {"name": "production", "prefix": "vfy_live_Ab3d", "created_at": "2026-10-15T18:05:40.118402+00:00", "rate_limit_per_min": 1200}
}
Bulk jobs
Check up to 100,000 values in one job. Jobs run in the background: create one, poll its status, then fetch the results. Each unique value is charged once, like a single lookup, and invalid values are free. Your balance must cover every unique value when you create the job; the final cost is often lower. Jobs and their results are deleted after 30 days. You can also upload files on the Bulk upload page.
Create a job
Either a JSON list:
curl -X POST https://api.verified.net/v1/bulk/jobs \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type": "email", "items": ["jane.doe@gmail.com", "info@example.com", "not-an-email"]}'
or a CSV upload (the column is found from the header or the values, or name it with column):
curl -X POST https://api.verified.net/v1/bulk/jobs \
-H "Authorization: Bearer YOUR_API_KEY" \
-F type=phone -F default_country=US -F column=mobile \
-F file=@contacts.csv
| Field | |
|---|---|
type | Required: email, phone, ip, carrier, reverse_phone or reverse_email. |
tier | Optional, reverse_phone jobs: standard (default) or premium. |
webhook_url | Optional: an https:// URL we POST to when the job finishes. See webhooks. |
items | JSON body: a list of strings, each up to 320 characters. |
file | Multipart: a CSV (comma, semicolon, tab or pipe separated) or a plain list, one value per line. Up to 20 MB. |
column | Multipart, optional: header name or column number (1 = first). |
default_country | Optional, phone jobs: two-letter country code for numbers without +. |
The response is 202 with the job:
{
"id": "514a249e-16a2-47e1-9a7e-c7a51de20cec",
"status": "queued",
"type": "email",
"source": "api",
"filename": null,
"rows": 3,
"unique_values": 3,
"processed": 0,
"valid": 0,
"invalid": 0,
"skipped": 0,
"credits_charged": 0,
"progress": 0.0,
"created_at": "2026-10-16T06:12:15.135085+00:00",
"started_at": null,
"completed_at": null,
"error": null
}
Send an Idempotency-Key header (any unique string, up to 255 characters) to make retries safe: repeating the request with the same key within 24 hours returns the job it created (200, header Idempotent-Replayed: true) instead of starting another.
Webhooks
With webhook_url, the create response includes webhook_secret (shown only once). When the job completes or is cancelled we POST:
{"event": "bulk.job.completed", "sent_at": "2026-10-16T23:59:01.511Z", "job": { ...the job, as GET /v1/bulk/jobs/{id} returns it... }}
The X-Verified-Signature header is sha256= followed by the hex HMAC-SHA256 of the raw request body, keyed with webhook_secret. Compute it yourself and compare in constant time before trusting the body. Answer with any 2xx within 5 seconds. We try up to 3 times (right away, then after about 4 and 16 minutes) and don't follow redirects. The URL must resolve to a public address. The job's webhook field shows status (waiting, pending, delivered or failed) and attempts.
# Python
import hashlib, hmac
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(expected, request.headers["X-Verified-Signature"])
Check status
status is queued, running, completed, cancelled or failed; progress goes from 0 to 1. Poll every few seconds. skipped counts values that weren't checked or charged (the job was cancelled or the balance ran out). GET /v1/bulk/jobs lists your 50 most recent jobs.
Get results
CSV: your original rows and columns in their original order, plus a vfy_status column and the result columns (vfy_valid, vfy_risk_score, …):
input,vfy_status,vfy_normalized,vfy_valid,vfy_deliverability,vfy_risk_score,...
jane.doe@gmail.com,done,jane.doe@gmail.com,true,unknown,0,...
info@example.com,done,info@example.com,false,undeliverable,95,...
not-an-email,done,not-an-email,false,undeliverable,100,...
Without format=csv you get JSON, one entry per unique value with the same result object as a single lookup, 1,000 per page (?page=2, and has_next tells you when to stop):
{
"job": { "id": "514a249e-…", "status": "completed", ... },
"page": 1,
"has_next": false,
"items": [
{ "input": "jane.doe@gmail.com", "status": "done", "result": { "valid": true, "risk_score": 0, ... } },
...
]
}
An item's status is done, insufficient_credits, cancelled or error; result is set only when it's done.
Cancel a job
Stops a queued or running job. Values not yet checked aren't charged; results so far stay available.
AI agents (MCP)
AI agents and assistants can use Verified.net directly through our Model Context Protocol server. It offers these tools: verify_email, validate_phone, carrier_lookup, ip_lookup, verify_contact, reverse_phone, reverse_email, create_bulk_job, get_bulk_job, get_bulk_results and get_account. They cost the same credits as the API (free repeats included), and every result adds credits_remaining so the agent can watch its spending.
Authentication is your API key in an Authorization: Bearer header. Use a separate key for each agent, so you can see its usage and revoke it on its own.
Claude Code
claude mcp add --transport http verified https://api.verified.net/mcp \
--header "Authorization: Bearer YOUR_API_KEY"
Cursor (~/.cursor/mcp.json) or VS Code (.vscode/mcp.json, use "servers" and add "type": "http")
{
"mcpServers": {
"verified": {
"url": "https://api.verified.net/mcp",
"headers": {"Authorization": "Bearer YOUR_API_KEY"}
}
}
}
Claude Desktop and other apps that only start local servers: use the mcp-remote bridge (needs Node.js) in the app's MCP config:
{
"mcpServers": {
"verified": {
"command": "npx",
"args": ["mcp-remote", "https://api.verified.net/mcp", "--header", "Authorization: Bearer YOUR_API_KEY"]
}
}
}
Reverse lookup tools return personal contact details. Use them only for lawful purposes such as verifying contacts or preventing fraud.
Need help?
Try any endpoint in the interactive reference (click Authorize and paste your key), or download the OpenAPI spec to generate a client. Questions: use our contact form.