All pages

POST /api/v1/email

Check an email address

Disposable domains, aliases and addresses built to be thrown away.

Disposable domains, aliases and addresses built to be thrown away. Useful at signup, before you send a confirmation to a mailbox that will not exist tomorrow.

Parameters

FieldTypeRequired
addressstringyes The address, up to 320 characters. Malformed ones are welcome.
aibooleanno Accepted for a uniform body, and only as false. No model reads an address, so "ai": true is refused with 422 ai_unavailable.
referencestringno Your own id for the thing being judged, up to 120 characters. Never parsed, stored and handed back, so a verdict is findable later by the name you already use for it.
policystringno Which of your policies to judge under. Absent means the project's policy, then your default; an account with none gets the shipped thresholds.
projectstringno Which of your projects the verdict is filed under. Absent means your default project.
actorstringno Your own id for whoever wrote it. Filed with the verdict, and used to move the line when a policy asks for reputation.

The address is not validated as an email before it is judged, on purpose. The whole point is to have an opinion about addresses, including broken ones, and rejecting the input with a 422 before anything looks at it would answer a different question than the one you asked.

Request

curl https://toxicfilter.com/api/v1/email \
  -H "Authorization: Bearer tf_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "address": "qx7f2k.throwaway+signup@mailinator.com" }'

Response

{
  "decision": "review",
  "flagged": ["spam"],
  "scores": { "spam": 0.68 },
  "signals": [
    {
      "category": "spam",
      "score": 0.68,
      "detector": "disposable_email",
      "reason": "Disposable mailbox provider with a random local part.",
      "evidence": ["mailinator.com"]
    }
  ],
  "used_ai": false,
  "took_ms": 2,
  "credits": { "remaining": 4903, "renews_at": "2026-09-30T00:00:00+00:00" }
}

Plus-addressing and dots are normalised, so a.name+shop@gmail.com and aname@gmail.com are recognised as the same inbox. That matters when somebody is opening their fourth account after three bans.

No model reads an address

An address is a shape, not a piece of writing: there is nothing to read. It is on a list or it is not, the local part is random or it is not, the domain can receive mail or it cannot, and no amount of reading makes x@mailinator.com more or less throwaway.

The field is still accepted, so a client can send the same body shape to every endpoint, but only as false or left out. "ai": true comes back as 422 ai_unavailable. That is deliberate: accepted and ignored would mean a used_ai: false the caller has to notice for themselves, on a call the quota check had already priced as a model call. The same applies to a name and a link.