Verification API
One endpoint. Send an email, get a verdict. Same engine as the dashboard — mailbox-level SMTP checks included. 1 credit per call; unknown results are refunded automatically.
Quickstart
- Create an account — 100 free credits, no card.
- Dashboard → API keys → create a key. You'll see the full key exactly once.
- Call the endpoint. That's the whole API.
Authentication
Bearer token in the Authorization header. Keys look like nb_live_1a2b3c4d_… — we store only a SHA-256 hash, so save the plaintext when you create it.
Request
POST /api/v1/verify
curl -X POST https://null-bounce.com/api/v1/verify \
-H "Authorization: Bearer nb_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "dana@acmefoundry.com"}'const res = await fetch("https://null-bounce.com/api/v1/verify", {
method: "POST",
headers: {
Authorization: "Bearer nb_live_YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({ email: "dana@acmefoundry.com" }),
});
const { result } = await res.json();
if (result.status === "valid") {
console.log("safe to send:", result.email);
} else if (result.didYouMean) {
console.log("typo? try:", result.didYouMean);
}import requests
res = requests.post(
"https://null-bounce.com/api/v1/verify",
headers={
"Authorization": "Bearer nb_live_YOUR_KEY",
"Content-Type": "application/json",
},
json={"email": "dana@acmefoundry.com"},
)
res.raise_for_status()
result = res.json()["result"]
print(result["status"], result["score"])Body: { "email": "…" } — one address per call, max 254 chars. Bulk belongs in the dashboard (CSV up to 50,000 rows) or your own batching against this endpoint.
Response
{
"result": {
"email": "dana@acmefoundry.com",
"normalized": "dana@acmefoundry.com",
"status": "valid",
"subStatus": "mailbox_exists",
"score": 1,
"didYouMean": null,
"freeProvider": false,
"roleAccount": false,
"disposable": false,
"mx": ["mx1.acmemail.net", "mx2.acmemail.net"],
"reason": "mailbox confirmed via SMTP handshake"
}
}- status
- valid · invalid · risky · unknown · do_not_mail
- score
- 0–1 confidence the mailbox can receive mail
- didYouMean
- Suggested correction when the domain looks like a typo
- mx
- Mail exchangers found for the domain
- freeProvider / roleAccount / disposable
- Classification flags
- reason
- Human-readable explanation of the verdict
Verdict statuses
| Status | Meaning | Send? |
|---|---|---|
| valid | Mailbox confirmed via SMTP handshake | Yes |
| invalid | Syntax, dead domain, or rejected mailbox | No |
| risky | Catch-all / implicit-MX / typo-suspect | Your call |
| unknown | Server refused to answer (greylist, block) | Refunded |
| do not_mail | Deliverable but disposable or role account | No |
Errors
| HTTP | Code | When |
|---|---|---|
| 401 | unauthorized | Missing/invalid API key or session. |
| 402 | insufficient_credits | Balance is 0. Top up in the dashboard. |
| 422 | invalid_input | Body failed validation. Message says what's wrong. |
| 429 | rate_limited | Too many requests. Check Retry-After header. |
| 503 | engine_unavailable | Engine temporarily down. Credit refunded — retry safely. |
Rate limits
API keys: 60 requests/minute burst, sustained load spreads automatically. Anonymous demo widget: 5 checks/day per IP. On 429, honorRetry-After.