Username data workflow · API V2

Analyze usernames and nicknames with API V2

Build a batch workflow for usernames and nicknames with GenderAPI V2. Choose dataset or AI policies per row, retain unknown results, and reconcile credits before retrying.

Can a username be analyzed without a real given name?

Yes, when you explicitly enable forceToGenderize. V2 first tries the dataset; if no gender is resolved, nickname-aware AI can interpret an alias without extracting a real given name. That is an inference, not verified identity, and the result may remain unknown. Without this option, ordinary AI inference requires a usable real given name.

This guide focuses on processing a dataset of handles with row-level policies and recoverable results. Use the username tool for a single interactive lookup, then use the batch workflow below when you are ready to integrate.

Try the V2 API

Analyze a username

Dataset + AI

Submit one value and inspect the complete response, including unknown results and credit usage.

Always AI (default): 2 credits, including an unknown result. Fallback: 1 credit, including AI fallback or an unknown result. Off, dataset only without AI: 1 credit per completed lookup, including an unknown result. With nickname inference enabled: 1 credit for a usable dataset result, or 2 credits total for AI, including an unknown result.

The submitted username goes to GenderAPI.io and is sent to the configured AI service in Always AI mode (the default) or when fallback needs it, but not in Off mode. Processing details.

No saved API key. The shared IP trial is available while credits remain.

Real response captured on 1 October 2026 below. Select Analyze username to run a live lookup.

Real V2 response · captured 1 October 2026
NameDaniel
GenderMale
Confidence98%
SourceAI model
Credits used2

This real response was captured on 1 October 2026; only the account balance is replaced. Live values may differ. A prediction is not verified identity.

Preserve the handle and choose the input type

Keep your source-system record ID, the original handle and any person-supplied name in separate fields. Send the handle as type: username, not as a full profile URL. Use type: email for email addresses and type: name when the source is an actual name. The API does not fetch a social profile or verify account ownership.

Dataset processing removes a leading @, normalizes the text and derives candidates from delimiters and digits. Ordinary lookup may add bounded prefix and suffix candidates for a concatenated handle; forceToGenderize keeps token matching but omits those extra substring candidates. Multiple matches are resolved by the largest stored total, so inspect match.name and match.method instead of assuming that the handle contains a verified first name.

Example inputWhat your application should preserve
@alice_smithKeep the original handle and inspect the selected candidate; the API may match a component.
prensesKeep the alias even if nickname inference returns a gender with name: null. It has not established a real name.
user47291Keep unknown as a valid outcome. Digits or an opaque identifier do not establish a person's gender.

Choose a policy for each row before submission

Batch items default to AI off, while single requests default to ordinary fallback. Choose explicitly when the distinction matters. forceToGenderize is optional for username, name and email inputs; it accepts an omitted ai_mode or fallback, but conflicts with off and always.

Successful unknown outcomes are also charged. A positive starting credit balance is sufficient to begin an operation, and the final debit can take it below zero. Use meta.usage and each item's charged_credits to reconcile the completed operation, rather than treating a maximum cost estimate as its final charge.

PolicyProcessingSuccessful item cost
options.ai_mode: offDataset only; unresolved inputs remain unknown.1 credit
options.ai_mode: fallbackDataset first, then ordinary AI if no gender is resolved.1 credit total, including AI
options.ai_mode: alwaysAI directly, without a dataset lookup.2 credits
forceToGenderize: trueDataset first, then nickname-aware AI when unresolved; a real name is not required.1 credit for a resolved dataset result; 2 total if AI is used

Submit a batch with stable row identifiers

The request below demonstrates three choices: a dataset-only handle, ordinary AI fallback and nickname-aware fallback. These are example inputs, not expected predictions. Use your existing Bearer API key; keep GENDERAPI_API_KEY on your server. Give every item an id that is unique within this batch.

Send at most 50 items per API-key batch or 10 for the shared IP trial. For a longer file or database export, maintain a job ID and the source row independently of each batch's zero-based index. Do not use a display name as the identifier, because different records can share it.

Choose your language. Set up your API key, then run the example on your server.

Every prediction request is a new billable operation, including retries. These examples do not automatically retry. Check billing status before sending another request.

Before you run: access and error handling

Run these examples on your server. Set GENDERAPI_API_KEY in the process environment to your existing API key. Confirm meta.access.mode is api_key: an unrecognized key can fall back to the IP trial.

HTTP 4xx and 5xx JSON responses preserve the error body and return a nonzero exit status. Check code, action and meta.usage.billing_status before retrying. For HTTP 200 batch responses, also inspect each item's data or error.

Error and retry guide →
cURL
curl --silent --show-error --fail-with-body --max-time 30 \
  --request POST 'https://api.genderapi.io/api/v2/gender/batch' \
  --header "Authorization: Bearer ${GENDERAPI_API_KEY:?Set GENDERAPI_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{
  "items": [
    {
      "id": "profile-001",
      "type": "username",
      "value": "@alice_smith",
      "options": {
        "ai_mode": "off"
      }
    },
    {
      "id": "profile-002",
      "type": "username",
      "value": "alexriver",
      "options": {
        "ai_mode": "fallback"
      }
    },
    {
      "id": "profile-003",
      "type": "username",
      "value": "prenses",
      "country": "TR",
      "forceToGenderize": true
    }
  ]
}'

cURL 7.76+ in a POSIX shell. Run in your terminal. Runtime documentation

JavaScript / Node.js
// Server-side Node.js. Save as example.mjs.
const apiKey = process.env.GENDERAPI_API_KEY;
if (!apiKey) throw new Error("Set GENDERAPI_API_KEY");
const body = {
  "items": [
    {
      "id": "profile-001",
      "type": "username",
      "value": "@alice_smith",
      "options": {
        "ai_mode": "off"
      }
    },
    {
      "id": "profile-002",
      "type": "username",
      "value": "alexriver",
      "options": {
        "ai_mode": "fallback"
      }
    },
    {
      "id": "profile-003",
      "type": "username",
      "value": "prenses",
      "country": "TR",
      "forceToGenderize": true
    }
  ]
};

const response = await fetch("https://api.genderapi.io/api/v2/gender/batch", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(body),
  signal: AbortSignal.timeout(30_000),
  redirect: "error",
});
const raw = await response.text();
if (!(response.headers.get("content-type") ?? "").includes("json")) {
  throw new Error(`HTTP ${response.status}: expected JSON; request ID ${response.headers.get("x-request-id")}`);
}
const result = JSON.parse(raw); // Also accepts application/problem+json.
if (!response.ok) {
  console.error(`HTTP ${response.status}`, result);
  process.exitCode = 1; // A retry is a new operation; inspect billing first.
} else {
  console.log(JSON.stringify(result, null, 2));
  // For batches, inspect every item: HTTP 200 may contain item errors.
}

Node.js 22+; built-in fetch. Save as example.mjs and run node example.mjs. Runtime documentation

Python
import json
import os
import sys
import urllib.error
import urllib.request

api_key = os.environ.get("GENDERAPI_API_KEY")
if not api_key:
    raise RuntimeError("Set GENDERAPI_API_KEY")
body = json.loads("{\"items\":[{\"id\":\"profile-001\",\"type\":\"username\",\"value\":\"@alice_smith\",\"options\":{\"ai_mode\":\"off\"}},{\"id\":\"profile-002\",\"type\":\"username\",\"value\":\"alexriver\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"profile-003\",\"type\":\"username\",\"value\":\"prenses\",\"country\":\"TR\",\"forceToGenderize\":true}]}")

class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None

request = urllib.request.Request(
    "https://api.genderapi.io/api/v2/gender/batch",
    method="POST",
    data=json.dumps(body).encode("utf-8"),
    headers={
        "Authorization": "Bearer " + api_key,
        "Content-Type": "application/json",
    },
)
opener = urllib.request.build_opener(NoRedirect())
try:
    response = opener.open(request, timeout=30)
except urllib.error.HTTPError as error:
    response = error  # Keep the Problem Details body on non-2xx responses.
with response:
    status = response.status
    raw = response.read().decode("utf-8")
    if "json" not in response.headers.get("Content-Type", ""):
        raise RuntimeError(f"HTTP {status}: expected a JSON response")
    result = json.loads(raw)
print(json.dumps(result, indent=2), file=sys.stderr if status >= 300 else sys.stdout)
if not 200 <= status < 300:
    sys.exit(1)  # Inspect code, action and billing before retrying.
# For batches, inspect every item even when HTTP status is 200.

Python 3.10+; standard library. Save as example.py and run python3 example.py. Runtime documentation

PHP
<?php
$apiKey = getenv('GENDERAPI_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('Set GENDERAPI_API_KEY');
}
$body = json_decode('{"items":[{"id":"profile-001","type":"username","value":"@alice_smith","options":{"ai_mode":"off"}},{"id":"profile-002","type":"username","value":"alexriver","options":{"ai_mode":"fallback"}},{"id":"profile-003","type":"username","value":"prenses","country":"TR","forceToGenderize":true}]}', true, 512, JSON_THROW_ON_ERROR);

$ch = curl_init('https://api.genderapi.io/api/v2/gender/batch');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FOLLOWLOCATION => false,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $apiKey,
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($body, JSON_THROW_ON_ERROR),
]);
$raw = curl_exec($ch);
if ($raw === false) {
    throw new RuntimeException(curl_error($ch));
}
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE) ?: '';
curl_close($ch);
if (strpos($contentType, 'json') === false) {
    throw new RuntimeException("HTTP $status: expected a JSON response");
}
$result = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
$output = json_encode($result, JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR) . PHP_EOL;
if ($status < 200 || $status >= 300) {
    fwrite(STDERR, $output); // Preserve the Problem Details body.
    exit(1);
}
echo $output;
// For batches, inspect every item; HTTP 200 can contain item errors.

PHP 8+ with the cURL extension. Save as example.php and run php example.php. Runtime documentation

Java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;

public class GenderApiExample {
    private static String requiredEnv(String name) {
        String value = System.getenv(name);
        if (value == null || value.isBlank()) throw new IllegalStateException("Set " + name);
        return value;
    }

    public static void main(String[] args) throws Exception {
        String apiKey = requiredEnv("GENDERAPI_API_KEY");
        String body = "{\"items\":[{\"id\":\"profile-001\",\"type\":\"username\",\"value\":\"@alice_smith\",\"options\":{\"ai_mode\":\"off\"}},{\"id\":\"profile-002\",\"type\":\"username\",\"value\":\"alexriver\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"profile-003\",\"type\":\"username\",\"value\":\"prenses\",\"country\":\"TR\",\"forceToGenderize\":true}]}";
        HttpClient client = HttpClient.newBuilder()
            .connectTimeout(Duration.ofSeconds(10))
            .followRedirects(HttpClient.Redirect.NEVER)
            .build();
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.genderapi.io/api/v2/gender/batch"))
            .timeout(Duration.ofSeconds(30))
            .header("Authorization", "Bearer " + apiKey)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(body, StandardCharsets.UTF_8))
            .build();
        HttpResponse<String> response = client.send(request,
            HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
        if (!response.headers().firstValue("content-type").orElse("").contains("json")) {
            throw new IllegalStateException("HTTP " + response.statusCode() + ": expected JSON");
        }
        // JSON text; parse with your application's JSON library when integrating.
        if (response.statusCode() < 200 || response.statusCode() >= 300) {
            System.err.println(response.body()); // Includes Problem Details.
            System.exit(1);
        }
        System.out.println(response.body());
        // For batches, inspect each item's data or error, including on HTTP 200.
    }
}

Java 17+; standard HTTP client. Save as GenderApiExample.java and run java GenderApiExample.java. Runtime documentation

C# / .NET
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

string RequiredEnv(string name) =>
    !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(name))
        ? Environment.GetEnvironmentVariable(name)!
        : throw new InvalidOperationException($"Set {name}");

var apiKey = RequiredEnv("GENDERAPI_API_KEY");
using var handler = new HttpClientHandler { AllowAutoRedirect = false };
using var client = new HttpClient(handler) { Timeout = TimeSpan.FromSeconds(30) };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://api.genderapi.io/api/v2/gender/batch");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
request.Content = new StringContent("{\"items\":[{\"id\":\"profile-001\",\"type\":\"username\",\"value\":\"@alice_smith\",\"options\":{\"ai_mode\":\"off\"}},{\"id\":\"profile-002\",\"type\":\"username\",\"value\":\"alexriver\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"profile-003\",\"type\":\"username\",\"value\":\"prenses\",\"country\":\"TR\",\"forceToGenderize\":true}]}", Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
var raw = await response.Content.ReadAsStringAsync();
if (!(response.Content.Headers.ContentType?.MediaType?.Contains("json") ?? false))
    throw new InvalidOperationException($"HTTP {(int)response.StatusCode}: expected JSON");
using var result = JsonDocument.Parse(raw);
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(result.RootElement); // Preserve Problem Details.
    Environment.ExitCode = 1;
}
else
{
    Console.WriteLine(result.RootElement);
    // For batches, inspect every item even on HTTP 200.
}

.NET 8+ console application. Use as Program.cs in a console project, then run dotnet run. Runtime documentation

Go
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "strings"
    "time"
)

func requiredEnv(name string) string {
    value := os.Getenv(name)
    if value == "" { panic("Set " + name) }
    return value
}

func run() error {
    apiKey := requiredEnv("GENDERAPI_API_KEY")
    body := "{\"items\":[{\"id\":\"profile-001\",\"type\":\"username\",\"value\":\"@alice_smith\",\"options\":{\"ai_mode\":\"off\"}},{\"id\":\"profile-002\",\"type\":\"username\",\"value\":\"alexriver\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"profile-003\",\"type\":\"username\",\"value\":\"prenses\",\"country\":\"TR\",\"forceToGenderize\":true}]}"
    request, err := http.NewRequest("POST", "https://api.genderapi.io/api/v2/gender/batch", strings.NewReader(body))
    if err != nil { return err }
    request.Header.Set("Authorization", "Bearer " + apiKey)
    request.Header.Set("Content-Type", "application/json")
    client := &http.Client{
        Timeout: 30 * time.Second,
        CheckRedirect: func(req *http.Request, via []*http.Request) error {
            return http.ErrUseLastResponse
        },
    }
    response, err := client.Do(request)
    if err != nil { return err }
    defer response.Body.Close()
    raw, err := io.ReadAll(response.Body)
    if err != nil { return err }
    if !strings.Contains(response.Header.Get("Content-Type"), "json") || !json.Valid(raw) {
        return fmt.Errorf("HTTP %d: expected a JSON response", response.StatusCode)
    }
    if response.StatusCode < 200 || response.StatusCode >= 300 {
        return fmt.Errorf("HTTP %d: %s", response.StatusCode, raw)
    }
    fmt.Println(string(raw))
    // For batches, inspect every item even on HTTP 200.
    return nil
}

func main() {
    if err := run(); err != nil {
        fmt.Fprintln(os.Stderr, err) // Keep Problem Details for error handling.
        os.Exit(1)
    }
}

Go 1.22+; standard library. Save as main.go and run go run main.go. Runtime documentation

Reconcile every row, including unknowns and errors

Read the response as a set of item outcomes. HTTP 200 does not guarantee that all items succeeded, and a successful item does not guarantee an identified gender. Save meta.request_id and map each item back to the original record using its id or index.

When billing is confirmed, retry only failed items whose errors warrant another attempt. Resubmitting successful items, including unknowns, starts new billable operations. meta.summary.succeeded includes both identified and unknown items, so retain those categories separately in your own job report.

Item outcomeHow to store or handle it
data.result_status: identifiedStore gender together with source, confidence_kind, confidence and match. An identified inference remains an estimate.
data.name: null with a genderValid in nickname mode. Preserve the alias; do not manufacture a real name from the prediction.
data.result_status: unknownKeep JSON null and reason. not_found, no_name_candidate, ambiguous and insufficient_evidence describe different unresolved outcomes; none is an automatic retry instruction.
error presentKeep the error code. Check billing and the error's retry guidance before resubmitting that failed item.
meta.usage.billing_status: unconfirmed or response lostPause and reconcile before retrying; a missing response does not prove that credits were not charged.

Evaluate a policy before filling a dataset

Use representative, independently labeled examples for the languages, input styles and modes your application will process. Evaluate dataset observed_frequency and AI model_reported scores separately. There is no universal confidence cutoff that proves a username prediction correct, and stored sample_count is not a product-accuracy measurement.

Keep an unknown or review path, retain information supplied by the person, and record how many inputs your chosen policy answers as well as how often those answered predictions are correct. If AI is invoked, the submitted username and country context go to the configured inference service; the API does not return the underlying model revision in the prediction response.

Frequently asked questions

Does a username lookup visit the social-media profile?

No. V2 analyzes the submitted value and optional country context. It does not fetch a social profile or verify that the handle belongs to a particular person.

Can nickname inference return a gender when name is null?

Yes. forceToGenderize allows nickname-aware inference without a real given name. A non-null gender with name: null can therefore be an identified result; it is still an estimate and does not verify identity.

Should I retry every unknown item in a batch?

No. Unknown items are completed, billable outcomes. Retry decisions apply to operational errors after checking billing and the error guidance. Resending a successful item, including an unknown, is a new billable operation.

Published June 4, 2025Last reviewed

Connect your application

Use the complete V2 contract

Choose request options and handle both identified and unknown outcomes.

Continue testing

Use your GenderAPI key

Paste the API key from your GenderAPI account to keep testing after this IP address has used its shared 10-credit trial for the current 24-hour window.

Stored only for this browser tab. It is cleared when the tab is closed.