Developer docs

Email Verification API

One endpoint, bearer-token auth, JSON in and out. Send an email address, get a disposable / legitimate verdict in milliseconds — from whatever stack you already run.

Sub-100ms p9999.4% accuracy500 free credits

Introduction

The Disposable.Check API tells you, in a single request, whether an email address is disposable — a throwaway, burner, or temporary inbox — or a legitimate address worth keeping in your funnel. It is a JSON-over-HTTPS API: one endpoint, bearer-token auth, no SDK required.

Every verdict flows through a layered cascade — curated allow/deny lists, a global disposable-domains list, a 30-day verdict cache, and finally live heuristics (MX records, local-part entropy, brand similarity, mail-server reputation) with an AI classifier for borderline cases. The response tells you which layer produced the answer via the source field.

Base for every example: a free account ships with 500 credits — no card required. Generate a key from your API Keys dashboard and you can run every snippet below as-is.

Base URL

All requests go to a single HTTPS base. There is no versioned path prefix.

https://api.disposable.check

HTTPS is required; plain-HTTP requests are rejected. All request and response bodies are application/json encoded as UTF-8.

Authentication

Authenticate every request with your team's API key as a bearer token in the Authorization header. Keys are issued per team and can be revoked at any time from the dashboard.

Authorization: Bearer YOUR_API_KEY
  • Treat your key like a password — keep it server-side, in an environment variable, never in client-side code or a public repo.
  • Requests with a missing or malformed header get 401 Unauthorized; an unrecognized key also returns 401.
  • Rotate a key by issuing a new one and revoking the old one from API Keys. Revocation is immediate.

Quickstart

Send a POST with one JSON field — email — and read isDisposable off the response. Pick your language:

request
curl -X POST https://api.disposable.check/api/check-email \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email": "user@mailinator.com"}'

A throwaway address comes back like this:

200 OKresponse
{
  "email": "user@mailinator.com",
  "isDisposable": true,
  "source": "list"
}

Check an email

POST/api/check-email

Evaluates a single email address and returns a disposable verdict. This is the core, metered endpoint — each successful call costs one credit (see Credits & limits).

Request

Headers

HeaderRequiredValue
AuthorizationYesBearer YOUR_API_KEY
Content-TypeYesapplication/json

Body parameters

FieldTypeRequiredDescription
emailstringYesThe full email address to evaluate. Must be syntactically valid (local@domain.tld). Only the domain is used for the verdict — the local part is never stored.

A minimal request body:

200 OKresponse
{ "email": "user@mailinator.com" }

Response

A 200 OK returns a JSON verdict. Which fields are present depends on how the verdict was resolved — email, isDisposable, and source are always there; the rest are added only when a live detection runs.

FieldTypeAlwaysDescription
emailstringYesEcho of the submitted address.
isDisposableboolean | nullYestrue if the address is disposable, false if legitimate, null when the verdict is genuinely unknown.
sourcestringYesWhich cascade layer answered. See Verdict sources.
classificationstringNodisposable, legitimate, or unknown. Present on live/cached verdicts.
confidencenumberNoModel confidence from 0 to 1. Present on live/cached verdicts.
reasonstringNoHuman-readable explanation of the verdict.
signalsobjectNoFeature breakdown behind the verdict (see below). Present on live/cached verdicts.
matchedRuleobjectNoPresent only when one of your team allow/deny rules matched — { kind, value }.

The signals object

FieldTypeDescription
mxValidbooleanThe domain publishes valid MX (mail-exchange) records.
entropynumberShannon entropy of the local part — high values suggest a randomly generated inbox.
levenshteinMatchstring | nullNearest known throwaway-mail brand if the domain is a close lookalike, else null.
mxClusterSuspiciousbooleanThe domain shares mail servers with known disposable providers.

Verdict sources

The source field reports which layer of the detection cascade produced the verdict, in precedence order (earlier layers win):

sourceMeaning
allowlistMatched one of your team allow rules — forced to legitimate.
denylistMatched one of your team deny rules — forced to disposable.
legit-listA curated, globally known-legitimate domain (e.g. gmail.com).
listMatched the curated global disposable-domains list.
cacheA cached result from a recent live detection of this domain.
heuristicResolved live from MX, entropy, brand similarity, and cluster reputation.
llmA borderline case escalated to the AI classifier.

Response examples

Disposable — resolved live (full payload)

200 OKresponse
{
  "email": "user@mailinator.com",
  "isDisposable": true,
  "classification": "disposable",
  "confidence": 0.94,
  "reason": "high-entropy local part; MX cluster flagged disposable",
  "source": "heuristic",
  "signals": {
    "mxValid": true,
    "entropy": 3.7,
    "levenshteinMatch": "mailinator",
    "mxClusterSuspicious": true
  }
}

Legitimate — fast legit-list hit

200 OKresponse
{
  "email": "jane@gmail.com",
  "isDisposable": false,
  "source": "legit-list"
}

Team rule match

When a team allow/deny rule matches, it overrides every other layer:

200 OKresponse
{
  "email": "partner@trusted-partner.com",
  "isDisposable": false,
  "source": "allowlist",
  "matchedRule": { "kind": "domain", "value": "trusted-partner.com" }
}

Errors

Errors use standard HTTP status codes and return a JSON body of the shape { "error": "message" }.

StatusMeaningExample body
200Success — verdict returned.
400Bad request — the email is missing or not a valid address.{ "error": "Invalid email format" }
401Unauthorized — missing/malformed header or unrecognized key.{ "error": "Invalid token" }
402Payment required — the team is out of credits.{ "error": "Insufficient credits" }
500Server error — something failed on our side; safe to retry.{ "error": "Internal server error" }
Heads up: credits are charged before the verdict is resolved, so a 402 still applies even when a team allow-rule would have matched. Top up or wait for your cycle to renew.

Credits & limits

  • One credit per successful call. Every verdict — list hit, cache hit, or full live detection — costs exactly one credit. Errored requests (4xx/5xx) are not charged, except that a 402 is itself the "out of credits" signal.
  • Free tier: 500 credits granted once at signup, no card required.
  • Paid plans grant a monthly credit allotment that resets each billing cycle and does not roll over. See Pricing.
  • Need to check thousands of addresses at once? Use the Bulk Check CSV uploader instead of looping the API — it's billed per unique domain.

Best practices

  • Validate syntax first. Reject obviously malformed input client-side so you don't spend a credit (and a round-trip) on a 400.
  • Branch on isDisposable, not source. The boolean is the contract; source and signals are for logging and tuning your own thresholds.
  • Treat null gracefully. A null verdict means "unknown" — decide whether to allow, soft-flag, or challenge rather than hard-blocking.
  • Handle 402 and retry 5xx. Back off and retry on 500; surface 402 to whoever manages billing.
  • Cache on your side if you re-check the same domains often — verdicts are stable, and it conserves credits.

Support

Questions, edge cases, or a domain you think we're scoring wrong? Reach us through the contact page, and check the API status page for live health.