Developers · Docs

Email verification API reference

Authenticate with an API key. Verify one address or many. Get one BillionVerify-compatible status per address — valid, invalid, risky, disposable, catchall, role, or unknown.

Quickstart

From key to first verify

Create an API key

Sign in, open Settings → API keys, and create a key. Store it like a password — never ship it to the browser.

Open API keys

Authenticate each request

Pass Authorization: Bearer <key>, X-API-Key, or ValidReach-API-Key. Missing or invalid keys return 401 with code 4010.

API product page

Credits

Definitive results (deliverable, undeliverable, or risky) use 1 credit. Unknown never burns credits.

View credits

Endpoints

POST/api/v1/verify/single

Verify one email

Real-time check for signup forms, checkout, and CRM capture. Optional check_smtp and force_refresh.

Request

POST /api/v1/verify/single
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{ "email": "user@example.com", "check_smtp": false }

Response (shape)

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "email": "user@example.com",
    "status": "valid",
    "score": 0.95,
    "is_deliverable": true,
    "is_disposable": false,
    "is_role": false,
    "is_free": true,
    "reason": "accepted",
    "credits_used": 1,
    "retryable": false
  }
}
POST/api/v1/verify/bulk

Verify up to 50 emails

Synchronous batch with per-row results, aggregate counters, and deliverability buckets.

Request

POST /api/v1/verify/bulk
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{ "emails": ["a@x.com", "b@y.com"] }

Response (shape)

{
  "success": true,
  "code": "0",
  "data": {
    "results": [ /* { email, status, result, … } */ ],
    "total_emails": 2,
    "valid_emails": 1,
    "invalid_emails": 1,
    "credits_used": 2,
    "process_time": 420,
    "deliverability_buckets": { "strict_deliverable": 1 }
  }
}
POST/api/v1/verify/file

Upload a list (async file job)

multipart/form-data with a CSV or TXT file (optional check_smtp, email_column). Returns a task handle immediately.

Request

POST /api/v1/verify/file
Authorization: Bearer YOUR_API_KEY
Content-Type: multipart/form-data

file=@emails.csv  email_column=email

Response (shape)

{
  "success": true,
  "code": "0",
  "data": {
    "task_id": "…",
    "status": "pending",
    "status_url": "/api/v1/verify/file/<taskId>",
    "download_url": "/api/v1/verify/file/<taskId>/results"
  }
}
GET/api/v1/verify/file/:taskId

Fetch job status

Progress and per-status counters. Use ?timeout=30 to long-poll until the job reaches a terminal state.

Request

GET /api/v1/verify/file/<taskId>?timeout=30
Authorization: Bearer YOUR_API_KEY

Response (shape)

{
  "success": true,
  "code": "0",
  "data": {
    "task_id": "…",
    "status": "completed",
    "progress": 100,
    "total_emails": 1000,
    "processed_emails": 1000,
    "valid_emails": 850,
    "invalid_emails": 100,
    "unknown_emails": 30,
    "download_url": "/api/v1/verify/file/<taskId>/results"
  }
}
GET/api/v1/verify/file/:taskId/results

Download job results

CSV by default. Add ?format=json for paginated rows, or filter with valid, invalid, risky, unknown, catchall, role, and disposable.

Request

GET /api/v1/verify/file/<taskId>/results?invalid=true
Authorization: Bearer YOUR_API_KEY

Response (shape)

email,status,result,reason,score,billable,row_status,…
user@example.com,invalid,undeliverable,mailbox_not_found,0,1,done,…
GET/api/v1/credits

Check credit balance

Balance, lifetime consumption, and granted credits for the account behind the API key.

Request

GET /api/v1/credits
Authorization: Bearer YOUR_API_KEY

Response (shape)

{
  "success": true,
  "code": "0",
  "data": {
    "credits_balance": 9500,
    "credits_consumed": 500,
    "credits_added": 10000,
    "last_updated": "2026-02-04T10:30:00Z"
  }
}
POST/GET/api/v1/webhooks

Register task webhooks

Subscribe an HTTPS endpoint to file.completed / file.failed. Deliveries carry X-Webhook-Event, X-Webhook-Timestamp, and X-Webhook-Signature (sha256=HMAC over timestamp.rawBody). DELETE /api/v1/webhooks/:id removes one.

Request

POST /api/v1/webhooks
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{ "url": "https://your-app.com/hooks/verify",
  "events": ["file.completed", "file.failed"] }

Response (shape)

{
  "success": true,
  "code": "0",
  "data": {
    "id": "…",
    "url": "https://your-app.com/hooks/verify",
    "events": ["file.completed", "file.failed"],
    "secret": "5c60…619bf",
    "is_active": true
  }
}
POST/GET/api/v1/verify/disposable

Disposable check (free)

In-memory disposable-domain lookup. Never consumes credits.

Request

GET /api/v1/verify/disposable?email=x@mailinator.com
Authorization: Bearer YOUR_API_KEY

Response (shape)

{
  "success": true,
  "code": "0",
  "data": {
    "email": "x@mailinator.com",
    "domain": "mailinator.com",
    "is_disposable": true,
    "checked_at": "2026-02-04T10:30:00Z"
  }
}

Result values

valid

Mailbox exists and accepts mail. Safe to send.

invalid

Mailbox does not exist or cannot receive: invalid syntax, no MX, mailbox not found.

risky

Most likely deliverable, but the domain has a confirmed abuse history. Treat like disposable.

disposable

Temporary or disposable mailbox. Usually remove from the list.

catchall

The domain accepts all addresses, so the specific mailbox cannot be confirmed.

role

Role-based mailbox such as info@ or support@. Usually deliverable, may engage less.

unknown

Deliverability could not be confirmed. Never burns a credit — retry later if needed.

Boolean fields such as is_disposable, is_role, and is_catchall help you encode policy. See understanding risky emails for handling guidance.

Ready to integrate

Create a key and verify your first address

Start free. Same results in the dashboard, list jobs, and API.