All pages

POST /api/v1/url

Check a link

One address on its own: is it shaped like something pretending to be somewhere else.

One address, judged as an address. A different question from moderating a message that contains a link: not "is this an advert" but "is this trying to look like somewhere it is not".

curl https://toxicfilter.com/api/v1/url \
  -H "Authorization: Bearer tf_live_..." \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://paypal.com@login-secure.example/verify", "reference": "link_88" }'
{
  "decision": "block",
  "flagged": ["scam"],
  "signals": [
    { "category": "scam", "score": 0.9, "detector": "url",
      "reason": "The address has a username in front of the host, so it opens somewhere other than the name a reader sees." }
  ]
}

What it looks at

Shape
Credentials before the hosthttps://paypal.com@evil.example/ goes to evil.example. The part people read and the part that decides are different, which is the oldest trick there is and still the best.
A brand that is not the brandpaypal.com.secure-login.example. Configured, not guessed; see below.
Punycodexn--pypal-4ve.com renders as something else entirely.
Bare IP addressesLegitimate services have names.
Deep subdomainsFive labels is how the real domain gets pushed off the end of a phone's address bar.
ShortenersNot bad in themselves, since half the internet posts them, but a shortened link is an unanswered question.
Throwaway endings.zip and .mov especially: they are file extensions, so invoice.zip is both a filename and a domain.

It never fetches anything. No request to the address, no redirect chain followed, no reputation service asked. So it can tell you an address is shaped like a trick, and it can never tell you a domain is malicious. A clean answer means "this looks like what it says it is", not "this is safe". Treat it as one signal among yours, not as a verdict on the destination.

Whose brands

The impersonation check is configuration and starts empty, because who gets impersonated depends entirely on who you are. A Spanish marketplace cares about Correos, BBVA and Wallapop; a bank cares about itself; nobody cares about a list of American brands their users have never heard of. Each entry is a word to look for in the host and the domains allowed to contain it.

It also works as a batch item: {"kind": "url", "url": "..."}. Priced as the cheap call, and it never reaches a model: there is nothing in an address for one to read.

ai is accepted here only as false, for callers who send the same body shape everywhere. "ai": true is refused with 422 ai_unavailable rather than accepted and quietly ignored, which would be a model call priced by the quota check and never made. Same on an address and a name.

reference, policy, actor and rules work here as they do on every other endpoint.