What error code does the API return when out of credits?
When your Valid Email Checker account hits zero credits across every bucket, the API stops accepting new verification requests and responds with HTTP 402 Payment Required. The error body identifies the cause as Insufficient credits and includes your current balance so you can log it and decide what to do next.
The exact response shape
{
"error": "Insufficient credits",
"current_balance": 0,
"message": "Please purchase more credits to continue"
}| Field | Type | Meaning |
|---|---|---|
error | string | Always "Insufficient credits". Stable across releases; safe to match on. |
current_balance | number | Total credits across all buckets at the moment the request was rejected. Will be 0 most of the time; occasionally 1 or 2 for a request that needed more than the residual. |
message | string | Human-readable hint. Do not match on the exact string; it may evolve. |
When does this fire?
/verify-singlerequest when your total balance is below 1 credit./verify-bulkrequest when your total balance is below the email count in the request. For example, submitting 500 emails with only 200 credits triggers 402 immediately — the entire bulk is rejected, no partial deduction.- Mid-flight on a bulk task in progress, the background worker pauses the task and surfaces an out-of-credits state on the next
get-resultspoll. The task stays paused until you top up; you can also cancel it from the dashboard.
Why 402 and not 403?
HTTP 402 (Payment Required) was reserved in the original spec for exactly this situation — a request that would succeed except the caller has not paid enough. Most APIs that hit this scenario use either 402 or 429 in practice. Valid Email Checker uses 402 because it signals a billing condition (top up to fix) rather than an abuse condition (back off and retry). The distinction matters when your client-side retry logic decides what to do next.
How to handle 402 in client code
const response = await fetch(
'https://app.validemailchecker.com/api/verify-single',
{ /* ...headers and body... */ }
);
if (response.status === 402) {
const data = await response.json();
// Do NOT retry immediately — top-up is required first.
notifyAdminToTopUp(data.current_balance);
pauseIntegrationUntilCreditsAvailable();
return;
}Two things to avoid:
- Do not retry the request in a tight loop — the balance will not change without human intervention.
- Do not silently swallow the error. Surface it to whoever owns the integration so they can top up before the queue backs up.
Setting up a low-balance alert
Credits-used response field on success
On a successful /verify-single response, the body includes credits_used: 1. If you want to track running balance client-side, decrement your local counter on every successful call and use the dashboard Credits History as the periodic source of truth. The exact remaining balance after a request is not echoed in the response; query the dashboard or build a lightweight Supabase view if you need it programmatically.
What does NOT trigger 402
- Rate limits — those return 429. See what error code when rate-limited.
- A revoked or suspended key — that returns 403. See revoked-key error.
- An
unknownverification result — that refunds the credit automatically, so it stays a 200 OK response withcredits_used: 0.
Next steps
Related questions
Still stuck? Email support
