Use the batch API when you need to validate more than a handful of records — list cleanups, CRM imports, bulk signup verification.
Overview
- Upload a CSV → receive a job ID
- Poll
GET /v1/batch/:iduntilstatus=done(or use webhooks) - Download the result CSV from
result_url
CSV format
Single-column, no header, UTF-8:
john@example.com
jane@acme.com
noreply@disposablemail.xyz
Maximum file size: 50 MB. Maximum rows per job: 1,000,000.
Full workflow
import { Checkharbor } from "@checkharbor/node";
import { readFileSync } from "fs";const checkharbor = new Checkharbor({ apiKey: process.env.CHECKHARBOR_API_KEY! });
// 1. Create job from CSV file
const csvContent = readFileSync("emails.csv", "utf-8");
const job = await checkharbor.batch.create({
type: "email",
csvString: csvContent,
webhookUrl: "https://myapp.com/webhook/checkharbor",
});
console.log("Job created:", job.id);
// 2. Poll until done
const done = await checkharbor.batch.waitUntilDone(job.id, {
pollMs: 5000, // check every 5s
timeoutMs: 600_000, // 10 min timeout
});
console.log(`Processed ${done.processed_rows}/${done.total_rows} rows`);
// 3. Download result
const csv = await checkharbor.batch.downloadResult(done);
console.log(csv.slice(0, 200)); // preview
```
import os
from checkharbor import Checkharborclient = Checkharbor(api_key=os.environ["CHECKHARBOR_API_KEY"])
# 1. Create job from CSV file
with open("emails.csv") as f:
job = client.batch.create(
type="email",
csv_string=f.read(),
webhook_url="https://myapp.com/webhook/checkharbor",
)
print("Job created:", job["id"])
# 2. Poll until done
done = client.batch.wait_until_done(
job["id"], poll_seconds=5, timeout_seconds=600
)
print(f"Processed {done['processed_rows']}/{done['total_rows']} rows")
# 3. Download and parse
import csv, io
csv_content = client.batch.download_result(done)
reader = csv.DictReader(io.StringIO(csv_content))
for row in reader:
if row["deliverability"] == "undeliverable":
print("Remove:", row["input"])
```
# 1. Upload
JOB=$(curl -s -X POST https://api.checkharbor.com/v1/batch \
-H "X-Api-Key: chk_live_..." \
-F "type=email" \
-F "file=@emails.csv")
JOB_ID=$(echo $JOB | jq -r '.id')
echo "Job: $JOB_ID"# 2. Poll
while true; do
STATUS=$(curl -s https://api.checkharbor.com/v1/batch/$JOB_ID \
-H "X-Api-Key: chk_live_...")
DONE=$(echo $STATUS | jq -r '.status')
echo "Status: $DONE"
if [ "$DONE" = "done" ]; then break; fi
if [ "$DONE" = "failed" ]; then echo "FAILED"; exit 1; fi
sleep 5
done
# 3. Download
RESULT_URL=$(echo $STATUS | jq -r '.result_url')
curl -o results.csv "$RESULT_URL"
```
Listing your jobs
GET /v1/batch?limit=50 returns your most recent jobs (newest first, max 200). Failed jobs include an error_message field.
Webhook payload
When the job completes, Check Harbor POSTs the BatchJob object to your webhook_url. Every webhook request includes an X-Checkharbor-Signature: sha256=<hex> header — an HMAC-SHA256 of the raw body. Verify it against your batch signing secret to authenticate the request:
{
"id": "job_01HXYZ123",
"status": "done",
"type": "email",
"total_rows": 1000,
"processed_rows": 1000,
"result_url": "https://api.checkharbor.com/v1/batch/job_01HXYZ123/download?sig=...",
"created_at": "2024-06-11T10:00:00Z"
}
The result_url expires after ~1 hour. Download it promptly or re-fetch the job to get a fresh URL.
Result CSV format
The result CSV includes the original value plus all validation fields:
Email batch result:
input,valid_syntax,mx_found,disposable,role_based,free_provider,did_you_mean,deliverability,score,credits_used
john@example.com,true,true,false,false,true,,deliverable,92,1
Phone batch result:
input,valid,e164,country,line_type,carrier,score,credits_used
+905321234567,true,+905321234567,TR,mobile,,90,1
IP batch result:
input,country,city,asn,vpn,proxy,tor,datacenter,abuse_score,credits_used
84.17.45.10,NL,,9009,true,false,false,true,68,1
carrierandcityare currently always empty (country-level geo data; carrier data coming later).
Credit estimation
Credits are deducted upfront at submission (rows × 1 credit). If your balance is insufficient, the upload is rejected with 402 insufficient_credits and nothing is charged. If a job fails mid-run, credits for unprocessed rows are automatically refunded.