BillionVerify LogoBillionVerify

API Reference

Complete BillionVerify API reference for authentication, email verification, file jobs, downloads, credits, and webhooks.

The BillionVerify API is a RESTful service for real-time email verification, synchronous batch checks, asynchronous file processing, credits, and webhooks. All requests must be sent over HTTPS.

Base URL

https://api.billionverify.com/v1

OpenAPI Specification

The canonical machine-readable contract is available here:

Authentication

Send your API key with one of these headers, in the same priority order used by the server:

  1. BILLIONVERIFY-API-KEY
  2. BV-API-KEY
  3. EV-API-KEY
  4. EMAILVERIFY-API-KEY
  5. Authorization: Bearer <api_key>

Primary header example:

BILLIONVERIFY-API-KEY: bv_live_...

Get your API key from the BillionVerify dashboard.

Example

curl -X POST https://api.billionverify.com/v1/verify/single \
  -H "BILLIONVERIFY-API-KEY: bv_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","check_smtp":false}'

Rate Limits

Rate limits are applied per API key and endpoint type.

EndpointRate Limit
Single Verification (/verify/single)6,000 requests/minute
Batch Verification (/verify/bulk)1,500 requests/minute
File Upload (/verify/file)300 requests/minute
Other endpoints (/credits, /webhooks, etc.)200 requests/minute

When rate limited, the API returns 429 Too Many Requests:

{
  "success": false,
  "code": "4290",
  "message": "Rate limit exceeded",
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please try again later."
  }
}

Response Format

Successful responses:

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {}
}

Error responses:

{
  "success": false,
  "code": "4010",
  "message": "Unauthorized",
  "error": {
    "code": "INVALID_API_KEY",
    "message": "API key is invalid or missing"
  }
}

Endpoints

Single Email Verification

Verify a single email synchronously.

POST /verify/single

Request

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

Parameters

ParameterTypeRequiredDefaultDescription
emailstringYes-Email address to verify
check_smtpbooleanNofalsePerform live SMTP mailbox verification

Notes

  • check_smtp defaults to false when omitted.
  • When check_smtp=false, the request skips live SMTP network checks.

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "email": "user@example.com",
    "status": "valid",
    "score": 0.95,
    "is_deliverable": true,
    "is_disposable": false,
    "is_catchall": false,
    "is_role": false,
    "is_free": false,
    "has_gravatar": false,
    "gravatar_url": "",
    "domain": "example.com",
    "domain_age": 10,
    "mx_records": ["mail.example.com"],
    "domain_reputation": {
      "mx_ip": "192.0.2.1",
      "is_listed": false,
      "blacklists": [],
      "checked": true
    },
    "smtp_check": false,
    "reason": "accepted",
    "smtp_response": "",
    "error_message": "",
    "domain_suggestion": "",
    "response_time": 250,
    "credits_used": 1
  }
}

Batch Email Verification

Verify multiple email addresses synchronously. Use this for small batches of up to 100 emails.

POST /verify/bulk

Request

{
  "emails": ["user1@example.com", "user2@example.com"],
  "check_smtp": false
}

Parameters

ParameterTypeRequiredDefaultDescription
emailsarrayYes-Array of email addresses (max: 100)
check_smtpbooleanNofalsePerform live SMTP mailbox verification

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "results": [
      {
        "email": "user1@example.com",
        "status": "valid",
        "score": 0.95,
        "is_deliverable": true,
        "credits_used": 1
      },
      {
        "email": "user2@example.com",
        "status": "invalid",
        "score": 0,
        "is_deliverable": false,
        "credits_used": 0
      }
    ],
    "total_emails": 2,
    "valid_emails": 1,
    "invalid_emails": 1,
    "credits_used": 1,
    "process_time": 1500
  }
}

File Upload Verification

Upload a CSV, TXT, XLSX, or XLS file for asynchronous verification.

POST /verify/file

Multipart Fields

FieldTypeRequiredDefaultDescription
filefileYes-CSV, TXT, XLSX, or XLS file
check_smtpbooleanNofalsePerform live SMTP mailbox verification
email_columnstringNoauto-detectColumn containing email addresses
preserve_originalbooleanNotrueKeep original columns in the result file

Supported Limits

  • Maximum file size: 20MB
  • Maximum emails per file: 100,000

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "task_id": "7143874e-21c5-43c1-96f3-2b52ea41ae6a",
    "file_name": "emails.csv",
    "file_size": 45678,
    "status": "pending",
    "message": "File uploaded successfully, parsing and processing email verification",
    "status_url": "https://api.billionverify.com/v1/verify/file/7143874e-21c5-43c1-96f3-2b52ea41ae6a",
    "created_at": "2026-02-04T10:30:00Z",
    "estimated_count": 1000,
    "unique_emails": 950,
    "total_rows": 1000,
    "email_column": "email"
  }
}

Get File Job Status

Get the latest status for a file job.

GET /verify/file/{job_id}

Query Parameters

ParameterTypeRequiredDefaultDescription
timeoutintegerNo0Long-polling timeout in seconds (0-300)
  • download_url is the stable API entrypoint for result downloads.
  • direct_download_url is a signed storage URL for immediate download.
  • direct_download_expires_at tells you when that signed storage URL expires.
  • result_file_url and result_file_path are not part of the public API contract.

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "task_id": "7143874e-21c5-43c1-96f3-2b52ea41ae6a",
    "status": "completed",
    "progress": 100,
    "email_progress": 100,
    "chunk_progress": 100,
    "progress_source": "email",
    "total_emails": 1000,
    "processed_emails": 1000,
    "valid_emails": 850,
    "invalid_emails": 100,
    "unknown_emails": 30,
    "role_emails": 15,
    "catchall_emails": 5,
    "risky_emails": 0,
    "disposable_emails": 0,
    "credits_used": 970,
    "download_url": "https://api.billionverify.com/v1/verify/file/7143874e-21c5-43c1-96f3-2b52ea41ae6a/results",
    "direct_download_url": "https://download.example.com/results_7143874e.csv?signature=...",
    "direct_download_expires_at": "2026-02-04T11:32:05Z",
    "started_at": "2026-02-04T10:30:00Z",
    "completed_at": "2026-02-04T10:32:05Z",
    "total_chunks": 10,
    "completed_chunks": 10,
    "failed_chunks": 0,
    "unique_emails": 950,
    "total_rows": 1000
  }
}

Job Status Values

StatusDescription
pendingJob is queued
processingJob is actively being processed
uploadingFinalizing or assembling results
completedJob finished successfully
completed_with_warningJob finished, but with warnings
failedJob failed

Download File Results

Download verification results for a completed file job.

GET /verify/file/{job_id}/results

Behavior

  • Without filters, the endpoint responds with 307 Temporary Redirect to the full result file.
  • With filters, the endpoint returns a generated CSV directly.
  • Filters are combined with OR semantics.

Query Parameters

ParameterTypeDescription
validbooleanInclude valid emails
invalidbooleanInclude invalid emails
riskybooleanInclude risky emails
unknownbooleanInclude unknown emails
catchallbooleanInclude catch-all emails
rolebooleanInclude role emails
disposablebooleanInclude disposable emails

Example

curl -L -o filtered-results.csv \
  "https://api.billionverify.com/v1/verify/file/{job_id}/results?valid=true&catchall=true&role=true" \
  -H "BILLIONVERIFY-API-KEY: bv_live_xxx"

Credits

Get the current credit balance for the authenticated account.

GET /credits

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "account_id": "abc123",
    "api_key_id": "key_xyz",
    "api_key_name": "Default API Key",
    "credits_balance": 9500,
    "credits_consumed": 500,
    "credits_added": 10000,
    "last_updated": "2026-02-04T10:30:00Z"
  }
}

Webhooks

Use webhooks to receive asynchronous file-job notifications.

Endpoints

  • POST /webhooks
  • GET /webhooks
  • DELETE /webhooks/{webhook_id}

Supported Events

  • file.completed
  • file.failed

verification.completed is not part of the public webhook contract.

Create Webhook

POST /webhooks

Request

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

Rules

  • url must be HTTPS
  • events may contain only supported event names

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "id": "673f3bff-81ea-4730-9cef-af1eb7f134bf",
    "url": "https://your-app.com/webhooks/billionverify",
    "events": ["file.completed", "file.failed"],
    "secret": "5c609e6893ab3b65ce8940549a030bc165762fe171e0b38f880bd570099619bf",
    "is_active": true,
    "created_at": "2026-02-04T10:30:00Z",
    "updated_at": "2026-02-04T10:30:00Z"
  }
}

The webhook secret is returned only on creation. Store it securely. You need it to verify webhook signatures.

List Webhooks

GET /webhooks

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "webhooks": [
      {
        "id": "673f3bff-81ea-4730-9cef-af1eb7f134bf",
        "url": "https://your-app.com/webhooks/billionverify",
        "events": ["file.completed", "file.failed"],
        "is_active": true,
        "last_delivery_status": "success",
        "last_delivery_at": "2026-04-01T12:00:00Z",
        "last_error": null,
        "created_at": "2026-02-04T10:30:00Z",
        "updated_at": "2026-02-04T10:30:00Z"
      }
    ],
    "total": 1
  }
}
  • last_delivery_status is success or failed when a delivery has been attempted.
  • last_delivery_at is the timestamp of the most recent final delivery outcome.
  • last_error contains the latest final error message, or null when the latest delivery succeeded.
  • For webhooks that have never been delivered, all three fields are null.

Delete Webhook

DELETE /webhooks/{webhook_id}

Response

{
  "success": true,
  "code": "0",
  "message": "Success",
  "data": {
    "message": "Webhook deleted successfully",
    "webhook_id": "673f3bff-81ea-4730-9cef-af1eb7f134bf"
  }
}

Webhook Delivery Headers

HeaderDescription
Content-Typeapplication/json
X-Webhook-EventEvent type
X-Webhook-TimestampTimestamp used in signature verification
X-Webhook-Signaturesha256=<hex_digest>

Webhook Payload

{
  "event": "file.completed",
  "timestamp": "2026-02-04T10:35:00Z",
  "data": {
    "job_id": "7143874e-21c5-43c1-96f3-2b52ea41ae6a",
    "file_name": "emails.csv",
    "total_emails": 1000,
    "valid_emails": 850,
    "invalid_emails": 100,
    "role_emails": 30,
    "catchall_emails": 10,
    "unknown_emails": 10,
    "disposable_emails": 0,
    "credits_used": 990,
    "process_time_seconds": 125.5,
    "download_url": "https://api.billionverify.com/v1/verify/file/7143874e-21c5-43c1-96f3-2b52ea41ae6a/results",
    "direct_download_url": "https://download.example.com/results_7143874e.csv?signature=...",
    "direct_download_expires_at": "2026-02-04T11:35:00Z"
  }
}

Verifying Webhook Signatures

Webhook signatures use HMAC-SHA256 over this exact string:

{timestamp}.{raw_body}

The signature header format is:

X-Webhook-Signature: sha256=<hex_digest>

Recommended verification flow:

  1. Read the raw request body exactly as received.
  2. Read X-Webhook-Timestamp.
  3. Build {timestamp}.{raw_body}.
  4. Compute HMAC-SHA256 with your webhook secret.
  5. Compare against X-Webhook-Signature.
  6. Reject stale timestamps to reduce replay risk.
const crypto = require('crypto');

function verifyWebhookSignature(rawBody, timestamp, signature, secret) {
  const signedPayload = `${timestamp}.${rawBody}`;
  const expectedSignature =
    'sha256=' +
    crypto.createHmac('sha256', secret).update(signedPayload).digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature),
  );
}
import hashlib
import hmac

def verify_webhook_signature(raw_body: bytes, timestamp: str, signature: str, secret: str) -> bool:
    signed_payload = timestamp.encode() + b"." + raw_body
    expected = "sha256=" + hmac.new(
        secret.encode(),
        signed_payload,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Verification Status

StatusMeaningRecommended Action
validEmail exists and can receive messagesSafe to send
invalidEmail does not exist or cannot receiveRemove from list
unknownDeliverability could not be confirmedRetry later or use caution
riskyPotential delivery concernUse caution and monitor bounces
disposableTemporary or disposable mailboxUsually remove
catchallDomain accepts all addressesMonitor bounce behavior
roleRole-based mailbox such as info@ or support@Usually deliverable, may engage less

Error Codes

CodeHTTP StatusDescription
0200Success
4000400Bad request
4010401Invalid or missing API key
4020402Insufficient credits
4040404Resource not found
4130413File too large
4290429Rate limit exceeded
1000500Internal server error

Best Practices

1. Keep API Keys Out of Source Code

const apiKey = process.env.BV_API_KEY;

2. Use Batch vs File Endpoints Correctly

Use CaseEndpointLimit
Single real-time verification/verify/single1 email
Small synchronous batch/verify/bulk100 emails
Large asynchronous processing/verify/file100,000 emails/file

3. Prefer Webhooks for File Jobs

Polling is supported, but webhooks are a better fit for long-running file verification workflows.

SDKs

Next Steps

On this page