The name field is where verification goes wrong in public. Block a disposable email and nobody notices. Tell a customer their surname is offensive, or greet them as "Dear Garcia" because you split their name in the wrong place, and it ends up in a screenshot. This lesson covers four APIs that each do one narrow job well, and the rules for keeping each in its lane.
- Human Name Parser splits a full name into title, first, middle, last, nickname and suffix.
- Gibberish Detector scores text for keyboard-mash randomness.
- Username Profanity says whether a handle is offensive, including disguised spellings.
- Profanity Filter masks offensive words in free text.
All four cost 2 credits a call, so cost is not the constraint here. Judgment is.
Parse names, but keep what the person typed
Most forms ask for "full name" in one box because two boxes annoy people and fail for many cultures. Then the CRM wants first and last for a mail merge. The parser bridges that.
curl "https://api.apiverve.com/v1/humannameparser?name=MR.+MARTINO+PETROS+DE+FLORENCE+%28TINO%29+Jr." \
-H "x-api-key: YOUR_API_KEY"Title Mr., first Martino, middle Petros, last de Florence, nick Tino, suffix Jr.
That example shows what the parser is good at: it recognises the title and the suffix, pulls the nickname out of the parentheses, keeps the particle de attached to the surname, and fixes the shouting capitals. It also reads Smith, John Q. correctly as last name Smith, first John, middle Q.. The response adds initials on every plan and a premium formalName such as Mr. de Florence, Martino P. Jr..
Now the cases that should change how you use it.
Dr. Maria del Carmen Lopez-Garcia PhD parses to first Maria, middle del Carmen, last Lopez-garcia. Two things went wrong. del Carmen is part of a compound given name, not a middle name in the English sense, and the second half of the hyphenated surname lost its capital letter. The initials come back MDL, which is not what she would write.
Cher parses to first "" and last Cher. A single name is put in last, so a template that says "Hi {first}" prints "Hi ". Plenty of real people have one name, and plenty more give only one to a form.
asdf qwerty parses cleanly to first Asdf, last Qwerty, initials AQ. The parser structures whatever it is given. It does not judge whether the input is a name.
The rules that follow from those three:
- Store the name exactly as typed and use that for anything the person sees, including the greeting on their account page. Parsed parts are for sorting, searching and mail merge.
- Never write parsed parts back over the original. The casing fix that helps
MARTINObreaksLopez-Garcia,McDonaldandvan der Berg. - Fall back when
firstis empty. Greet with the full name, or ask once: "What should we call you?" That one optional field beats any parser for greeting people correctly.
Your welcome email uses Hi {parsed.first}. A user signs up as Cher. What does the parser return, and what is the fix?
Answer the check above to continue.
One signup screen, four checks
Here is the profile check you can run on a signup that has a full name, a public username and a short "what will you build" answer. It returns parsed name parts for your CRM and a list of flags. Only an offensive username blocks the form. Everything else becomes review.
const BASE = 'https://api.apiverve.com/v1';
const headers = { 'x-api-key': process.env.APIVERVE_API_KEY };
async function call(api, params, method = 'GET') {
const init = { method, headers: { ...headers }, signal: AbortSignal.timeout(3000) };
let url = `${BASE}/${api}`;
if (method === 'GET') url += `?${new URLSearchParams(params)}`;
else {
init.headers['Content-Type'] = 'application/json';
init.body = JSON.stringify(params);
}
const res = await fetch(url, init);
const body = await res.json();
if (!res.ok || body.status !== 'ok') throw new Error(body.error || `HTTP ${res.status}`);
return body.data;
}
export async function profileCheck({ fullName, username, useCase }) {
const [name, handle, junk] = await Promise.all([
call('humannameparser', { name: fullName }),
call('usernameprofanity', { username }),
useCase && useCase.trim().length >= 4 ? call('gibberishdetector', { text: useCase }, 'POST') : null,
]);
const flags = [];
if (!name.parsed.first) flags.push('single_name');
if (junk?.isGibberish) flags.push('gibberish_use_case');
return {
blockUsername: handle.isProfane,
review: flags.length > 0,
flags,
displayName: fullName.trim(),
crm: { first: name.parsed.first, last: name.parsed.last },
};
}import os
from concurrent.futures import ThreadPoolExecutor
import requests
BASE = "https://api.apiverve.com/v1"
HEADERS = {"x-api-key": os.environ["APIVERVE_API_KEY"]}
def call(api: str, params: dict, method: str = "GET") -> dict:
if method == "GET":
r = requests.get(f"{BASE}/{api}", params=params, headers=HEADERS, timeout=3)
else:
r = requests.post(f"{BASE}/{api}", json=params, headers=HEADERS, timeout=3)
r.raise_for_status()
body = r.json()
if body.get("status") != "ok":
raise RuntimeError(body.get("error"))
return body["data"]
def profile_check(full_name: str, username: str, use_case: str = "") -> dict:
with ThreadPoolExecutor(max_workers=3) as pool:
name_f = pool.submit(call, "humannameparser", {"name": full_name})
handle_f = pool.submit(call, "usernameprofanity", {"username": username})
junk_f = (pool.submit(call, "gibberishdetector", {"text": use_case}, "POST")
if len(use_case.strip()) >= 4 else None)
name, handle = name_f.result(), handle_f.result()
junk = junk_f.result() if junk_f else None
flags = []
if not name["parsed"]["first"]:
flags.append("single_name")
if junk and junk["isGibberish"]:
flags.append("gibberish_use_case")
return {
"blockUsername": handle["isProfane"],
"review": bool(flags),
"flags": flags,
"displayName": full_name.strip(),
"crm": {"first": name["parsed"]["first"], "last": name["parsed"]["last"]},
}The three calls run in parallel because none depends on another, so the check adds one round trip, not three. Notice what is not in it: no gibberish check on the name, no profanity filter on the name, and displayName is the original string. single_name is a review flag only so your CRM export knows the first-name column is empty, not because anything is wrong with the person.
If any call fails, decide in advance which way to fall. For a free tier, let the signup through and flag it for later review; a name check is never worth a lost customer. Combine these flags with the email and phone decisions from the earlier lessons rather than letting any single one decide alone.
Next
You can now verify every field a person types into a form. The next course moves from what people type to where they connect from: IP reputation, VPN and Tor detection, and bot signals. Continue to Network and Fraud Signals.