BillionVerify Python SDK
Official Python SDK for the BillionVerify email verification API.
PyPI: https://pypi.org/project/billionverify/ Documentation: https://billionverify.com/docs
Installation
pip install billionverify
Quick Start
from billionverify import BillionVerify
client = BillionVerify(api_key="your-api-key")
# Verify a single email
result = client.verify("user@example.com")
print(result.status) # 'valid', 'invalid', 'unknown', 'risky', 'disposable', 'catchall', 'role'
print(result.is_deliverable) # True or False
Configuration
client = BillionVerify(
api_key="your-api-key", # Required
base_url="https://api.billionverify.com/v1", # Optional
timeout=30.0, # Optional: Request timeout in seconds (default: 30)
retries=3, # Optional: Number of retries (default: 3)
)
Single Email Verification
Uses the /verify/single endpoint:
result = client.verify(
email="user@example.com",
check_smtp=True, # Optional: Perform SMTP verification (default: True)
force_refresh=False, # Optional: Bypass cache and force live verification (default: False)
include_domain_reputation=False, # Optional: Include domain reputation details (default: False)
)
# Flat response structure
print(result.email) # 'user@example.com'
print(result.status) # 'valid', 'invalid', 'unknown', 'risky', 'disposable', 'catchall', 'role'
print(result.score) # 0.95
print(result.is_deliverable) # True
print(result.is_disposable) # False
print(result.is_catchall) # False
print(result.is_role) # False
print(result.is_free) # True
print(result.domain) # 'example.com'
print(result.reason) # 'Valid email address'
print(result.check_smtp) # True (whether SMTP was performed)
print(result.domain_suggestion) # None or suggested domain correction
print(result.credits_used) # 1
# Response metadata for audit logs and throttled runners
print(result.response_metadata.request_id) # Server X-Request-ID
print(result.response_metadata.rate_limit_remaining) # Remaining requests in current window
Bulk Email Verification (Synchronous)
Verify up to 50 emails synchronously using verify_bulk():
# Synchronous bulk verification (max 50 emails)
response = client.verify_bulk(
emails=["user1@example.com", "user2@example.com", "user3@example.com"],
check_smtp=True, # Optional
)
# Returns BulkVerifyResponse directly
print(f"Total: {response.total_emails}")
print(f"Credits used: {response.credits_used}")
for result in response.results:
print(f"{result.email}: {result.status}")
print(f" Deliverable: {result.is_deliverable}")
print(f" Disposable: {result.is_disposable}")
print(f" Catchall: {result.is_catchall}")
print(f" Role: {result.is_role}")
File Upload (Async Verification)
For large lists, use upload_file() for asynchronous file verification:
# Upload a file for async verification
task = client.upload_file(
file_path="emails.csv",
check_smtp=True,
email_column="email", # Column name for CSV files
preserve_original=True, # Keep original columns in results
)
print(f"Task ID: {task.task_id}")
print(f"Status: {task.status}")
print(f"Estimated count: {task.estimated_count}")
# Get task status (with optional long-polling)
status = client.get_file_task_status(
task_id=task.task_id,
timeout=60, # Long-poll for up to 60 seconds (0-300)
)
print(f"Progress: {status.progress}%")
print(f"Processed: {status.processed_emails}/{status.total_emails}")
# Wait for completion (polling)
completed = client.wait_for_file_task(
task_id=task.task_id,
poll_interval=5.0, # seconds
max_wait=600.0, # seconds
)
# Download results as CSV with optional filters
output_file = client.download_file_results(
task_id=task.task_id,
output_path="results.csv",
valid=True, # Include valid emails
invalid=True, # Include invalid emails
unknown=True, # Include unknown emails
risky=True, # Include risky emails
disposable=True, # Include disposable emails
catchall=True, # Include catch-all emails
role=True, # Include role-based emails
)
print(f"Results saved to: {output_file}")
Async Support
import asyncio
from billionverify import AsyncBillionVerify
async def main():
async with AsyncBillionVerify(api_key="your-api-key") as client:
# Single verification
result = await client.verify("user@example.com")
print(result.status)
# Bulk verification
response = await client.verify_bulk([
"user1@example.com",
"user2@example.com"
])
for r in response.results:
print(f"{r.email}: {r.status}")
asyncio.run(main())
Health Check
Check API health status (no authentication required):
health = client.health_check()
print(health.status) # 'ok'
print(health.version) # API version
Credits
credits = client.get_credits()
print(credits.credits_balance) # Available credits
print(credits.credits_consumed) # Credits used
print(credits.credits_added) # Total credits added
print(credits.api_key_name) # API key name
Webhooks
Webhooks support events: file.completed, file.failed
# Create a webhook
webhook = client.create_webhook(
url="https://your-app.com/webhooks/billionverify",
events=["file.completed", "file.failed"],
)
print(f"Webhook ID: {webhook.id}")
print(f"Secret: {webhook.secret}") # Save this for signature verification
# List webhooks
webhooks = client.list_webhooks()
for wh in webhooks:
print(f"{wh.id}: {wh.url}")
# Delete a webhook
client.delete_webhook(webhook.id)
# Verify webhook signature
from billionverify import BillionVerify
is_valid = BillionVerify.verify_webhook_signature(
payload=raw_body,
signature=signature_header,
secret="your-webhook-secret",
)
Error Handling
from billionverify import (
BillionVerify,
BillionVerifyError,
AuthenticationError,
RateLimitError,
ValidationError,
InsufficientCreditsError,
NotFoundError,
TimeoutError,
)
try:
result = client.verify("user@example.com")
except AuthenticationError:
print("Invalid API key")
except RateLimitError as e:
print(f"Rate limited. Retry after {e.retry_after} seconds")
print(f"Request ID: {e.response_metadata.request_id}")
except ValidationError as e:
print(f"Invalid input: {e.message}")
except InsufficientCreditsError:
print("Not enough credits")
except NotFoundError:
print("Resource not found")
except TimeoutError:
print("Request timed out")
except BillionVerifyError as e:
# Catch-all for anything else, including the response-shape codes below.
print(f"{e.code}: {e.message}")
Malformed or empty server responses
The SDK never lets a malformed API reply leak out as a raw KeyError,
TypeError, or json.JSONDecodeError. Empty bodies, null payloads,
non-JSON content, and responses missing required fields are all surfaced
as a typed BillionVerifyError with response_metadata populated, so you
can recover and log the request ID:
error.code |
When it fires |
|---|---|
EMPTY_RESPONSE |
2xx with no body, or envelope {"data": null} |
INVALID_RESPONSE |
Non-JSON body, wrong top-level shape, or missing fields |
try:
result = client.verify("user@example.com")
except BillionVerifyError as e:
if e.code in ("EMPTY_RESPONSE", "INVALID_RESPONSE"):
log.error("bad upstream reply", extra={
"request_id": e.response_metadata.request_id,
"status": e.response_metadata.status_code,
"details": e.details,
})
raise
Context Manager
with BillionVerify(api_key="your-api-key") as client:
result = client.verify("user@example.com")
print(result.status)
# Connection is automatically closed
Type Hints
This SDK includes full type annotations for IDE support and type checking.
from billionverify import (
VerificationResult,
BulkVerifyResponse,
FileUploadResponse,
FileTaskStatus,
CreditsResponse,
VerificationStatus,
)
def process_result(result: VerificationResult) -> None:
if result.status == "valid":
print(f"Email {result.email} is valid")
if result.is_deliverable and not result.is_disposable:
print("Safe to send to this email")
Status Values
The verification status can be one of:
valid- Email is valid and deliverableinvalid- Email is invalid or does not existunknown- Could not determine statusrisky- Email exists but may have delivery issuesdisposable- Temporary/disposable email addresscatchall- Domain accepts all emails (catch-all)role- Role-based email (e.g., info@, support@)
License
MIT
Metadata
Release files for billionverify 1.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| billionverify-1.2.2.tar.gz | 26.3 kB | With provenance | Details for billionverify-1.2.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| billionverify-1.2.2-py3-none-any.whl | Python 3 | none | any | Details for billionverify-1.2.2-py3-none-any.whl |
Total release size: 41.6 kB
Release files / billionverify-1.2.2.tar.gz
| Download URL | billionverify-1.2.2.tar.gz |
|---|---|
| Size | 26.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
72def2affa296ef6ee7eb6232a54cac6e825d29b42e6e77357ef30fd79df8f5d
|
|
BLAKE2b-256 checksum How to use checksums |
9151c325cc9b0cf95e2668f4989ad62285b3185e566163a037859fcae464719a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logRelease files / billionverify-1.2.2-py3-none-any.whl
| Download URL | billionverify-1.2.2-py3-none-any.whl |
|---|---|
| Size | 15.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7fb92d81c925dbaf68b4c7e8afd54d08ed924288a24f7fd708cbc86f36c1842b
|
|
BLAKE2b-256 checksum How to use checksums |
a8d268d61f79dbb7f43b196e38b8f15c1f90a64866ffa978b3eaf344a71df5b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logSecurity for billionverify 1.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for billionverify-1.2.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.