API DOCUMENTATION V2

Batch name, email and username predictions

Send up to 50 GenderAPI v2 predictions in one batch. Learn per-item options, preserved IDs, partial failures, response summaries and credit accounting.

Batch names, emails and usernames

POST /gender/batch accepts an items array with 1–50 items for API-key access, or at most 10 for the IP trial. You can send only names, only emails, only usernames, or mix all three. Each item has its own country, forceToGenderize and options. IDs are optional and must be unique.

Results preserve input order and include index, your optional id, charged_credits and exactly one of data or error. HTTP 200 can contain item-level failures, so inspect every item. meta.summary reports total, succeeded, identified, unknown and failed. An unknown prediction is a successful, billable item.

Request validation or planning failure rejects the batch before debit. If every executed item fails, the API returns a non-2xx Problem response with a data array and a legacy results alias. Failed items cost zero after a confirmed refund. If billing is unconfirmed, do not assume item charges are final.

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": "contact-1",
      "type": "name",
      "value": "Onur",
      "country": "TR"
    },
    {
      "id": "contact-2",
      "type": "email",
      "value": "alice.smith@example.com",
      "options": {
        "ai_mode": "fallback"
      }
    },
    {
      "id": "contact-3",
      "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": "contact-1",
      "type": "name",
      "value": "Onur",
      "country": "TR"
    },
    {
      "id": "contact-2",
      "type": "email",
      "value": "alice.smith@example.com",
      "options": {
        "ai_mode": "fallback"
      }
    },
    {
      "id": "contact-3",
      "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\":\"contact-1\",\"type\":\"name\",\"value\":\"Onur\",\"country\":\"TR\"},{\"id\":\"contact-2\",\"type\":\"email\",\"value\":\"alice.smith@example.com\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"contact-3\",\"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":"contact-1","type":"name","value":"Onur","country":"TR"},{"id":"contact-2","type":"email","value":"alice.smith@example.com","options":{"ai_mode":"fallback"}},{"id":"contact-3","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\":\"contact-1\",\"type\":\"name\",\"value\":\"Onur\",\"country\":\"TR\"},{\"id\":\"contact-2\",\"type\":\"email\",\"value\":\"alice.smith@example.com\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"contact-3\",\"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\":\"contact-1\",\"type\":\"name\",\"value\":\"Onur\",\"country\":\"TR\"},{\"id\":\"contact-2\",\"type\":\"email\",\"value\":\"alice.smith@example.com\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"contact-3\",\"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\":\"contact-1\",\"type\":\"name\",\"value\":\"Onur\",\"country\":\"TR\"},{\"id\":\"contact-2\",\"type\":\"email\",\"value\":\"alice.smith@example.com\",\"options\":{\"ai_mode\":\"fallback\"}},{\"id\":\"contact-3\",\"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

Read a batch response

This independent synthetic example contains a dataset match, an unknown result and a provider failure. It illustrates a partial-success HTTP 200 response, not the expected output of the batch request above. The two successful items cost 1 credit each; the failed item has a confirmed zero charge.

Illustrative JSON response
{
  "data": [
    {
      "index": 0,
      "id": "known",
      "charged_credits": 1,
      "data": {
        "input": {
          "type": "name",
          "value": "Onur",
          "country": "TR"
        },
        "name": "onur",
        "gender": "male",
        "country": "TR",
        "confidence": 0.9,
        "confidence_kind": "observed_frequency",
        "sample_count": 100,
        "source": "dataset",
        "result_status": "identified",
        "reason": null,
        "country_source": "dataset",
        "match": {
          "name": "onur",
          "method": "normalized",
          "scope": "country",
          "country": "TR"
        }
      }
    },
    {
      "index": 1,
      "id": "missing",
      "charged_credits": 1,
      "data": {
        "input": {
          "type": "name",
          "value": "zzzxxyy",
          "country": null
        },
        "name": null,
        "gender": null,
        "country": null,
        "confidence": null,
        "confidence_kind": null,
        "sample_count": null,
        "source": "none",
        "result_status": "unknown",
        "reason": "not_found",
        "country_source": null,
        "match": {
          "name": null,
          "method": null,
          "scope": null,
          "country": null
        }
      }
    },
    {
      "index": 2,
      "id": "failed",
      "charged_credits": 0,
      "error": {
        "type": "urn:genderapi:problem:ai_upstream_error",
        "title": "ai upstream error",
        "status": 502,
        "detail": "The AI provider could not complete the request.",
        "instance": "urn:uuid:11111111-1111-4111-8111-111111111111",
        "code": "ai_upstream_error",
        "request_id": "11111111-1111-4111-8111-111111111111",
        "documentation": "https://api.genderapi.io/api/v2/errors",
        "action": "inspect_billing_before_retry"
      }
    }
  ],
  "meta": {
    "request_id": "11111111-1111-4111-8111-111111111111",
    "duration_ms": 12,
    "access": {
      "mode": "ip_trial",
      "reason": "api_key_missing"
    },
    "usage": {
      "charged_credits": 2,
      "remaining_credits": 6,
      "billing_status": "confirmed",
      "resets_at": "2026-09-26T12:00:00.000Z",
      "limit": 10,
      "period_seconds": 86400
    },
    "summary": {
      "total": 3,
      "succeeded": 2,
      "identified": 1,
      "unknown": 1,
      "failed": 1
    }
  }
}

Plan batch credits and retries

Authenticate with your existing Bearer API key and send Content-Type: application/json. Every submitted batch is a new operation. If retrying a partial failure, submit only the failed items after checking billing; resending successful items charges them again.

Batch items default to AI off and cost 1 credit per successful item. Explicit fallback also costs 1 total, including AI. Always costs 2. forceToGenderize costs 1 for a resolved dataset result or 2 if AI is used. Successful unknowns are charged. One positive starting credit is enough to begin the batch; its final charge may leave a negative balance.