API Reference
Complete email verification API reference. Endpoints, parameters, response codes for email validation.
The BillionVerify API is a RESTful service that provides powerful email verification capabilities. All API requests should be made over HTTPS.
Base URL
https://api.billionverify.com/v1OpenAPI Specification
The complete API specification is available in OpenAPI 3.0 format:
- OpenAPI YAML: https://api.billionverify.com/openapi.yaml
- Interactive API Docs: https://api.billionverify.com/docs
You can import the OpenAPI spec into tools like Postman, Insomnia, or use it to generate client libraries.
Authentication
All API requests require authentication using the BV-API-KEY header:
BV-API-KEY: YOUR_API_KEYGet your API key from the BillionVerify dashboard.
Example
curl -X POST https://api.billionverify.com/v1/verify/single \
-H "BV-API-KEY: sk_your_api_key" \
-H "Content-Type: application/json" \
-d '{"email": "test@example.com"}'Rate Limits
Rate limits are applied per API key, per endpoint type:
| Endpoint | Rate 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 |
Need higher limits? Contact us at support@billionverify.com for unlimited API access or custom rate limits.
When rate limited, you'll receive a 429 Too Many Requests response:
{
"success": false,
"code": "4290",
"message": "Rate limit exceeded",
"error": {
"code": "4290",
"message": "Rate limit exceeded. Please try again later."
}
}Response Format
All API responses follow a consistent format:
{
"success": true,
"code": "0",
"message": "Success",
"data": { ... }
}For errors:
{
"success": false,
"code": "ERROR_CODE",
"message": "Error message",
"error": {
"code": "ERROR_CODE",
"message": "Detailed error message"
}
}Endpoints
Single Email Verification
Verify a single email address with detailed results.
POST /verify/singleRequest
{
"email": "user@example.com",
"check_smtp": true
}Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
email | string | Yes | - | Email address to verify |
check_smtp | boolean | No | true | Perform SMTP mailbox verification |
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,
"domain": "example.com",
"mx_records": ["has_mx_records"],
"domain_reputation": {
"mx_ip": "192.0.2.1",
"is_listed": false,
"blacklists": [],
"checked": true
},
"smtp_check": true,
"reason": null,
"response_time": 450,
"credits_used": 1
}
}Response Fields
| Field | Type | Description |
|---|---|---|
email | string | The verified email address |
status | string | Verification status (see Status Values) |
score | number | Confidence score (0.0 - 1.0) |
is_deliverable | boolean | Whether email can receive messages |
is_disposable | boolean | Whether email is from disposable service |
is_catchall | boolean | Whether domain accepts all emails |
is_role | boolean | Whether email is role-based (info@, support@) |
is_free | boolean | Whether email is from free provider |
domain | string | Email domain |
mx_records | array | MX record status |
domain_reputation | object | Domain blacklist check results |
smtp_check | boolean | Whether SMTP verification was performed |
reason | string | Reason for status (nullable) |
response_time | integer | Verification time in milliseconds |
credits_used | integer | Number of credits consumed |
Batch Email Verification
Verify multiple email addresses synchronously. Best for small batches (up to 50 emails).
POST /verify/bulkRequest
{
"emails": [
"user1@example.com",
"user2@example.com",
"user3@example.com"
],
"check_smtp": true
}Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
emails | array | Yes | - | Array of email addresses (max: 50) |
check_smtp | boolean | No | true | Perform SMTP verification |
Response
{
"success": true,
"code": "0",
"message": "Success",
"data": {
"results": [
{
"email": "user1@example.com",
"status": "valid",
"score": 0.95,
"is_deliverable": true,
"is_disposable": false,
"is_catchall": false,
"is_role": false,
"is_free": false,
"domain": "example.com",
"smtp_check": true,
"reason": null,
"credits_used": 1
}
],
"total_emails": 3,
"valid_emails": 2,
"invalid_emails": 1,
"credits_used": 3,
"process_time": 2500
}
}File Upload Verification
Upload a CSV or Excel file for asynchronous email verification. Best for large lists.
POST /verify/fileRequest
curl -X POST https://api.billionverify.com/v1/verify/file \
-H "BV-API-KEY: sk_your_api_key" \
-F "file=@emails.csv"Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
file | file | Yes | CSV or Excel file (max: 20MB, 100,000 rows) |
email_column | string | No | Column name containing emails (auto-detected if not specified) |
Supported File Formats
- CSV (.csv)
- Excel (.xlsx, .xls)
- Text (.txt) - one email per line
Response
{
"success": true,
"code": "0",
"message": "Success",
"data": {
"task_id": "7143874e-21c5-43c1-96f3-2b52ea41ae6a",
"status": "pending",
"message": "File uploaded successfully, processing started",
"file_name": "emails.csv",
"file_size": 45678,
"estimated_count": 1000,
"unique_emails": 950,
"total_rows": 1000,
"email_column": "email",
"status_url": "/v1/verify/file/7143874e-21c5-43c1-96f3-2b52ea41ae6a",
"created_at": "2026-02-04T10:30:00Z"
}
}Get Job Status
Check the status of a file verification job.
GET /verify/file/{job_id}Response (In Progress)
{
"success": true,
"code": "0",
"message": "Success",
"data": {
"job_id": "7143874e-21c5-43c1-96f3-2b52ea41ae6a",
"status": "processing",
"file_name": "emails.csv",
"total_emails": 1000,
"processed_emails": 450,
"progress_percent": 45,
"valid_emails": 380,
"invalid_emails": 50,
"unknown_emails": 20,
"created_at": "2026-02-04T10:30:00Z"
}
}Response (Completed)
{
"success": true,
"code": "0",
"message": "Success",
"data": {
"job_id": "7143874e-21c5-43c1-96f3-2b52ea41ae6a",
"status": "completed",
"file_name": "emails.csv",
"total_emails": 1000,
"processed_emails": 1000,
"progress_percent": 100,
"valid_emails": 850,
"invalid_emails": 100,
"unknown_emails": 30,
"role_emails": 15,
"catchall_emails": 5,
"disposable_emails": 0,
"credits_used": 970,
"process_time_seconds": 125.5,
"result_file_path": "results/2026/02/04/result_xxx.csv",
"download_url": "/v1/verify/file/7143874e-21c5-43c1-96f3-2b52ea41ae6a/results",
"created_at": "2026-02-04T10:30:00Z",
"completed_at": "2026-02-04T10:32:05Z"
}
}Job Status Values
| Status | Description |
|---|---|
pending | Job is queued |
processing | Job is being processed |
completed | Job finished successfully |
failed | Job failed (see error field) |
Download Results
Download verification results for a completed job.
GET /verify/file/{job_id}/resultsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
valid | boolean | - | Include valid emails |
invalid | boolean | - | Include invalid emails |
catchall | boolean | - | Include catch-all emails |
role | boolean | - | Include role emails |
unknown | boolean | - | Include unknown emails |
Without filter parameters, returns the complete result file. With filters, returns a CSV with matching emails only.
Example: Download Deliverable Emails
curl -o deliverable.csv \
"https://api.billionverify.com/v1/verify/file/{job_id}/results?valid=true&catchall=true&role=true" \
-H "BV-API-KEY: sk_your_api_key"Check Credits
Get current credit balance.
GET /creditsResponse
{
"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
Receive real-time notifications when file verification jobs complete.
Create Webhook
POST /webhooksRequest
{
"url": "https://your-app.com/webhooks/billionverify",
"events": ["file.completed", "file.failed"]
}Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS URL to receive webhook notifications |
events | array | Yes | Events to subscribe to |
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"
}
}Important: The secret is only returned when creating the webhook. Store it securely - you'll need it to verify webhook signatures.
List Webhooks
GET /webhooksResponse
{
"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,
"created_at": "2026-02-04T10:30:00Z",
"updated_at": "2026-02-04T10:30:00Z"
}
],
"total": 1
}
}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 Events
| Event | Description |
|---|---|
file.completed | File verification job completed successfully |
file.failed | File verification job failed |
Webhook Payload
When an event occurs, we send a POST request to your webhook URL:
{
"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,
"result_file_path": "results/2026/02/04/result_xxx.csv",
"download_url": ""
}
}Webhook Headers
| Header | Description |
|---|---|
X-Webhook-Event | Event type (e.g., file.completed) |
X-Webhook-Signature | HMAC-SHA256 signature for verification |
X-Webhook-Timestamp | Unix timestamp when webhook was sent |
User-Agent | BillionVerify-Webhook/1.0 |
Verifying Webhook Signatures
To verify a webhook is from BillionVerify, compute the HMAC-SHA256 signature:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = 'sha256=' +
crypto.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}import hmac
import hashlib
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Verification Status
| Status | Score | Meaning | Recommended Action |
|---|---|---|---|
valid | 0.9+ | Email exists and can receive messages | Safe to send |
invalid | 0.1 | Email doesn't exist or can't receive | Remove from list |
unknown | 0.5 | Could not determine validity | Retry later or use caution |
risky | 0.4 | Email presents potential delivery concerns | Use caution, monitor bounces |
disposable | 0.3 | From disposable email service | Consider removing |
catchall | 0.7 | Domain accepts all emails | Monitor for bounces |
role | 0.6 | Role-based email (info@, support@) | Usually deliverable, may have lower engagement |
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
0 | 200 | Success |
4000 | 400 | Bad Request - Invalid parameters |
4010 | 401 | Unauthorized - Invalid or missing API key |
4020 | 402 | Payment Required - Insufficient credits |
4030 | 403 | Forbidden - Access denied |
4040 | 404 | Not Found - Resource doesn't exist |
4130 | 413 | File too large |
4290 | 429 | Too Many Requests - Rate limit exceeded |
1000 | 500 | Internal Server Error |
Best Practices
1. Use Environment Variables
Never hardcode API keys:
// Good
const apiKey = process.env.BV_API_KEY;
// Bad - don't do this
const apiKey = 'sk_xxx';2. Handle Rate Limits
Implement exponential backoff:
async function verifyWithRetry(email, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await verify(email);
} catch (error) {
if (error.code === '4290') {
await sleep(Math.pow(2, i) * 1000);
continue;
}
throw error;
}
}
}3. Choose the Right Endpoint
| Use Case | Endpoint | Max Emails |
|---|---|---|
| Real-time validation (forms) | /verify/single | 1 |
| Small batch processing | /verify/bulk | 50 |
| Large list verification | /verify/file | 100,000 |
4. Use Webhooks for Large Files
Don't poll constantly; use webhooks:
// 1. Create webhook (once)
const webhook = await client.createWebhook({
url: 'https://your-app.com/webhook',
events: ['file.completed', 'file.failed']
});
// 2. Store the secret securely
saveSecret(webhook.secret);
// 3. Upload file
const job = await client.uploadFile('emails.csv');
// 4. Handle webhook when job completes
app.post('/webhook', (req, res) => {
if (verifySignature(req)) {
const { job_id, total_emails, valid_emails } = req.body.data;
// Process results
}
res.status(200).send('OK');
});SDKs
Use our official SDKs for easier integration: