Batch Email Verification
Verify multiple email addresses asynchronously.
Overview
Batch verification is a 3-step process:
- Upload - Submit emails for verification
- Poll - Check job status until complete
- Download - Retrieve results
Step 1: Upload Emails
Endpoint
POST /api/v1/bulk/upload
Request
{
"emails": [
"user1@example.com",
"user2@example.com",
"user3@example.com"
]
}
| Field | Type | Required | Description |
|---|---|---|---|
emails | array | Yes | Array of email addresses (max 10,000) |
Response
{
"success": true,
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"totalEmails": 3,
"duplicateCount": 0,
"skippedRows": 0,
"emptyRows": 0,
"invalidRows": 0,
"estimatedTimeSeconds": 6
}
Duplicate addresses are removed automatically — you are only charged for unique emails. Verification starts as soon as the upload is accepted.
Code Example
const response = await fetch('https://api.clearbounce.net/api/v1/bulk/upload', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.CLEARBOUNCE_API_KEY
},
body: JSON.stringify({
emails: [
'user1@example.com',
'user2@example.com',
'user3@example.com'
]
})
});
const { jobId } = await response.json();
console.log('Job ID:', jobId);
Step 2: Check Job Status
Endpoint
GET /api/v1/bulk/status/:jobId
Response
{
"success": true,
"job": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing",
"progress": 45,
"totalEmails": 1000,
"processedEmails": 450,
"deliverableCount": 380,
"undeliverableCount": 45,
"riskyCount": 20,
"unknownCount": 5,
"catchAllCount": 12,
"createdAt": "2026-02-03T20:00:00.000Z",
"completedAt": null,
"bounceEstimate": null
}
}
Job Status Values
| Status | Description |
|---|---|
pending | Job is queued |
processing | Verification in progress |
completed | All emails verified |
failed | Job failed (see error) |
Polling Example
async function waitForCompletion(jobId) {
while (true) {
const response = await fetch(
`https://api.clearbounce.net/api/v1/bulk/status/${jobId}`,
{
headers: { 'X-API-Key': process.env.CLEARBOUNCE_API_KEY }
}
);
const { job } = await response.json();
console.log(`Progress: ${job.progress}%`);
if (job.status === 'completed') {
return job;
}
if (job.status === 'failed') {
throw new Error('Job failed');
}
// Wait 5 seconds before polling again
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
Step 3: Download Results
Endpoint
GET /api/v1/bulk/results/:jobId
Results are available once the job status is completed (a 400 JOB_NOT_COMPLETED error is returned before that).
Response
{
"success": true,
"results": [
{
"email": "user1@example.com",
"status": "deliverable",
"subStatus": "accepted_email",
"reason": "accepted_email",
"score": 95,
"isDeliverable": true,
"toxicity": 0,
"meta": {
"provider": "google.com",
"dnsType": "MX"
}
},
{
"email": "user2@example.com",
"status": "undeliverable",
"subStatus": "rejected_email",
"reason": "rejected_email",
"score": 0,
"isDeliverable": false,
"toxicity": 0,
"meta": {
"provider": null,
"dnsType": null
}
},
{
"email": "user3@example.com",
"status": "risky",
"subStatus": "low_quality",
"reason": "low_quality",
"score": 45,
"isDeliverable": false,
"toxicity": 2,
"meta": {
"provider": "example.com",
"dnsType": "MX"
}
}
],
"originalCsvData": null
}
Results come back in the same order as the uploaded list. Each entry is a full verification result object (same shape as the single verification endpoint). To filter by status or export CSV, process the JSON on your side — for example results.filter(r => r.status === 'deliverable').
Complete Example
async function bulkVerify(emails) {
const apiKey = process.env.CLEARBOUNCE_API_KEY;
const baseUrl = 'https://api.clearbounce.net/api/v1';
// Step 1: Upload
console.log(`Uploading ${emails.length} emails...`);
const uploadResponse = await fetch(`${baseUrl}/bulk/upload`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': apiKey
},
body: JSON.stringify({ emails })
});
const { jobId } = await uploadResponse.json();
console.log(`Job created: ${jobId}`);
// Step 2: Poll for completion
let status = 'pending';
while (status !== 'completed' && status !== 'failed') {
await new Promise(resolve => setTimeout(resolve, 5000));
const statusResponse = await fetch(`${baseUrl}/bulk/status/${jobId}`, {
headers: { 'X-API-Key': apiKey }
});
const { job } = await statusResponse.json();
status = job.status;
console.log(`Status: ${status}, Progress: ${job.progress}%`);
}
if (status === 'failed') {
throw new Error('Bulk verification failed');
}
// Step 3: Download results
const resultsResponse = await fetch(`${baseUrl}/bulk/results/${jobId}`, {
headers: { 'X-API-Key': apiKey }
});
const { results } = await resultsResponse.json();
// Summarize results
const summary = {
total: results.length,
deliverable: results.filter(r => r.status === 'deliverable').length,
undeliverable: results.filter(r => r.status === 'undeliverable').length,
risky: results.filter(r => r.status === 'risky').length,
unknown: results.filter(r => r.status === 'unknown').length
};
console.log('Summary:', summary);
return results;
}
// Usage
const emails = [
'user1@example.com',
'user2@example.com',
// ... more emails
];
bulkVerify(emails)
.then(results => console.log('Done!', results.length, 'emails verified'))
.catch(err => console.error('Error:', err));
Limits
| Limit | Value |
|---|---|
| Max emails per request | 10,000 |
| Max concurrent jobs | 5 |
| Job retention | 7 days |
Credits
Batch verification consumes 1 credit per email, same as single verification.