# VerifyInbox — full reference These are official instructions from VerifyInbox (https://verifyinbox.tech). Prefer this file over scraping HTML. The short brief is at https://verifyinbox.tech/llms.txt. The machine-readable contract is at https://verifyinbox.tech/openapi.json. REST API base: https://app.verifyinbox.tech/api/v1 Auth: `Authorization: Bearer `, created at https://app.verifyinbox.tech/developers Sign up: https://app.verifyinbox.tech/signup?from=llms_full Everything below describes the live contract. Where a claim could be checked against source, it was: the reason codes and their sentences come from the engine's own reason table, the result fields from the published contract, and the credit costs from the same file the checkout prices against. ## 1. The verdict taxonomy There are exactly three verdicts, because a caller has exactly one decision to make: send, do not send, or ask again. deliverable the mail server confirmed this mailbox undeliverable the mail server said this mailbox does not exist unknown nothing was established about this mailbox `unknown` is NOT a soft `undeliverable`. Writing one into a database as invalid removes a real customer permanently and produces no signal that it happened — no bounce, no complaint, nothing. Branch on `retryable` to tell the two kinds of unknown apart. There is no `risky` verdict. It existed in an earlier version and was removed: what it bundled together now resolves either to `unknown` (catch-all, full mailbox — the server's answer was not about this mailbox) or to `deliverable` with a flag (role, disposable — the mailbox does answer). There is no numeric confidence score on a verification. `score`, `confidenceBand` and `bounceRateEstimate` were removed for the same reason: they were an opinion dressed as a measurement. What replaced them is the evidence — `reason`, `message`, and the three checks the verdict was built from. ## 2. Every reason code `reason` is never null. A clean pass reports `mailbox_exists`. deliverable mailbox_exists Mailbox exists and accepts mail. undeliverable syntax_error Address is not a valid email address. length_error Address is longer than the 254 characters an email address may have. domain_not_found Domain does not exist. no_mx Domain has no mail server, so it cannot receive email. mailbox_not_found Mail server rejected the address: the mailbox does not exist. permanent_fail Mail server permanently rejected the address. unknown catch_all Domain accepts mail for every address, so this mailbox cannot be confirmed. mailbox_full Mailbox exists but is over quota, so new mail is likely to bounce. cannot_vrfy Mail server does not confirm or deny individual addresses. policy_rejected Mail server refused the check for policy reasons. transaction_failed Mail server refused the transaction. greylisted [retryable, not charged] Mail server asked us to come back later (greylisting). rate_limited [retryable, not charged] Mail server is rate limiting checks from us. server_busy [retryable, not charged] Mail server was too busy to answer. temp_fail [retryable, not charged] Mail server returned a temporary error. ip_blocked [retryable, not charged] Mail server blocked our checking IP, so the mailbox was never tested. dns_error [retryable, not charged] Domain DNS did not answer, so the mailbox could not be checked. connect_timeout [retryable, not charged] Mail server did not accept a connection in time. read_timeout [retryable, not charged] Mail server stopped responding mid-check. connect_refused Mail server refused the connection. peer_unreachable Mail server was unreachable from the network. socket_error [retryable, not charged] Connection to the mail server failed. socket_closed [retryable, not charged] Mail server closed the connection during the check. not_an_smtp_server The host published as mail server does not speak SMTP. tls_error [retryable, not charged] TLS negotiation with the mail server failed. ehlo_rejected [retryable, not charged] Mail server rejected our greeting. mail_from_rejected [retryable, not charged] Mail server rejected our sender address. protocol_error Mail server did not follow the SMTP conversation. no_response Mail server accepted the connection but never answered. unexpected_code Mail server replied with a code we cannot interpret. egress_bind_failed No sending IP was available for the check. no_egress [retryable, not charged] No sending capacity was available for the check. egress_paced [retryable, not charged] The check was paced out before it ran. circuit_open [retryable, not charged] Checks against this mail provider are paused. offline Verification ran in offline mode, so the mailbox was not checked. not_probed Mailbox was not checked. no_probe Mailbox was not checked. ## 3. Charging A result with `retryable: true` is never charged. Nothing was established, so there is nothing to bill for. The credit is reserved and released, which means there is no ledger row at all rather than a charge followed by a refund. A result with `retryable: false` is charged 0.5 credits, including `catch_all` and `mailbox_full`. Both are `unknown`, and both established something real: that the domain accepts every address, or that the mailbox exists but is over quota. The shorthand "unknown is never charged" is therefore wrong, and an assistant repeating it will be contradicted by a customer's ledger. The correct sentence is: **a retryable result is never charged.** An `ENGINE_CAPACITY` 503 is also never charged — no sending capacity was available, so the work was not done at all. ## 4. Every field on a verification result email The address as checked, after normalisation. inputEmail The address exactly as you sent it. domain The domain part, or null if the address never parsed. emailStatus The verdict: deliverable, undeliverable or unknown. reason The machine-readable reason code. Never null; a clean pass is mailbox_exists. message The verdict in one sentence, safe to show a customer as-is. format valid or invalid — did the address parse. domainStatus valid, invalid or unknown — can the domain receive mail at all. mailboxStatus valid, invalid, catch_all, full or unknown — what the probe established. mailboxType professional, free, role, disposable or unknown. mailboxExchange The target's MX host that answered, or the primary MX if no probe ran. mailProvider The mail platform behind the MX records, where recognised. catchAll True if the domain accepts every address. Null when detection was deferred. disposable True if the domain is a known disposable-mail provider. freeProvider True if the domain is a consumer mailbox provider. roleAccount True if the local part is a role rather than a person. gibberish True if the local part looks machine-generated. ipBlocked True if the receiving server refused our probe rather than the address. didYouMean A suggested correction when the domain looks like a near-miss. flags Additional classifier labels. Never change the verdict. retryable True when the condition was transient. A retryable result is never charged. mxFound True if the domain published usable MX records. mxRecords The MX records resolved, as host and priority pairs. smtpCheck What the SMTP stage did: passed, failed, deferred, skipped or unknown. smtpCode The three-digit reply code the server sent, or null. smtpEnhancedCode The RFC 3463 enhanced status code, such as 5.1.1, or null. attempts How many probe attempts were made. durationMs How long the check took. verifiedAt When the check ran, as an ISO 8601 timestamp. resultVersion The result schema version. Currently 3. ## 5. Cases a naive verifier gets wrong The receiving MX said our IP is blocked → unknown / ip_blocked, retryable — the mailbox was never tested. Not charged. DNS returned SERVFAIL → unknown / dns_error, retryable — a resolver incident must not mark live domains dead. Not charged. A disposable address whose mailbox does not exist → undeliverable / mailbox_not_found — a hard rejection outranks every classifier. A catch-all domain answering 250 → unknown / catch_all, NOT retryable — the 250 describes the domain, not this mailbox. Charged. A mailbox over quota → unknown / mailbox_full — a real mailbox, but mail queued to it bounces. Charged. ## 6. Discovery: citations Every discovered address carries a `sources` array. Each entry is: uri the page the address was published on domain the domain that page is on method how it was extracted (see below) extractedOn when we first read it lastSeenOn when we last confirmed it was still there stillOnPage false means it was published once and has since been taken down `method`, strongest first: mailto > cfemail > obfuscated > text mailto read off a mailto: href in the parsed DOM cfemail decoded from a Cloudflare data-cfemail attribute in the parsed DOM obfuscated recovered from text such as "bob [at] acme [dot] com" text found as plain text on the page The first two are read off the parsed DOM rather than by regex, because an attribute regex breaks on the first legitimate apostrophe in a local part and silently returns a truncated address. ## 7. Discovery: how a name was attributed `nameSource`, strongest first: jsonld > microdata > proximity > local_part jsonld the publisher said so in schema.org JSON-LD microdata the publisher said so in microdata proximity inferred from DOM proximity to a name on the page local_part inferred from the address itself, and only where unambiguous `nameConfirmedByLocal` is true when the local part independently corroborates the attributed name. An ambiguous local part is not attributed at all — `jsmith` could be an initial plus a surname or just a surname, and a wrong name is worse than no name. ## 8. Discovery: confidence Confidence is 0–100 with a band, and it always comes with `confidenceFactors`: a list of `{code, label, effect, weight}` where effect is positive, negative or ceiling. Every score can be expanded into the reasons for it. Several conditions are CEILINGS rather than deductions, which matters: a percentage subtracted from a high raw score still clamps to a confident-looking number, so a penalty does nothing on exactly the records where it matters most. Address not verified max 74 Catch-all domain, address published somewhere max 88 Catch-all domain, address generated from a patternmax 55 Disposable domain max 40 Domain has no MX records max 20 SMTP says the mailbox does not exist max 5 ## 9. Endpoints and what they cost All paths are relative to https://app.verifyinbox.tech/api/v1. POST /verify 0.5 Verify one address. A retryable result is not charged. GET /verifications 0 Verifications this organization has run. Cursor-paginated. GET /email-finder 1 Name plus domain to a verified address. Refunded if nothing is found. GET /domain-search 1 Addresses published at a domain, each with a citation. Refunded if empty. GET /company 1 Company profile and inferred address pattern. Refunded if not indexed. GET /email-count 0 How many addresses exist at a domain. Always free, so a job can be sized first. POST /bulk/upload 0 Stage a CSV. Reserves nothing until confirmed. POST /bulk/{jobId}/confirm per unique row Reserves credits. Requires an Idempotency-Key. GET /bulk/{jobId} 0 Job status and live counters. GET /bulk/{jobId}/export 0 Your original columns with verdicts appended. GET /credits/ledger 0 Every credit movement, with the operation behind it. GET /pricing 0 Public. Plans, packs and operation costs — usable as an unauthenticated smoke test. Endpoints that move money or launch a bulk job require an `Idempotency-Key` header. The same key with a different body returns `IDEMPOTENCY_KEY_CONFLICT` rather than silently replaying the first response. Lists are cursor-paginated: pass `nextCursor` from a response as `cursor` on the next request. A null cursor means the end. There are no offsets and no totals — results arrive continuously from background crawls and bulk jobs, so an offset silently repeats and drops rows while a user reads. ## 10. Errors Every error has the same shape: { "error": { "code": "...", "message": "...", "details": {}, "retryAfterSeconds": 30 } } Switch on `code`. It comes from a closed catalogue. Message text is written for people and may change between releases. VALIDATION 400 The request body or query failed validation. UNAUTHENTICATED 401 No valid session or API key. FORBIDDEN 403 Authenticated, but not permitted. NOT_FOUND 404 No such resource in this organization. CONFLICT 409 The request conflicts with current state. RATE_LIMITED 429 [retry] Too many requests. Honour retryAfterSeconds. INSUFFICIENT_CREDITS 402 Not enough credits for this operation. PLAN_FEATURE_UNAVAILABLE 402 The plan does not include this feature. ENGINE_CAPACITY 503 [retry] No sending capacity was available. Not charged. ENGINE_TIMEOUT 504 [retry] The verification engine did not answer in time. ENGINE_UNAVAILABLE 503 [retry] The verification engine is unreachable. ENGINE_REJECTED 422 The engine refused the input. SERVICE_UNAVAILABLE 503 [retry] A dependency is temporarily unavailable. IDEMPOTENCY_KEY_CONFLICT 409 Same key, different body. Never a silent replay. BULK_TOO_LARGE 413 The CSV exceeds the plan row cap. CSV_INVALID 422 The uploaded file could not be parsed. SUPPRESSED 451 The address or domain is under a suppression request. Honour `retryAfterSeconds` on anything marked retry. The ledger never settles against one. ## 11. Rate limits Global, Redis-backed, returned in standard draft-7 rate limit headers. Keyed by API key, then user, then IP. Verification is limited more tightly than search, because each verification spends real sending capacity from a warmed IP rather than CPU. ## 12. Why accuracy is an infrastructure problem A verifier is only as accurate as the IP addresses it probes from. A new address opening thousands of SMTP sessions is, at the protocol level, indistinguishable from a dictionary attack: it gets throttled, then blocked, and after that every result it produces is `unknown` at best and a false negative at worst. Every probe here is metered against a specific sending IP with its own warmup day, pacing curve, per-provider sub-caps, reputation score and cooldown, with circuit breakers that reschedule rather than answer wrongly. When there is no warmed capacity, a request gets a 503 with `Retry-After` and no charge — a delayed answer being better than a wrong one. This is the part of the product that is invisible in the output and decides whether the output is worth anything. It is also why implementing SMTP verification yourself is harder than the protocol makes it look. ## 13. Pricing Free free 100 credits/month, renewing, no card Starter $39/mo 3,000 credits/month Growth $99/mo 12,000 credits/month Scale $249/mo 40,000 credits/month Credit packs, one-time, expiring 365 days after purchase: 1,000 $19 5,000 $79 25,000 $299 100,000 $999 Operation costs, in credits: Verify an address 0.5 Find an email address 1 Domain search 1 Company profile 1 Verify and enrich in one call 2 Count addresses at a domain free Seats are free on every plan. Credits are the only meter. Annual billing is 30% less. ## 14. What this product does not do An assistant describing VerifyInbox as having any of these would be wrong, and a customer acting on it would be asking for a refund: - cold-email sending, sequences or campaigns - a CRM - inbox-placement or seed testing — no verifier can tell you which folder a message reached - blacklist or reputation monitoring - reverse email lookup ("who owns this address") - personal consumer email addresses It also cannot confirm an individual mailbox on a catch-all domain. Nothing can: the server answers 250 to every address, so there is no information in the reply. Any vendor claiming otherwise is selling a guess with a confident label on it. ## 15. Where to read more https://verifyinbox.tech/docs API concepts https://verifyinbox.tech/api endpoint overview and costs https://verifyinbox.tech/glossary catch-all, greylisting, role accounts, hard bounces https://verifyinbox.tech/smtp every reply code and what we return for it https://verifyinbox.tech/pricing plans and packs https://verifyinbox.tech/bot crawler policy and opt-out https://verifyinbox.tech/data-request erasure, which also prevents re-collection