This guide covers how to integrate BounceZero’s email verification API in Python - from a simple synchronous requests call to async batch verification with httpx, Flask/Django integration patterns, and error handling for production use.
import requests
API_KEY = "YOUR_BOUNCEZERO_API_KEY"
BASE_URL = "https://api.bouncezero.io/v1"
def verify_email(email: str) -> dict:
"""Verify a single email address and return the full result."""
response = requests.post(
f"{BASE_URL}/verify",
json={"email": email},
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=10
)
response.raise_for_status()
return response.json()
def is_safe_to_send(email: str) -> bool:
"""Return True only if the email is valid and non-disposable."""
result = verify_email(email)
if result["result"] == "invalid":
return False
if result.get("is_disposable"):
return False
# Accept valid and high-confidence catch-all
if result["result"] == "catch-all" and result.get("score", 0) < 70:
return False
return True
# Usage
if is_safe_to_send("[email protected]"):
print("Safe to send")
else:
print("Suppress this email")
The result field returns: valid, invalid, catch-all, disposable, or unknown. The score field (0-100) rates catch-all confidence - 70+ is safe to send.
import asyncio
import httpx
API_KEY = "YOUR_BOUNCEZERO_API_KEY"
BASE_URL = "https://api.bouncezero.io/v1"
CONCURRENCY = 10 # max concurrent requests (respect rate limits)
async def verify_email_async(client: httpx.AsyncClient, email: str) -> dict:
response = await client.post(
f"{BASE_URL}/verify",
json={"email": email},
headers={"Authorization": f"Bearer {API_KEY}"},
)
response.raise_for_status()
data = response.json()
return {"email": email, **data}
async def verify_batch(emails: list[str]) -> list[dict]:
sem = asyncio.Semaphore(CONCURRENCY)
async def bounded_verify(client, email):
async with sem:
try:
return await verify_email_async(client, email)
except Exception as e:
return {"email": email, "result": "error", "error": str(e)}
async with httpx.AsyncClient(timeout=15) as client:
tasks = [bounded_verify(client, email) for email in emails]
return await asyncio.gather(*tasks)
# Usage
emails = ["[email protected]", "[email protected]", "[email protected]"]
results = asyncio.run(verify_batch(emails))
for r in results:
status = r.get("result", "error")
print(f"{r['email']}: {status}")
The semaphore limits concurrency to 10 requests at a time. For lists over 500 emails, the bulk upload endpoint (section 3) is faster and more efficient.
import csv
import asyncio
import httpx
API_KEY = "YOUR_BOUNCEZERO_API_KEY"
async def verify_csv(input_path: str, output_path: str):
# Read emails from CSV
emails = []
with open(input_path, newline="") as f:
reader = csv.DictReader(f)
fieldnames = reader.fieldnames or []
rows = list(reader)
for row in rows:
emails.append(row.get("email", ""))
# Verify all emails
from verify_email_async import verify_batch # import from section 2
results = await verify_batch(emails)
result_map = {r["email"]: r for r in results}
# Write enriched CSV
out_fields = list(fieldnames) + ["bz_result", "bz_score", "bz_is_disposable"]
with open(output_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=out_fields)
writer.writeheader()
for row in rows:
email = row.get("email", "")
res = result_map.get(email, {})
row["bz_result"] = res.get("result", "")
row["bz_score"] = res.get("score", "")
row["bz_is_disposable"] = res.get("is_disposable", "")
writer.writerow(row)
print(f"Written {len(rows)} rows to {output_path}")
asyncio.run(verify_csv("leads.csv", "leads_verified.csv"))
This appends three columns to the existing CSV: bz_result, bz_score, and bz_is_disposable. Filter rows where bz_result == "invalid" before loading to your sequencer.
from flask import Flask, request, jsonify
import requests, os
app = Flask(__name__)
API_KEY = os.environ["BOUNCEZERO_API_KEY"]
@app.route("/register", methods=["POST"])
def register():
email = request.json.get("email", "").strip()
# Verify email before creating account
try:
res = requests.post(
"https://api.bouncezero.io/v1/verify",
json={"email": email},
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=5
).json()
except Exception:
# Fail open: allow registration if API is unavailable
res = {}
if res.get("result") == "invalid":
return jsonify({"error": "Invalid email address."}), 422
if res.get("is_disposable"):
return jsonify({"error": "Disposable emails are not allowed."}), 422
# Create user account...
return jsonify({"status": "ok"}), 201
Note the fail open pattern: if the API call fails (timeout, network error), registration proceeds. This prevents the verification API from becoming a hard dependency that breaks signup. Log failures for monitoring.
| Field | Type | Description |
|---|---|---|
| result | string | Classification: valid | invalid | catch-all | disposable | unknown |
| score | int 0-100 | Confidence score - especially useful for catch-all decisions |
| is_disposable | boolean | True if the domain is a known disposable email provider |
| is_role | boolean | True if the local part is role-based (info, admin, sales, etc.) |
| mx_found | boolean | True if the domain has valid MX records |
| smtp_valid | boolean | True if the SMTP RCPT TO response was positive |
New to verification? Start with the complete email verification guide.
Use the BounceZero API with Python’s requests library: response = requests.post(‘https://api.bouncezero.io/v1/verify’, json={‘email’: email}, headers={‘Authorization’: ‘Bearer YOUR_KEY’}). The result contains ‘result’ (valid/invalid/catch-all/disposable/unknown), ‘is_disposable’, ‘is_role’, and ‘score’ fields. For async code, use httpx.AsyncClient.
For lists under 500 emails, use asyncio + httpx with a semaphore (CONCURRENCY = 10) to make concurrent API calls. For 1,000+ emails, use the bulk upload API endpoint - upload CSV, poll for completion, download enriched results.
For synchronous verification: requests (pip install requests). For async: httpx (pip install httpx) and asyncio (standard library). For CSV handling: pandas or the built-in csv module. No other dependencies needed for BounceZero API integration.
100 free credits on every account. No credit card required. Full API docs available after signup.
Ayoub built BounceZero's 5-stage validation pipeline, its dedicated BGP-announced IP infrastructure, and the Patroni HA PostgreSQL cluster behind every verification. Previously built high-volume email delivery infrastructure. Trained at 1337 Benguerir (École 42 network, 2019). Open-source: bgp_analyzer.
Verify your list before loading it into your sending platform
All tool integrations + workflow guide in one place
Clean lists before every campaign - keep domains alive
Stop bounces before Lemlist flags your account
Protect shared inbox pools from dirty lists
Apollo accuracy is 70-85% - BounceZero catches the rest
Add verification after any enrichment waterfall
Explore other topics