POST
/api/v1/name
Check a name
Usernames and display names, including the ones spelled to slip past filters.
Usernames and display names, including the ones spelled to slip past a word list. Check it at registration, and again when somebody changes it.
Parameters
| Field | Type | Required | |
|---|---|---|---|
name | string | yes | Up to 200 characters. |
locales | string[] | no | Your site's languages, up to ten. |
ai | boolean | no | No model reads a name, so this is false and cannot be turned on. Sending "ai": true is refused with 422 ai_unavailable rather than accepted and ignored. |
reference | string | no | 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. |
policy | string | no | Which of your policies to judge under. Absent means the project's policy, then your default; an account with none gets the shipped thresholds. |
project | string | no | Which of your projects the verdict is filed under. Absent means your default project. |
actor | string | no | Your own id for whoever wrote it. Filed with the verdict, and used to move the line when a policy asks for reputation. |
Request
curl https://toxicfilter.com/api/v1/name \
-H "Authorization: Bearer tf_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "name": "H4t3R_88", "locales": ["en"] }'
Response
{
"decision": "review",
"flagged": ["evasion"],
"scores": { "evasion": 0.74 },
"signals": [
{
"category": "evasion",
"score": 0.74,
"detector": "evasion",
"reason": "Full-width characters and digit substitution used to obscure a word.",
"evidence": ["H4t3R"]
}
],
"used_ai": false,
"took_ms": 3,
"credits": { "remaining": 4890, "renews_at": "2026-09-30T00:00:00+00:00" }
}
Evasion is its own answer
evasion is scored separately from whatever was being hidden, and that is
useful on its own: leetspeak, homoglyphs, full-width characters and invisible
codepoints in a username are a signal about intent even when the underlying word is
ambiguous. A name written to get past a filter tells you something a clean name does
not.
Why no model reads it
A name is a shape, not a piece of writing: there is no argument to follow, no sarcasm and no target, and the question is whether the characters were chosen to get past a list. The normaliser and the word lists answer that, and they answer it in under a millisecond for one credit. A model would add a sentence of prose and several credits to the same answer.
So ai here is not a default you can override. It is refused, because the one
thing it must not be is accepted and ignored: used_ai: false with nothing
anywhere saying why is how a caller pays for a habit and believes they bought something.
The same is true of an address and
a link. A bio is writing, so
a signup can ask for the model.
Names are short, so context is thin and false positives cost more here than anywhere else. Treat
reviewon a name as "look at it", never as "reject it": plenty of real people have names a filter finds interesting.