REST API Referentie
Een paar endpoints, één antwoordstructuur. Alles hieronder werkt live met uw account.
https://namegender.com/api/v1/gender
Gratis aanmelden
Markdown voor codeerassistenten zoals Claude Code, Cursor en Copilot. Plak het in de chat of geef de assistent de link.
Snel starten
Maak een sleutel in uw dashboard en verzend uw eerste aanvraag. Geen SDK nodig.
curl "https://namegender.com/api/v1/gender?name=Ay%C5%9Fe&country=TR" \
-H "Authorization: Bearer YOUR_API_KEY"
<?php
$query = http_build_query(['name' => 'Ayşe', 'country' => 'TR']);
$ch = curl_init('https://namegender.com/api/v1/gender?' . $query);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY'],
]);
$result = json_decode(curl_exec($ch), true);
echo $result['gender']; // female
echo $result['probability']; // 100
const params = new URLSearchParams({ name: 'Ayşe', country: 'TR' });
const response = await fetch(`https://namegender.com/api/v1/gender?${params}`, {
headers: { Authorization: 'Bearer YOUR_API_KEY' },
});
const result = await response.json();
console.log(result.gender); // "female"
console.log(result.probability); // 100
import requests
response = requests.get(
"https://namegender.com/api/v1/gender",
params={"name": "Ayşe", "country": "TR"},
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
result = response.json()
print(result["gender"]) # female
print(result["probability"]) # 100
require "net/http"
require "json"
uri = URI("https://namegender.com/api/v1/gender")
uri.query = URI.encode_www_form(name: "Ayşe", country: "TR")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts JSON.parse(response.body)["gender"] # female
req, _ := http.NewRequest("GET", "https://namegender.com/api/v1/gender?name=Ay%C5%9Fe&country=TR", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
var result struct {
Gender string `json:"gender"`
Probability int `json:"probability"`
}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result.Gender) // female
Elk endpoint retourneert dezelfde structuur, dus u kunt invoer omschakelen zonder uw parseringscode te wijzigen.
Authenticatie
Elke request stuurt uw API-sleutel mee in een header. Gebruik standaard Authorization: Bearer, of X-Api-Key als uw HTTP-client de Authorization header al voor iets anders gebruikt. Een sleutel in de URL wordt geweigerd: URL's worden gekopieerd naar proxylogboeken, analysetools en browsergeschiedenis.
Authorization: Bearer ng_live_xxxxxxxxxxxx
Kopiëren mislukt. Selecteer en kopieer de tekst.
X-Api-Key: ng_live_xxxxxxxxxxxx
Kopiëren mislukt. Selecteer en kopieer de tekst.
U kunt een sleutel beperken tot specifieke IP-adressen via het dashboard.
Clientbibliotheken
Dunne wrappers rond de REST API. Ze sturen je sleutel mee, bouwen elk verzoek op en zetten foutresponses om in exceptions.
npm install namegender
Kopiëren mislukt. Selecteer en kopieer de tekst.
npm install -g namegender
Kopiëren mislukt. Selecteer en kopieer de tekst.
composer require namegender/namegender
Kopiëren mislukt. Selecteer en kopieer de tekst.
pip install namegender-client
Kopiëren mislukt. Selecteer en kopieer de tekst.
gem install namegender
Kopiëren mislukt. Selecteer en kopieer de tekst.
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<dependency>
<groupId>com.github.anpekesen</groupId>
<artifactId>namegender-java</artifactId>
<version>v0.9.0</version>
</dependency>
Kopiëren mislukt. Selecteer en kopieer de tekst.
dotnet add package NameGender --version 0.6.0
Kopiëren mislukt. Selecteer en kopieer de tekst.
go get github.com/anpekesen/namegender-go@v0.7.0
Kopiëren mislukt. Selecteer en kopieer de tekst.
remotes::install_github('anpekesen/namegender-r', ref = 'v0.7.0')
Kopiëren mislukt. Selecteer en kopieer de tekst.
Install-Module NameGender
Kopiëren mislukt. Selecteer en kopieer de tekst.
cargo add namegender
Kopiëren mislukt. Selecteer en kopieer de tekst.
Je hebt er geen nodig. De API bestaat uit een handvol eenvoudige JSON-endpoints; een bibliotheek bespaart je een middag, niet een project. Als je taal niet vermeld staat, bevat de REST-referentie copy-paste-voorbeelden.
Alles weergevenAI-assistenten (MCP)
Gebruik NameGender vanuit Claude, Cursor en elke andere client die het Model Context Protocol ondersteunt. Vraag de assistent naar een lijst met namen en hij roept de API voor u aan, met het bewijs naast elk antwoord.
claude mcp add namegender -e NAMEGENDER_API_KEY=ng_live_... -- npx -y namegender-mcp
Kopiëren mislukt. Selecteer en kopieer de tekst.
{
"mcpServers": {
"namegender": {
"command": "npx",
"args": [
"-y",
"namegender-mcp"
],
"env": {
"NAMEGENDER_API_KEY": "ng_live_..."
}
}
}
}
Kopiëren mislukt. Selecteer en kopieer de tekst.
Voeg dit toe aan het MCP-configuratiebestand van de client en start de client opnieuw.
Tools
gender_from_name- Geslacht op basis van een voornaam of volledige naam.
gender_from_email- Leest de naam in een e-mailadres; functionele adressen zoals info@ geven onbekend terug.
gender_from_username- Leest de naam in een gebruikersnaam of handle.
gender_bulk- Tot 100 waarden in één aanvraag, met een samenvatting van het matchpercentage.
name_countries- Landen waar een naam geregistreerd is. Geen uitspraak over herkomst.
salutation- Aanhef van een brief in de taal van de brief; de neutrale vorm als het geslacht niet zeker is.
name_check- Of een in een formulier getypte naam echt lijkt, met de redenen. Noemt een naam nooit nep.
age_from_name- Mediane leeftijd en leeftijdsbereiken van de mensen met een voornaam in de Verenigde Staten, Frankrijk en Noorwegen.
account_status- Resterende credits en de gratis hoeveelheid van vandaag.
Elke lookup verbruikt credits van het account dat eigenaar is van de sleutel, precies zoals een directe API-call. Vermeld in het officiële MCP-register als io.github.anpekesen/namegender. npm-pakket · Bron
Geslacht uit naam
Accepteert een voornaam of volledige naam. Titels, tweede voornamen en achternamen worden verwijderd voordat de zoekopdracht plaatsvindt, dus "Dr. Ayşe Yılmaz" en "Ayşe" geven hetzelfde resultaat.
| Parameter | Type | Beschrijving |
|---|---|---|
name
verplicht
|
string
|
De naam om in te delen. Voornaam of volledige naam. |
country
optioneel
|
string
|
ISO 3166-1 alfa-2 landcode. Verbetert de nauwkeurigheid voor namen waarvan het geslacht per regio verschilt, zoals Andrea (man in Italië, vrouw in Duitsland). |
locale
optioneel
|
string
|
Een taaltag zoals de-DE of en_US, bijvoorbeeld de taal van de browser. De regio wordt het land als country niet wordt meegestuurd. Een tag zonder regio (en, de) bepaalt geen land. |
ip
optioneel
|
string
|
Het IP-adres van de eindgebruiker. Het land ervan wordt gebruikt als country en een locale met regio allebei ontbreken. Wordt niet opgeslagen. IP geolocation by DB-IP (db-ip.com). |
ai_fallback
optioneel
|
boolean
|
Als de naam niet in onze gegevens voorkomt, vraag dan een taalmodel om een schatting in plaats van null terug te geven. Werkt alleen nadat AI-zoekopdrachten in uw instellingen zijn ingeschakeld, en kost één extra credit. |
best_guess
optioneel
|
boolean
|
Retourneer het overheersende geslacht, ook als het bewijs onder de betrouwbaarheidsdrempel blijft. Standaard uit: een antwoord van bijna 50/50 dat definitief oogt, richt meer schade aan dan null. |
curl "https://namegender.com/api/v1/gender?name=Jordan" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"credits_charged": 1,
"credits_remaining": 49999,
"request_id": "req_4b7e0c2d9a1f6358",
"query": "Jordan",
"name": "Jordan",
"first_name": "Jordan",
"middle_name": null,
"last_name": null,
"name_type": "personal",
"gender": "male",
"country": null,
"sample_size": 62240,
"probability": 84,
"took_ms": 1,
"confidence": "high",
"source": "db",
"matched_as": null
}
Geslacht uit e-mail
Haalt de persoon uit het lokale deel van het adres en classify dat. "ayse.yilmaz84@example.com" leidt tot Ayşe.
| Parameter | Type | Beschrijving |
|---|---|---|
email
verplicht
|
string
|
Het e-mailadres. Alleen het deel vóór @ wordt gebruikt. |
country
optioneel
|
string
|
ISO 3166-1 alfa-2 landcode. Verbetert de nauwkeurigheid voor namen waarvan het geslacht per regio verschilt, zoals Andrea (man in Italië, vrouw in Duitsland). |
locale
optioneel
|
string
|
Een taaltag zoals de-DE of en_US, bijvoorbeeld de taal van de browser. De regio wordt het land als country niet wordt meegestuurd. Een tag zonder regio (en, de) bepaalt geen land. |
ip
optioneel
|
string
|
Het IP-adres van de eindgebruiker. Het land ervan wordt gebruikt als country en een locale met regio allebei ontbreken. Wordt niet opgeslagen. IP geolocation by DB-IP (db-ip.com). |
ai_fallback
optioneel
|
boolean
|
Als de naam niet in onze gegevens voorkomt, vraag dan een taalmodel om een schatting in plaats van null terug te geven. Werkt alleen nadat AI-zoekopdrachten in uw instellingen zijn ingeschakeld, en kost één extra credit. |
best_guess
optioneel
|
boolean
|
Retourneer het overheersende geslacht, ook als het bewijs onder de betrouwbaarheidsdrempel blijft. Standaard uit: een antwoord van bijna 50/50 dat definitief oogt, richt meer schade aan dan null. |
best_guess werkt op de voornaam die uit het adres wordt gehaald, niet op het adres zelf. Als er geen voornaam uit te halen is, valt er niets te forceren en blijft gender null. Houd er rekening mee dat een geforceerd antwoord hier steunt op een extractie die zelf fout kan zijn.
curl "https://namegender.com/api/v1/gender/email?email=ayse.yilmaz84%40example.com" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"credits_charged": 1,
"credits_remaining": 49998,
"query": "ayse.yilmaz84@example.com",
"name": "Ayse",
"gender": "female",
"sample_size": 655,
"probability": 100,
"took_ms": 1,
"confidence": "high",
"source": "db"
}
Geslacht uit gebruikersnaam
Verwerkt camelCase, snake_case, navolgende cijfers en voorvoegsel @ tekens. "AyseYilmaz84" leidt tot Ayşe.
| Parameter | Type | Beschrijving |
|---|---|---|
username
verplicht
|
string
|
De gebruikersnaam of handle. Een voorvoegsel @ wordt genegeerd. |
country
optioneel
|
string
|
ISO 3166-1 alfa-2 landcode. Verbetert de nauwkeurigheid voor namen waarvan het geslacht per regio verschilt, zoals Andrea (man in Italië, vrouw in Duitsland). |
locale
optioneel
|
string
|
Een taaltag zoals de-DE of en_US, bijvoorbeeld de taal van de browser. De regio wordt het land als country niet wordt meegestuurd. Een tag zonder regio (en, de) bepaalt geen land. |
ip
optioneel
|
string
|
Het IP-adres van de eindgebruiker. Het land ervan wordt gebruikt als country en een locale met regio allebei ontbreken. Wordt niet opgeslagen. IP geolocation by DB-IP (db-ip.com). |
ai_fallback
optioneel
|
boolean
|
Als de naam niet in onze gegevens voorkomt, vraag dan een taalmodel om een schatting in plaats van null terug te geven. Werkt alleen nadat AI-zoekopdrachten in uw instellingen zijn ingeschakeld, en kost één extra credit. |
best_guess
optioneel
|
boolean
|
Retourneer het overheersende geslacht, ook als het bewijs onder de betrouwbaarheidsdrempel blijft. Standaard uit: een antwoord van bijna 50/50 dat definitief oogt, richt meer schade aan dan null. |
curl "https://namegender.com/api/v1/gender/username?username=AyseYilmaz84" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"credits_charged": 1,
"credits_remaining": 49997,
"query": "AyseYilmaz84",
"name": "Ayse",
"gender": "female",
"sample_size": 655,
"probability": 100,
"took_ms": 1,
"confidence": "high",
"source": "db"
}
Bulkaanvraag
Verzend tot 100 namen in één aanvraag. Gebruik dit in plaats van looping: één bulkaanroep voor 100 namen is één enkele trip en een enkele gededupliceerde zoekopdracht.
| Parameter | Type | Beschrijving |
|---|---|---|
names
verplicht
|
string[]
|
Array van namen. Maximaal 100 items. |
type
optioneel
|
string
|
Wat de items zijn: naam, e-mail of gebruikersnaam. Standaard naar naam. |
country
optioneel
|
string
|
Toegepast op elk item in de aanvraag. |
locale
optioneel
|
string
|
Taaltag waarvan de regio het land voor elk item wordt als country niet wordt meegestuurd. |
ip
optioneel
|
string
|
IP-adres van de eindgebruiker waarvan het land voor elk item geldt als country en een locale met regio ontbreken. Wordt niet opgeslagen. IP geolocation by DB-IP (db-ip.com). |
curl -X POST "https://namegender.com/api/v1/gender/bulk" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"names": ["Ayşe", "Mehmet", "Priya", "Wei"]}'
<?php
$ch = curl_init('https://namegender.com/api/v1/gender/bulk');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_API_KEY',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'names' => ['Ayşe', 'Mehmet', 'Priya', 'Wei'],
]),
]);
$data = json_decode(curl_exec($ch), true);
foreach ($data['results'] as $row) {
printf("%-8s %-7s %d%%\n", $row['query'], $row['gender'] ?? '?', $row['probability']);
}
const response = await fetch('https://namegender.com/api/v1/gender/bulk', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ names: ['Ayşe', 'Mehmet', 'Priya', 'Wei'] }),
});
const { results, summary } = await response.json();
console.log(summary.match_rate); // 100
results.forEach(r => console.log(r.query, r.gender, r.probability));
import requests
response = requests.post(
"https://namegender.com/api/v1/gender/bulk",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"names": ["Ayşe", "Mehmet", "Priya", "Wei"]},
)
data = response.json()
print(data["summary"]["match_rate"]) # 100
for row in data["results"]:
print(row["query"], row["gender"], row["probability"])
{
"credits_charged": 4,
"credits_remaining": 49995,
"request_id": "req_71d0a9e3c5b24f86",
"took_ms": 2,
"summary": {
"total": 4,
"identified": 4,
"unknown": 0,
"match_rate": 100
},
"results": [
{ "query": "Ayşe", "gender": "female", "probability": 100, "sample_size": 655, "confidence": "high", "source": "db" },
{ "query": "Mehmet", "gender": "male", "probability": 100, "sample_size": 1130, "confidence": "high", "source": "db" },
{ "query": "Priya", "gender": "female", "probability": 100, "sample_size": 2993, "confidence": "high", "source": "db" },
{ "query": "Wei", "gender": "male", "probability": 86, "sample_size": 136, "confidence": "high", "source": "db" }
]
}
Resultaten retourneren in dezelfde volgorde als u ze hebt verzonden. Credits worden per naam in rekening gebracht, en de hele aanvraag wordt afgewezen voordat enig werk gebeurt als uw saldo onvoldoende is, dus u krijgt nooit een half verwerkte batch.
Het samenvattingsblok laat u de match rate in één oogopslag zien, zodat u kunt bepalen of de invoer opschoning nodig heeft voordat u de rest verwerkt.
Bestandstaken
Upload een CSV- of XLSX-bestand van maximaal 100 MB en 1.000.000 rijen en krijg het terug met geslachtskolommen bij elke rij. Eén credit per rij, alleen in rekening gebracht als de taak voltooid wordt.
-
1.
POST /batchesStuur het bestand en name_column. De taak wordt meteen in de wachtrij gezet. -
2.
GET /batches/{id}Lees de taak tot status completed of failed is. poll_after_seconds geeft aan hoe lang je tussen twee keer lezen wacht. -
3.
GET /batches/{id}/resultDownload het resultaat. Het komt terug in het formaat dat je uploadde.
| Parameter | Type | Beschrijving |
|---|---|---|
file
verplicht
|
file
|
CSV, TSV of XLSX met een kopregel. |
name_column
verplicht
|
string
|
Kop van de kolom met de namen, precies zoals in het bestand. Verplicht, behalve bij start=false. |
country_column
optioneel
|
string
|
Kop van een kolom met een landcode per rij. |
country
optioneel
|
string
|
Standaardland voor rijen zonder land. |
ai_fallback
optioneel
|
boolean
|
Een AI-model vragen voor namen die niet in de dataset staan. Vereist AI-toestemming in Instellingen. |
best_guess
optioneel
|
boolean
|
Het waarschijnlijkere geslacht teruggeven, ook bij zwak bewijs. |
delete_after_download
optioneel
|
boolean
|
Het resultaat kan één keer worden gedownload en wordt daarna verwijderd. |
start
optioneel
|
boolean
|
false: alleen uploaden en bekijken. Standaard true. |
# 1. Upload and start
curl -X POST "https://namegender.com/api/v1/batches" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: 6f1c2e0a-customers-2026-09" \
-F "file=@customers.csv" \
-F "name_column=first_name" \
-F "country_column=country"
# 2. Poll until status is completed or failed
curl "https://namegender.com/api/v1/batches/B-7K2M9QX4TA" \
-H "Authorization: Bearer YOUR_API_KEY"
# 3. Download the result
curl "https://namegender.com/api/v1/batches/B-7K2M9QX4TA/result" \
-H "Authorization: Bearer YOUR_API_KEY" \
-o customers-gender.csv
import { NameGender } from 'namegender';
import { openAsBlob } from 'node:fs';
import { writeFile } from 'node:fs/promises';
const client = new NameGender(process.env.NAMEGENDER_API_KEY);
const job = await client.batches.create(await openAsBlob('customers.csv'), {
filename: 'customers.csv',
name_column: 'first_name',
country_column: 'country',
});
const done = await client.batches.wait(job.id);
if (done.status === 'failed') throw new Error(done.error.code);
const file = await client.batches.download(done.id);
await writeFile('customers-gender.csv', Buffer.from(await file.arrayBuffer()));
from namegender import NameGender
client = NameGender("YOUR_API_KEY")
job = client.batches.create("customers.csv", name_column="first_name", country_column="country")
done = client.batches.wait(job["id"])
if done["status"] == "failed":
raise RuntimeError(done["error"]["code"])
client.batches.download(done["id"], "customers-gender.csv")
{
"id": "B-7K2M9QX4TA",
"status": "completed",
"source": "api",
"file": { "name": "customers.csv", "format": "csv" },
"columns": { "name": "first_name", "country": "country" },
"rows": { "total": 200000, "processed": 200000, "identified": 187412 },
"progress": 100,
"credits": { "reserved": 200000, "charged": 200000 },
"summary": { "male": 96120, "female": 91292, "unknown": 12588, "from_llm": 0 },
"error": null,
"result": {
"url": "https://namegender.com/api/v1/batches/B-7K2M9QX4TA/result",
"format": "csv",
"expires_at": "2026-10-01T10:04:12Z"
},
"poll_after_seconds": null
}
name_column is verplicht om te starten: een geraden kolom die fout blijkt, zou credits aan de verkeerde gegevens besteden. Stuur start=false om eerst de kolommen, een voorbeeld en de kosten te zien, en start daarna de taak.
Stuur een Idempotency-Key-header. Een nieuwe poging met dezelfde sleutel geeft de eerste taak terug in plaats van een tweede te openen.
Er kunnen maximaal 3 taken tegelijk in de wachtrij staan of lopen. Een taak die nog niet gestart is, kan worden geannuleerd en de credit wordt teruggegeven; een taak in verwerking kan niet worden gestopt.
Webhooks
Voeg in je dashboard onder Webhooks een endpoint toe; we sturen het een ondertekende POST als een bestandstaak klaar is of mislukt, zodat je niet hoeft te pollen.
| Gebeurtenis | Type | Beschrijving |
|---|---|---|
batch.completed
|
BatchJob
|
De taak is klaar. De body bevat de taak precies zoals GET /batches/{id} die teruggeeft. |
batch.failed
|
BatchJob
|
De taak is mislukt en niet in rekening gebracht. Vertak op error.code. |
credits.low
|
CreditsAlert
|
Bij het huidige verbruik gaan de credits 7 dagen of minder mee. Elk uur gecontroleerd; abonnementsverlengingen worden meegerekend. |
credits.depleted
|
CreditsAlert
|
Het saldo is leeg en verzoeken worden geweigerd met 402. Elk uur gecontroleerd. |
webhook.test
|
object
|
Alleen verstuurd via "Testgebeurtenis sturen" in het dashboard, en alleen naar dat endpoint. |
| Header | Type | Beschrijving |
|---|---|---|
NameGender-Signature
verplicht
|
string
|
t=<unix-seconden>,v1=<hex>. Na het vernieuwen van het geheim staat er 24 uur lang een tweede v1. |
NameGender-Event-Id
verplicht
|
string
|
De gebeurtenis-ID. Bij elke nieuwe poging van dezelfde gebeurtenis gelijk. |
NameGender-Delivery-Attempt
verplicht
|
integer
|
1 bij de eerste poging, tot 8. |
Controleer elk verzoek
v1 is de HMAC-SHA256 van de tijdstempel, een punt en de ruwe body, met het geheim van je endpoint. Vergelijk in constante tijd, accepteer het verzoek als een v1 klopt en weiger een tijdstempel die meer dan vijf minuten van je klok afwijkt. De clientbibliotheken doen dit allemaal in één aanroep.
import express from 'express';
import { webhooks, NameGenderWebhookError } from 'namegender';
const app = express();
// express.raw, not express.json: the signature covers the exact bytes.
app.post('/namegender', express.raw({ type: 'application/json' }), async (req, res) => {
let event;
try {
event = await webhooks.verify(
req.body,
req.get('NameGender-Signature'),
process.env.NAMEGENDER_WEBHOOK_SECRET,
);
} catch (error) {
if (error instanceof NameGenderWebhookError) return res.sendStatus(400);
throw error;
}
res.sendStatus(204); // answer first, then do the work
if (event.type === 'batch.completed') {
const job = event.data.object; // same object as GET /batches/{id}
}
});
import os
from flask import Flask, request
from namegender import webhooks, WebhookVerificationError
app = Flask(__name__)
@app.post("/namegender")
def namegender_webhook():
try:
event = webhooks.verify(
request.get_data(), # raw bytes, not request.json
request.headers.get("NameGender-Signature"),
os.environ["NAMEGENDER_WEBHOOK_SECRET"],
)
except WebhookVerificationError:
return "", 400
if event["type"] == "batch.completed":
job = event["data"]["object"] # same object as GET /batches/{id}
return "", 204
<?php
$body = file_get_contents('php://input'); // raw body, before json_decode
$header = $_SERVER['HTTP_NAMEGENDER_SIGNATURE'] ?? '';
$secret = getenv('NAMEGENDER_WEBHOOK_SECRET');
parse_str(str_replace(',', '&', $header), $parts); // t=…&v1=…
preg_match_all('/v1=([0-9a-f]{64})/', $header, $m);
$t = (int) ($parts['t'] ?? 0);
$expected = hash_hmac('sha256', $t . '.' . $body, $secret);
$valid = abs(time() - $t) <= 300
&& array_filter($m[1], fn ($sig) => hash_equals($expected, $sig));
if (! $valid) {
http_response_code(400);
exit;
}
http_response_code(204);
$event = json_decode($body, true);
{
"id": "evt_16f7c01502fda5436e8b7c4e",
"type": "batch.completed",
"created_at": "2026-09-24T10:04:12Z",
"api_version": "v1",
"data": {
"object": {
"id": "B-7K2M9QX4TA",
"status": "completed",
"rows": { "total": 200000, "processed": 200000, "identified": 187412 },
"credits": { "reserved": 200000, "charged": 200000 },
"result": { "url": "…/api/v1/batches/B-7K2M9QX4TA/result", "format": "csv" }
}
}
}
- Antwoord binnen 10 seconden met een willekeurige 2xx en doe het werk daarna.
- Elk ander antwoord, een redirect inbegrepen, wordt binnen ongeveer 45 uur tot 7 keer opnieuw geprobeerd. Blijft een endpoint drie dagen falen, dan wordt het uitgeschakeld en krijg je een e-mail.
- Een nieuwe poging draagt dezelfde ID en de volgorde is niet gegarandeerd. Ontdubbel op NameGender-Event-Id en lees de taak met GET als je de actuele stand nodig hebt.
- Vernieuw je het geheim in het dashboard, dan tekent het oude nog 24 uur mee, zodat je je server bijwerkt zonder gebeurtenissen te missen.
- Er kunnen nieuwe gebeurtenistypen bijkomen. Antwoord 2xx op een type dat je niet verwerkt en negeer het.
Landenverdeling
Retourneert de landen waarin een naam is geregistreerd. Er worden twee lijsten geretourneerd die opzettelijk niet zijn samengevoegd: `registrations` is gemeten volume, alleen vergelijkbaar tussen de elf landen die getelde naamstatistieken publiceren, en `attested_in` is aanwezigheid, zonder weging.
| Parameter | Type | Beschrijving |
|---|---|---|
name
verplicht
|
string
|
De naam om op te zoeken. |
limit
optioneel
|
integer
|
Hoeveel getelde landen in `registrations` worden weergegeven. 1–100, standaard 25. Aandelen worden voor de kortere lijst niet opnieuw berekend. |
curl "https://namegender.com/api/v1/gender/countries?name=Mehmet" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"credits_charged": 1,
"credits_remaining": 49994,
"took_ms": 3,
"name": "Mehmet",
"basis": {
"counted_sources": ["ssa", "ons", "nrs", "nisra", "insee", "statcan", "ine", "cso", "ssb", "statat", "pesel", "bfs"],
"counted_countries": 8,
"attested_countries": 16,
"note": "Shares are calculated only across countries that publish counted name statistics…"
},
"registrations": [
{ "country": "CH", "count": 3890, "share": 29.45, "gender": "male", "source": "bfs" },
{ "country": "FR", "count": 3775, "share": 28.58, "gender": "male", "source": "insee" },
{ "country": "PL", "count": 1808, "share": 13.69, "gender": "male", "source": "pesel" }
],
"attested_in": ["AL","AT","AU","BE","CA","CH","ES","FR","GB","KS","MK","NO","PL","SE","TR","US"]
}
Eén tegoed per aanvraag. `share` wordt berekend over alle getelde landen en telt dus alleen op tot 100 als `limit` de lijst niet inkort; ook `counted_countries` telt vóór het inkorten. `attested_in` bevat geen percentages omdat er geen getallen achter die records liggen om deze te berekenen.
Aanhef
Maakt van een naam een aanhef, klaar voor een brief of e-mail, in tien talen: “Sehr geehrte Frau Dr. Müller,”, “Sayın Ahmet Bey,”, “Madame,”, “山田様”. De geslachtsbepaling is inbegrepen en kost hetzelfde ene tegoed. Elk antwoord bevat een formele, een informele en een neutrale regel, plus de onderdelen van de formele regel.
| Parameter | Type | Beschrijving |
|---|---|---|
name
verplicht
|
string
|
Volledige naam, inclusief titels (“Dr. Anna Müller”). Stuur deze of `first_name` en `last_name`. |
first_name, last_name
optioneel
|
string
|
Gebruik deze in plaats van `name` als je CRM namen in aparte velden bewaart. Er wordt niets ontleed. |
email
optioneel
|
string
|
E-mailadres, gebruikt als er geen naam wordt meegestuurd. De naam wordt gelezen uit het deel vóór de @, zonder accenten (Mueller, niet Müller); info@ en andere functieadressen krijgen de aanhef voor organisaties. |
language
optioneel
|
string
|
Taal van de aanhef: en, en-US, en-GB, de, de-AT, de-CH, fr, es, it, pt, pt-PT, pt-BR, nl, tr, pl, ja. Zonder deze: de taal van `locale`, dan de hoofdtaal van het land, dan Engels. Een niet-ondersteunde taal geeft een fout, nooit een stille overstap naar Engels. |
country, locale, ip
optioneel
|
string
|
Landhint voor de geslachtsbepaling, zoals bij de gender-endpoints. Bepaalt de taal alleen als `language` niet wordt meegestuurd. |
gender
optioneel
|
string
|
`male`, `female` of `neutral`, als je het al weet. Vervangt de bepaling; `neutral` geeft altijd de neutrale vorm. |
min_probability
optioneel
|
integer
|
Laagste waarschijnlijkheid voor een aanhef met geslacht, 50–100. Standaard 90. |
title
optioneel
|
string
|
Academische titel uit een apart veld, zoals `Dr.` Gebruikt in Duitse en Engelse aanheffen. |
curl -X POST "https://namegender.com/api/v1/salutation" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Dr. Anna Müller", "language": "de"}'
{
"credits_charged": 1,
"credits_remaining": 49993,
"language": "de",
"form": "gendered",
"reason": null,
"salutation": {
"formal": "Sehr geehrte Frau Dr. Müller,",
"informal": "Liebe Anna,",
"neutral": "Guten Tag Dr. Anna Müller,"
},
"parts": { "opening": "Sehr geehrte", "courtesy": "Frau", "academic": "Dr.", "name": "Müller" },
"gender": "female",
"gender_source": "lookup",
"probability": 99,
"first_name": "Anna",
"last_name": "Müller",
"name_type": "personal"
}
Een verkeerd geslacht is erger dan geen, dus de vorm met geslacht wordt alleen gebruikt als het geslacht met ten minste `min_probability` bekend is en de taal het naamdeel heeft dat ze nodig heeft. Anders is `form` gelijk aan `neutral` en zegt `reason` waarom. Bedrijven en functieadressen krijgen `form: organization`. `best_guess` en `ai_fallback` gelden hier niet.
POST /api/v1/salutation/bulk accepteert tot 100 namen in `names`, één tegoed per naam, met dezelfde opties voor elke naam.
Naamcontrole
Zegt of een naam die in een aanmeld- of leadformulier is getypt eruitziet als de naam van een echt persoon, en waarom. Vangt willekeurig toetsenbordgeram (“asdf qwerty”), opvulwaarden (“Test Test”, “John Doe”, “n/a”), fictieve personages (“Mickey Mouse”), scheldwoorden en cijfers, symbolen of e-mailadressen in het naamveld. Eén tegoed per naam.
| Parameter | Type | Beschrijving |
|---|---|---|
name
verplicht
|
string
|
De naam zoals die in het formulier is getypt. Stuur deze of `first_name` en `last_name`. |
first_name, last_name
optioneel
|
string
|
Gebruik deze in plaats van `name` als je formulier aparte velden heeft. |
country, locale, ip
optioneel
|
string
|
Landhint, zoals bij de gender-endpoints. Helpt bij het ontleden van de naam en het opzoeken in de registers. |
curl -X POST "https://namegender.com/api/v1/name-check" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "asdf qwerty"}'
{
"credits_charged": 1,
"credits_remaining": 49992,
"query": "asdf qwerty",
"assessment": "implausible",
"score": 0,
"signals": [
{ "code": "placeholder", "severity": "high", "part": "first_name", "value": "asdf" },
{ "code": "keyboard_pattern", "severity": "high", "part": "first_name", "value": "asdf" },
{ "code": "keyboard_pattern", "severity": "high", "part": "last_name", "value": "qwerty" }
],
"first_name": "Asdf",
"last_name": "Qwerty",
"name_type": "personal",
"evidence": { "first_name_status": "not_found", "first_name_counted_records": 0 }
}
`assessment` is `implausible` bij een signaal met hoge ernst (toetsenbordpatroon, herhaalde letters, opvulwaarde, scheldwoord, e-mail of URL), `suspicious` bij een gemiddeld signaal (fictief personage, cijfers, symbolen, bedrijfsnaam, geen klinkers, erg lang) of twee lage, en anders `plausible`. `score` loopt van 0 tot 100 voor je eigen drempel. Een voornaam uit officiële geboorteregisters verhoogt hem; een naam die we nooit hebben gezien verlaagt hem niet op zichzelf. Achternamen worden alleen op hun vorm beoordeeld: achter dit endpoint zit geen dataset met achternamen.
Getest op 4.610 echte voornamen in negen schriften, los en samen met een achternaam: geen enkele werd als verdacht of onwaarschijnlijk gemarkeerd. Achternamen zoals Null, Test of Cockburn, namen van twee letters zoals Ng en enkelvoudige namen worden bewust met rust gelaten.
POST /api/v1/name-check/bulk accepteert tot 100 namen in `names`, één tegoed per naam, met een samenvatting van de drie beoordelingen.
Leeftijd uit naam
Hoe oud de levende mensen met een voornaam zijn: de mediane leeftijd, de middelste helft (`age_range`) en de middelste 80% (`age_range_80`). Brittany in de Verenigde Staten: mediaan 36, de helft tussen 32 en 38. Eén tegoed per naam.
| Parameter | Type | Beschrijving |
|---|---|---|
name
verplicht
|
string
|
Een voornaam of een volledige naam; de voornaam wordt gebruikt. |
gender
optioneel
|
string
|
`male` of `female` om alleen de gegevens van dat geslacht te gebruiken. Mannen die Leslie heten zijn 16 jaar ouder dan vrouwen die Leslie heten. |
country, locale, ip
optioneel
|
string
|
Landhint, zoals bij de gender-endpoints. Gedekt: US, FR en NO. Zonder hint wordt de reeks van de Verenigde Staten gebruikt en is `country_source` `default`. Een ander land geeft `reason: country_not_covered` terug en kost niets. |
curl "https://namegender.com/api/v1/age?name=Brittany" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"credits_charged": 1,
"credits_remaining": 49991,
"request_id": "req_8f2c1a",
"name": "Brittany",
"first_name": "Brittany",
"gender": null,
"age": 36,
"age_range": { "low": 32, "high": 38 },
"age_range_80": { "low": 28, "high": 41 },
"birth_year": 1990,
"sample_size": 353775,
"births": 361434,
"country": "US",
"country_source": "default",
"source": "ssa",
"series": "1880-2024",
"reference_year": 2026,
"reason": null
}
Methode: geregistreerde geboorten per naam, geslacht en jaar, waarbij elk jaar wordt gewogen naar het aandeel van dat geboortecohort dat nog leeft (cohortsterftetafels van de SSA). Bronnen: SSA-geboorten 1880–2024 (US), INSEE 1900–2025 (Frankrijk), SSB 1945–2025 (Noorwegen). `reason` is `not_found` voor een naam die niet in de reeks staat en `insufficient_data` onder de 100 levende mensen.
Geboorten in het buitenland staan in geen enkele reeks, dus namen die veel voorkomen onder immigranten lijken jonger dan ze zijn. De Noorse reeks begint in 1945, dus mensen die eerder zijn geboren ontbreken. De Amerikaanse sterftetafel wordt ook voor Frankrijk en Noorwegen gebruikt.
POST /api/v1/age/bulk accepteert tot 100 namen in `names`, één tegoed per naam, in de volgorde waarin ze zijn verstuurd.
Saldo
Bekijk uw creditsaldo en wat er nog over is van de gratis dagelijkse hoeveelheid. Deze call wordt niet in rekening gebracht.
curl "https://namegender.com/api/v1/me" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"email": "you@example.com",
"credits_remaining": 50099,
"purchased_credits": 50000,
"free_today": 99,
"free_daily_limit": 100,
"lifetime_requests": 12480
}
Niet-Latijnse schriften
Stuur een naam in zijn eigen schrift en wij koppelen het aan de referentiegegevens. Geen extra parameter nodig: wij detecteren het schrift en kiezen de juiste strategie.
Arabisch schrift laat korte klinkers weg, dus محمد wordt "mhmd" terwijl onze gegevens "muhammed" bevatten. Wij matchen op het medeklinkerpatroon en behouden de vrouwelijke ة marker, dus خالد (Khalid) en خالدة (Khalida) blijven gescheiden. Omvat ook Perzische en Urdu-namen in Arabisch schrift.
Geconverteerd naar Pinyin. De familienaam staat eerst in het Chinees, dus 李明 heeft familienaam 李 (Li) met voornaam 明 (Ming) — wij verwijderen de familienaam voordat wij opzoeken. Een enkel teken is een volledige voornaam en wordt als één teken behandeld.
Dezelfde familienaam-eerst-verwerking als Chinees, met gebruik van algemene Koreaanse familienamen.
Hiragana en katakana worden correct gelezen (ひろし → Hiroshi).
Russische, Oekraïense, Bulgaarse en Servische namen translitereren rechtstreeks.
Hindi-, Marathi- en Nepalese namen. De inherente sluitende klinker wordt verwerkt (राहुल → Rahul, niet "Rahula").
Japanse kanji en Chinese tekens bevinden zich in hetzelfde Unicode-bereik, dus we kunnen ze niet van elkaar onderscheiden op basis van de tekens alleen. Han-invoer wordt als Chinees gelezen: een kanjinaam die we niet exact hebben opgeslagen krijgt zijn Mandarijnse uitspraak, wat voor een Japanse naam meestal onjuist is (健太 wordt "jian tai" gelezen terwijl de naam Kenta is). Namen die we hebben opgeslagen komen exact overeen en zijn correct. Stuur Japanse namen in kana of Latin om zeker te zijn.
Thais laat klinkers weg net als Arabisch en heeft zijn eigen matching-laag. Dit is nog niet gebouwd, dus deze retourneren null.
# Arap yazısı — ünsüz iskeleti üzerinden eşleşir
curl "https://namegender.com/api/v1/gender?name=%D9%85%D8%AD%D9%85%D8%AF" -H "Authorization: Bearer KEY"
# -> { "gender": "male", "probability": 100, "source": "script", "matched_as": "mahamad" }
# Çince — soyadı ayıklanır, verilen ad sorgulanır
curl "https://namegender.com/api/v1/gender?name=%E6%9D%8E%E6%98%8E" -H "Authorization: Bearer KEY"
# -> { "gender": "male", "probability": 92, "source": "db" }
Kopiëren mislukt. Selecteer en kopieer de tekst.
Wanneer we een script helemaal niet kunnen omzetten, is de respons gender: null met source: none. Controleer het source-veld: script betekent dat we hebben getranslitereerd, db betekent dat we de tekens die u heeft verzonden rechtstreeks hebben vergeleken. De twee hebben verschillende betrouwbaarheid, en we tonen u welke u heeft ontvangen.
Responsevelden
Identiek voor alle endpoints.
| Veld | Type | Beschrijving |
|---|---|---|
credits_charged
|
integer
|
Hoeveel credits er voor deze call zijn afgeschreven. |
credits_remaining
|
integer
|
Uw besteedbare saldo nadat deze call is betaald: gekochte credits plus wat er over is van de gratis hoeveelheid van vandaag. |
query
|
string
|
De invoer precies zoals u die stuurde, vóór enige opschoning. |
name
|
string
|
De naam die we daadwerkelijk hebben opgezocht na het verwijderen van titels en familienamen. |
first_name
|
string
|
Voornaam uit de invoer. Wordt ook teruggegeven als gender null is, zonder extra kosten. |
middle_name
|
string
|
Overige voornamen tussen de voornaam en de achternaam. Initialen worden weggelaten. |
last_name
|
string
|
Achternaam, inclusief tussenvoegsels zoals van of de la. Altijd null bij gebruikersnamen. |
name_type
|
string
|
personal, organization (Acme B.V.) of role (info@, klantenservice). Organisaties en rollen krijgen geen geslacht. |
gender
|
string
|
male, female, of null wanneer we niet zeker genoeg zijn. |
country
|
string
|
Het land waarvan de statistieken afkomstig zijn, of null voor de wereldwijde samenvatting. |
country_source
|
string
|
Waar het land vandaan komt: country, locale, ip of null als het antwoord wereldwijd is. |
sample_size
|
integer
|
Aantal geregistreerde personen achter dit antwoord. 0 betekent dat de bron verhoudingen of vermeldingen publiceert, geen aantal dat we kunnen controleren. |
probability
|
integer
|
Vertrouwen in het aangegeven geslacht, 50 tot 100. 0 wanneer geslacht null is. |
took_ms
|
integer
|
De tijd die wij nodig hadden om de lookup af te handelen, in hele milliseconden. Netwerktijd aan uw kant is niet inbegrepen. |
Twee velden die andere services niet bieden
source geeft aan waar het antwoord vandaan komt: de referentiedatabase, een fuzzy match, of de AI-fallback. matched_as benoemt de entry waar een fuzzy match op landde. Samen laten ze je bepalen hoeveel je één resultaat vertrouwt in plaats van het voor lief te nemen.
| Veld | Type | Beschrijving |
|---|---|---|
source
|
string
|
db, script, fuzzy, llm, of none. |
confidence
|
string
|
hoog, gemiddeld, laag, ongecontroleerd of onbekend, gebaseerd op steekproefgegevens. |
matched_as
|
string
|
Voor een fuzzy match, de databaseentry die overeenkomt. Anders null. |
Foutcodes
De HTTP-statuscode vertelt u dat een call is mislukt. De JSON-body noemt vervolgens de reden in error, legt die uit in message en geeft u een request_id om aan support door te geven, plus een link naar de bijbehorende rij in de documentatie hieronder. Baseer uw logica op error, nooit op message: berichten worden vertaald en kunnen anders geformuleerd worden.
| Code | HTTP | Betekenis |
|---|---|---|
missing_key |
401 | Er is geen API-sleutel meegestuurd. Voeg een Authorization: Bearer header of een X-Api-Key header toe aan het verzoek. |
invalid_key |
401 | Deze API-sleutel is niet geldig. |
revoked_key |
401 | Deze API-sleutel is ingetrokken. |
blocked |
403 | Dit account is opgeschort. Neem contact op met ondersteuning. |
email_not_verified |
403 | Het e-mailadres van dit account is nog niet bevestigd. Open de bevestigingslink die we je hebben gestuurd of vraag een nieuwe aan in je dashboard. |
ip_not_allowed |
403 | Verzoeken van dit IP-adres zijn niet toegestaan voor deze sleutel. |
proxy_secret_required |
403 | Deze sleutel werkt alleen via zijn API-marktplaats, die elk verzoek ondertekent. Gebruik de sleutel die u daar hebt ontvangen. |
forbidden |
403 | U bent niet gemachtigd om deze actie uit te voeren. |
no_credits |
402 | U bent zonder tegoed. Koop meer of wacht tot uw dagelijkse gratis quota wordt opnieuw ingesteld. |
missing_input |
400 | De parameter "name" is verplicht. |
invalid_input |
422 | De parameter "name" is niet geldig. |
too_many_items |
422 | Maximaal 100 items kunnen in één verzoek worden verzonden. |
ai_consent_required |
422 | ai_fallback stuurt de naam naar een AI-provider van derden, waar dit account niet mee heeft ingestemd. Zie het veld "ai" voor wie die provider is, en schakel AI-zoekopdrachten in uw dashboardinstellingen in. |
unknown_endpoint |
404 | Er bestaat geen endpoint op dit pad. Controleer de URL in de API-documentatie. |
method_not_allowed |
405 | Dit endpoint accepteert geen DELETE-verzoeken. |
payload_too_large |
413 | Die requestbody is te groot. |
rate_limited |
429 | Te veel verzoeken. Vertraag en probeer het over een moment opnieuw. |
batch_not_found |
404 | Er is geen bestandstaak met deze ID in dit account. |
batch_not_startable |
409 | Deze taak is al gestart of afgesloten. |
batch_not_finished |
409 | Deze taak is nog niet klaar. Controleer de status en download het resultaat zodra de taak is voltooid. |
batch_in_progress |
409 | Deze taak wordt verwerkt en kan nu niet worden geannuleerd. Verwijder hem zodra hij klaar is. |
result_gone |
410 | Deze taak heeft geen resultaat om te downloaden. De taak is mislukt, geannuleerd, verlopen, of het eenmalig downloadbare resultaat is al opgehaald. |
too_many_batches |
429 | Je hebt al 100 lopende bestandstaken. Wacht tot er een klaar is voordat je een nieuwe start. |
not_ready |
503 | De naamdatabase wordt opnieuw opgebouwd. Probeer het over een moment opnieuw. |
server_error |
500 | Er is iets misgegaan aan onze kant. Wij zijn hiervan op de hoogte gesteld. |
{
"error": "no_credits",
"message": "You are out of credits. Buy more or wait for your daily free quota to reset.",
"request_id": "req_9c1f5b2a7e0d4a13",
"docs": "https://namegender.com/docs#error-no_credits"
}
Kopiëren mislukt. Selecteer en kopieer de tekst.
Snelheidslimieten
Normaal gebruik bereikt geen limiet. De limiet bestaat om te voorkomen dat een gelekte sleutel wordt misbruikt, en wordt per API-sleutel geteld in plaats van per IP zodat meerdere klanten op één server elkaars quotum niet opgebruiken.
Huidige limiet: 1.200 requests per minuut per sleutel. Meer nodig? Vraag het en we verhogen het op je account.
Elke response bevat de standaard X-RateLimit-Limit en X-RateLimit-Remaining headers.
Spaties en niet-Latijnse letters in GET-requests
Een naam als Ayşe Yılmaz of 中村 kan niet zoals getypt in een URL mee. Percent-encode de waarde als je met GET aanroept, of stuur hem in een JSON-body met POST en sla het coderen helemaal over.
Ayşe Yılmaz -> Ay%C5%9Fe%20Y%C4%B1lmaz
محمد -> %D9%85%D8%AD%D9%85%D8%AF
中村 -> %E4%B8%AD%E6%9D%91
Kopiëren mislukt. Selecteer en kopieer de tekst.