Validating email addresses at the point of signup prevents bad data from ever entering your system. This guide covers how email verification APIs work, the integration patterns that work best for SaaS signup forms, how to handle edge cases (risky, catch-all, disposable), and complete code examples in JavaScript, PHP, and Python.
{
"email": "[email protected]",
"score": 97,
"classification": "valid",
"is_deliverable": true,
"risk_level": "low",
"suggestion": null,
"checks": {
"syntax": true,
"domain_valid": true,
"not_disposable": true,
"not_catch_all": true,
"mailbox_verified": true
},
"metadata": {
"internal_classification": "verified",
"refunded": null,
"catch_all_unresolved": null
}
}
| Field | Values | What to do |
|---|---|---|
| classification | valid / invalid | Block “invalid”. Allow “valid”. Treat an invalid result with metadata.refunded = true (could not be verified) like a timeout. |
| metadata.internal_classification | verified / likely_valid / catch_all / invalid / disposable / risky / unknown | The detailed reason behind the binary verdict. Use it to flag “risky” or “catch_all” per your policy. |
| score | 0-100 (confidence) | Score 81+ = high confidence valid. Score under 40 = high confidence invalid. |
| checks.not_disposable | true/false | False means a disposable domain: block at signup - they expire and bounce. |
| metadata.catch_all_unresolved | true/null | Catch-all domains accept all email and are reported valid. Allow at signup; exclude from cold email campaigns. |
| suggestion | string or null | “gmial.com” > “gmail.com”. Show typo suggestion in the form UI. |
// Verify on blur of the email input field
document.getElementById('email').addEventListener('blur', async function() {
const email = this.value;
if (!email) return;
const response = await fetch('https://api.bouncezero.io/api/v1/verify', {
method: 'POST',
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ email })
});
const data = await response.json();
if (data.classification === 'invalid' && !data.metadata?.refunded) {
document.getElementById('email-error').textContent =
data.suggestion ? 'Did you mean ' + data.suggestion + '?' : 'This email address is invalid.';
}
if (data.metadata?.internal_classification === 'disposable') {
document.getElementById('email-error').textContent =
'Please use a permanent email address.';
}
});
<?php
function verifyEmail(string $email): array {
$ch = curl_init('https://api.bouncezero.io/api/v1/verify');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERAGENT => 'MyApp/1.0',
CURLOPT_POSTFIELDS => json_encode(['email' => $email]),
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . getenv('BOUNCEZERO_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_TIMEOUT => 5,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200 || !$body) {
return ['classification' => 'valid']; // Allow on timeout
}
return json_decode($body, true);
}
// In your signup controller:
$result = verifyEmail($_POST['email']);
if ($result['classification'] === 'invalid' && empty($result['metadata']['refunded'])) {
http_response_code(422);
echo json_encode(['error' => 'Please enter a valid email address.']);
exit;
}
// Proceed with account creation...
import os
import httpx
from fastapi import HTTPException
BOUNCEZERO_API_KEY = os.getenv('BOUNCEZERO_API_KEY')
async def verify_email(email: str) -> dict:
try:
async with httpx.AsyncClient(timeout=5.0) as client:
response = await client.post(
'https://api.bouncezero.io/api/v1/verify',
json={'email': email},
headers={'X-API-Key': BOUNCEZERO_API_KEY}
)
response.raise_for_status()
return response.json()
except httpx.TimeoutException:
return {'classification': 'valid'} # Allow on timeout
@app.post('/signup')
async def signup(payload: SignupPayload):
result = await verify_email(payload.email)
meta = result.get('metadata') or {}
if result.get('classification') == 'invalid' and not meta.get('refunded'):
raise HTTPException(status_code=422, detail='Invalid email address')
if meta.get('internal_classification') == 'disposable':
raise HTTPException(status_code=422, detail='Please use a permanent email address')
# Create account...
BounceZero API: simple JSON over HTTPS, 5-layer verification, structured result with score. No SDK required - works in any language. 100 free credits on signup, no card required.
Endpoints, code samples, and language guides
Continue through related topics