Search by

namegender / namegender

anilpekesen

Official PHP client for the NameGender API

v0.4.0 2026-09-24 14:09 UTC

This package is auto-updated.

Last update: 2026-09-24 14:12:52 UTC


README

PHP client for the NameGender API. Requires PHP 8.1 or later. Get an API key from the namegender.com dashboard.

composer require namegender/namegender
$client = new NameGender\Client($_ENV['NAMEGENDER_API_KEY']);
$result = $client->name('Ayşe', country: 'TR');
echo $result['gender'], ' ', $result['probability'], ' ', $result['sample_size'];

Options and response

name, email, username and bulk take an $options array with ai_fallback and best_guess:

$result = $client->name('Andrea', country: 'IT', options: ['best_guess' => true]);

A result carries query, name, first_name, middle_name, last_name, name_type, gender, country, probability, sample_size, took_ms, source, confidence and matched_as, alongside credits_charged, credits_remaining, data_version and request_id. Success is the HTTP status: any non-2xx response throws NameGender\NameGenderException with status and body (['error', 'message', 'request_id', 'docs']). Branch on body['error'], not on the message.

Country distribution

Returns the countries a name is recorded in. This is not a country-of-origin or ethnicity inference, and must not be used as one.

$result = $client->countries('Mehmet', limit: 10);
print_r($result['registrations']); // [['country' => 'FR', 'count' => 3775, 'share' => 58.97, 'gender' => 'male', 'probability' => 99, 'source' => 'insee'], ...]
print_r($result['attested_in']);   // ['AL', 'AU', 'BE', ..., 'TR', 'US']
echo $result['basis']['note'];

The two lists are deliberately kept apart. registrations is measured volume and is comparable only among the seven countries that publish counted birth statistics (US, UK, France, Canada, Spain, Ireland, Norway); share is a percentage across those counts alone. attested_in is presence with no weight attached, which is where countries that publish no counts, such as Turkey, Japan and India, appear. Show basis.note next to any percentage you display.

limit (1–100, default 25) caps how many counted countries come back in registrations. One credit per request.

File jobs

Upload a CSV or XLSX file (up to 100 MB and 1,000,000 rows) and get it back with gender columns added. One credit per row, charged only if the job completes.

$batches = $client->batches();

$job = $batches->create('customers.csv', [   // a path, the file's contents (with 'filename') or a stream
    'name_column' => 'first_name',            // required to start
    'country_column' => 'country',            // optional: a country code per row
]);

$done = $batches->wait($job['id'], onProgress: fn (array $j) => print($j['progress']."\n"));
if ($done['status'] === 'failed') {
    throw new RuntimeException($done['error']['code']);
}

$batches->download($done['id'], 'customers-gender.csv');

name_column is required to start: a guessed column that turns out to be wrong would spend credits on the wrong data. To see the columns and the cost first, upload with 'start' => false, read $job['inspection'], then call $batches->start($job['id'], ['name_column' => ...]).

create sends an Idempotency-Key and retries network errors and 502/503/504 with the same key, so a retry never opens a second job. Pass your own idempotency_key to keep that guarantee across your own retries. create and download give up only after a transfer stalls for 300 seconds (other calls: 30); pass 'timeout' => ... to create, or timeout: to download, to change that.

wait returns a failed job rather than throwing; branch on $job['error']['code']. cancel returns the credit of a job that has not started, and deletes a finished one. list(limit:, page:) includes jobs started from the dashboard. Up to three jobs can be queued or running at once; a fourth is refused with 429 too_many_batches.

The result appends gender, probability, sample_size, country, source, matched_as, first_name, middle_name, last_name and name_type to every row. A CSV result starts with a UTF-8 byte order mark so that Excel reads it correctly; strip the first three bytes before handing it to fgetcsv.

Webhooks

Add an endpoint under Webhooks in the dashboard, and NameGender sends a signed POST to it when a file job completes or fails, and when credits are about to run out (credits.low) or have run out (credits.depleted, checked hourly). Webhooks::verify checks the signature and the timestamp, and returns the event.

use NameGender\Webhooks;
use NameGender\WebhookVerificationException;

try {
    $event = Webhooks::verify(
        file_get_contents('php://input'),   // the raw body, not a decoded $_POST
        $_SERVER['HTTP_NAMEGENDER_SIGNATURE'] ?? null,
        $_ENV['NAMEGENDER_WEBHOOK_SECRET'],
    );
} catch (WebhookVerificationException) {
    http_response_code(400);
    exit;
}

http_response_code(204);
if (function_exists('fastcgi_finish_request')) {
    fastcgi_finish_request();   // PHP-FPM: send the answer now, then do the work
}

if ($event['type'] === 'batch.completed') {
    $job = $event['data']['object'];   // the job, as batches()->get() returns it
}

In Laravel or Symfony, pass $request->getContent() and $request->header('NameGender-Signature') (Symfony: $request->headers->get(...)).

Use $event['id'] (also the NameGender-Event-Id header) to ignore a delivery you have already handled. A retry carries the same id, and order is not guaranteed. Anything other than a 2xx within 10 seconds is retried, up to 8 attempts over about 45 hours.