Skip to content

The public-provider lookup

Terminal window
curl -sS https://api.emvero.tech/v1/public-provider \
-H "Authorization: Bearer emv_your_credential" \
-H "Content-Type: application/json" \
-d '{"domain":"gmail.com"}'
{
"domain": "gmail.com",
"ascii_domain": "gmail.com",
"public_provider": true,
"dataset_version": "2026-08-18.1+ab12cd34ef56"
}

It costs nothing. No credits are spent, no X-Credits-Charged or X-Credits-Remaining is returned, and an empty balance does not refuse it.

It is the cheapest of the three free lookups: an answer from a list held in memory, with no resolver query, no SMTP session and no destination’s patience spent. The catch-all lookup costs one DNS query on a cache miss; this costs not even that.

It still needs a credential, like every other operation. What is free is the answer, not the access.

Not whether the address is free, and not whether the domain receives mail. Whether the domain tells you who the person is.

someone@gmail.com could be anybody. someone@siemens.com works at Siemens. Every domain in the list is one a provider hands out to the general public, so the answer for it is: this one tells you nothing.

This is the whole design and reading it the other way is the mistake worth guarding against.

true establishes something. The domain belongs to a provider that hands mailboxes to anybody who asks - Gmail, Outlook, Posteo, an ISP’s consumer mail. You can act on it.

false establishes nothing. The domain may be an organisation’s own, or it may be one of the long tail of small providers no list reaches. Reading false as this is a work address is the misreading, and there is deliberately no corporate flag in the response for you to read instead - a list of every public provider on earth does not exist, so the field claiming to be its complement would be wrong about exactly the domains you would most want it right about.

The asymmetry is on purpose rather than a gap being closed later. A wrong true tells you an employee’s work address is a personal one, which is a wrong answer with money behind it; a missing entry costs you only the signal. So the list covers the providers people actually use and does not chase the tail.

A Gmail address is a perfectly good address. Nothing here is a defect, and this signal never moves a verdict - the same is true of every risk annotation this service produces.

What it is for is products that treat a personal mailbox differently from a company one: a B2B trial that wants a work address, a sales lead you are about to route, an invoice address. Whether that difference matters is a business decision the field informs rather than makes.

It answers exactly one question, and it is the same signal a verification reports in checks.public_provider, read from the same bundle, so the two cannot disagree.

Everything else a verification establishes is absent:

  • It does not say the domain resolves, publishes mail routing, or accepts mail at all. A domain registered ten minutes ago and pointed nowhere comes back "public_provider": false on the strength of the list alone.
  • It does not say a mailbox exists. Nothing is asked of any destination.
  • It cannot produce a verdict. There is no status, no action and no reason_codes here, because none of them would be earned.
  • It is not the same question as who runs this domain’s mail server. Google runs Gmail and also runs a great deal of corporate mail; google.com itself is not in this list, because that is where Google’s own staff read mail.

Where the answer comes from, and dataset_version

Section titled “Where the answer comes from, and dataset_version”

The list is a reviewed file rather than an assembled one, which is the difference from the disposable lookup. Throwaway providers appear overnight and that list is rebuilt from four feeds daily. Public mailbox providers do not: the head of this list moves on the timescale of years, so it is curated and changes when somebody changes it.

dataset_version identifies the bundle both lists travel in. It is a label plus a digest of the values, so re-indenting a file does not mint a new version and a changed entry cannot fail to. Two things it is for: pinning a support conversation about a domain to the exact list that answered, and knowing that a cached answer of yours was taken against a bundle that has since moved.

domain accepts a whole address, because the code asking this question usually has one:

{ "domain": "someone@gmail.com" }

Only the domain is read. The local part is discarded before anything else happens - before the domain is even normalised - and appears in no response, no log and no error message. It is a convenience rather than a second field, and sending one has exactly the same effect as sending the domain by itself.

The domain is normalised the way every other lookup on this service normalises one, so an internationalised name is converted before it is compared and comes back in both forms.

Use this to sort personal addresses from company ones - qualifying a signup, routing a lead, deciding whether to ask for a work address - and to do it on volumes where paying per domain would not be worth it.

Buy a domain-depth check when the question is whether mail can reach the domain at all. It resolves the name, reads the mail routing, returns a real verdict, and reports every risk signal at once rather than this one. It costs 2 credits and answers something this cannot.

Buy a full check on a signup form. Neither of the above asks the destination about the recipient.

Status Meaning
400 missing_domain, or invalid_domain for something no lookup can be made for. Fix the request; it will not succeed on retry.
401 Missing or unrecognised credential.
413 The request body is larger than permitted.
429 Caller or source budget exceeded. Back off; honour Retry-After.
503 annotation_unavailable - the reference lists are not loaded, so no answer can be given.

The 503 matters more here than on the lookups beside it, and for a reason worth stating. On those, a negative is a real answer and a service that had lost its lists answering false would at least be visibly odd. Here false is exactly what an unlisted domain legitimately gets - so a service answering it to everything would be indistinguishable from a working one until somebody asked about gmail.com. It refuses instead. Treat it as no answer, not as a negative one.