# GenderAPI.io V2: First-name and full-name lookup

> Predict from a first or full name with GenderAPI.io V2. Use type: name and value, optional country context, Unicode text and AI fallback.

Canonical HTML: https://www.genderapi.io/docs/v2/gender-from-name

Last reviewed: 2026-09-27

## Before sending the request

Send GenderAPI.io V2 prediction requests to POST https://api.genderapi.io/api/v2/gender with type and value in the JSON body. Use your existing GenderAPI.io key in Authorization: Bearer YOUR_API_KEY and Content-Type: application/json. Read the result from data and the access and billing information from meta. Every request is processed independently.

Choose your language in the code example. Set GENDERAPI_API_KEY in the process environment before running it. Missing or unrecognized keys can use the shared IP trial, so confirm meta.access.mode is api_key when integrating an account.

- [Authentication and trial access](https://www.genderapi.io/docs/v2/authentication)
- [All request parameters](https://www.genderapi.io/docs/v2/request-parameters)

## Gender from a name

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `type` | `string` | Yes | `—` | Input category: name, email or username. |
| `value` | `string` | Yes | `—` | Required. 1–254 characters; nonblank, without control characters. Email values must be valid email syntax. |
| `country` | `string` | No | `—` | Optional uppercase ISO 3166-1 alpha-2 code, for example TR or US. Country-specific lookup can fall back to the global dataset. |
| `forceToGenderize` | `boolean` | No | `false` | Try the dataset first, then nickname-aware AI if unresolved. Supported for name, email and username. |
| `options` | `object` | No | `—` | Container for per-input AI options. |
| `options.ai_mode` | `string` | No | `fallback` | Allowed values: off, fallback, always. With forceToGenderize: true, omit this field or use fallback. |
| `id` | `string` | No | `—` | Optional 1–64 character identifier in POST JSON. Returned beside each batch result; unique within a batch. Accepted but not echoed for single predictions. Not supported in GET queries. |

For a first name or full name, send type: name and the complete input in value to POST https://api.genderapi.io/api/v2/gender. GenderAPI.io V2 uses the same request fields for both name formats. A successful response may still contain data.gender: null. Single requests check the dataset first and, by default, ask AI when it cannot determine a gender.

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.

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

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.

**cURL**

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

```bash
curl --silent --show-error --fail-with-body --max-time 30 \
  --request POST 'https://api.genderapi.io/api/v2/gender' \
  --header "Authorization: Bearer ${GENDERAPI_API_KEY:?Set GENDERAPI_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{
  "type": "name",
  "value": "James",
  "country": "US"
}'
```

**JavaScript / Node.js**

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

```javascript
// 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 = {
  "type": "name",
  "value": "James",
  "country": "US"
};

const response = await fetch("https://api.genderapi.io/api/v2/gender", {
  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.
}
```

**Python**

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

```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("{\"type\":\"name\",\"value\":\"James\",\"country\":\"US\"}")

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",
    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.
```

**PHP**

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

```php
<?php
$apiKey = getenv('GENDERAPI_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('Set GENDERAPI_API_KEY');
}
$body = json_decode('{"type":"name","value":"James","country":"US"}', true, 512, JSON_THROW_ON_ERROR);

$ch = curl_init('https://api.genderapi.io/api/v2/gender');
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.
```

**Java**

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

```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 = "{\"type\":\"name\",\"value\":\"James\",\"country\":\"US\"}";
        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"))
            .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.
    }
}
```

**C# / .NET**

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

```csharp
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");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
request.Content = new StringContent("{\"type\":\"name\",\"value\":\"James\",\"country\":\"US\"}", 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.
}
```

**Go**

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

```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 := "{\"type\":\"name\",\"value\":\"James\",\"country\":\"US\"}"
    request, err := http.NewRequest("POST", "https://api.genderapi.io/api/v2/gender", 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)
    }
}
```

## Example response

This is a real response captured on 1 October 2026 with an API key; only the account balance is replaced. It is not a measure of accuracy, and a live request can return a different result. API-key requests report meta.access.mode: api_key and null trial-only quota fields; IP-trial requests report ip_trial. Read data for the inference and meta.usage for the operation's billing outcome.

```json
{
  "data": {
    "input": {
      "type": "name",
      "value": "James",
      "country": "US"
    },
    "name": "james",
    "gender": "male",
    "country": "US",
    "confidence": 0.9956045412377965,
    "confidence_kind": "observed_frequency",
    "sample_count": 45274,
    "source": "dataset",
    "result_status": "identified",
    "reason": null,
    "country_source": "dataset",
    "match": {
      "name": "james",
      "method": "normalized",
      "scope": "country",
      "country": "US"
    }
  },
  "meta": {
    "request_id": "7b68043d-2656-4e2d-abcf-dabb4bbc6445",
    "duration_ms": 12,
    "access": {
      "mode": "api_key",
      "reason": null
    },
    "usage": {
      "charged_credits": 1,
      "remaining_credits": 49999,
      "billing_status": "confirmed",
      "resets_at": null,
      "limit": null,
      "period_seconds": null
    }
  }
}
```

- [Response fields and confidence](https://www.genderapi.io/docs/v2/responses)

## Prediction response fields

| Field | Type | Nullable | Example | Description |
| --- | --- | --- | --- | --- |
| `data.input` | `object` | No | `{"type":"name","value":"James","country":"US"}` | Input type, value and country. forceToGenderize is included when true. |
| `data.name` | `string` | Yes | `"james"` | Matched or extracted given name; null when none is available. |
| `data.gender` | `string` | Yes | `"male"` | male, female or JSON null. An inference, not verified personal identity. |
| `data.result_status` | `string` | No | `"identified"` | identified when a gender is returned; unknown otherwise. |
| `data.reason` | `string` | Yes | `null` | Null for identified results. Unknown reasons: not_found, no_name_candidate, ambiguous or insufficient_evidence. |
| `data.confidence` | `number` | Yes | `0.95` | 0–1 score or null. Null gender has null confidence. |
| `data.confidence_kind` | `string` | Yes | `"observed_frequency"` | observed_frequency: dominant dataset count / total. model_reported: AI score, not a calibrated probability. Null when unavailable. |
| `data.sample_count` | `integer` | Yes | `1200` | Dataset sample size or null. AI does not invent a sample count. |
| `data.source` | `string` | No | `"dataset"` | dataset, ai or none. |
| `data.country` | `string` | Yes | `"US"` | Country association from dataset or ai_association, or null. Does not establish nationality, residence or ethnicity. |
| `data.country_source` | `string` | Yes | `"dataset"` | Origin of the country association: dataset, ai_association or null. |
| `data.match` | `object` | No | `{"name":"james","method":"normalized","scope":"country","country":"US"}` | Matched dataset name, method (normalized, token, substring or model_inference), country/global scope and matched country. Unavailable evidence is null. |

## Access, billing and request metadata

| Field | Type | Nullable | Example | Description |
| --- | --- | --- | --- | --- |
| `meta.request_id` | `string` | No | `"550e8400-e29b-41d4-a716-446655440000"` | Unique identifier for this HTTP attempt; also sent in X-Request-ID. |
| `meta.duration_ms` | `integer` | No | `42` | Request processing time in milliseconds. |
| `meta.access.mode` | `string` | No | `"api_key"` | api_key, ip_trial or unauthenticated. Verify api_key when using a paid account. |
| `meta.access.reason` | `string` | Yes | `null` | Trial fallback reason: api_key_missing, api_key_invalid or api_key_not_found; null otherwise. |
| `meta.usage.charged_credits` | `integer` | Yes | `1` | Net credits charged. Zero before charging or after a full confirmed refund; null when billing is unconfirmed. |
| `meta.usage.remaining_credits` | `integer` | Yes | `99` | Balance when the operation completes. May be negative; null when unavailable or billing is unconfirmed. |
| `meta.usage.billing_status` | `string` | No | `"confirmed"` | not_charged, confirmed or unconfirmed. Check this before retrying a failed prediction. |
| `meta.usage.resets_at` | `string` | Yes | `"2026-09-27T12:00:00.000Z"` | IP trial reset time in UTC (ISO 8601); null for API-key accounts or when unknown. |
| `meta.usage.limit` | `integer` | Yes | `10` | IP trial allowance; null for API-key accounts. |
| `meta.usage.period_seconds` | `integer` | Yes | `86400` | IP trial window in seconds; null for API-key accounts. |

## Country context and unknown names

Supply country only when you have relevant context. The API can select a country-specific dataset row or fall back to a global row. data.match.scope shows which was selected; the returned country does not establish where the person lives.

Single requests default to AI fallback for 1 credit total. To use only the dataset, send options: {"ai_mode": "off"}. Unresolved inputs can return gender: null and are still billable when the operation succeeds. A full name may match a component; data.match records the selected candidate and matching method.

For nickname-like name values, forceToGenderize: true permits inference without a real given name: a resolved dataset result costs 1 credit; otherwise nickname-aware AI costs 2 total. A positive starting balance is sufficient and the resulting balance can be negative.

## Look up a full name without assuming the first word wins

Send the original Unicode name. Dataset matching applies NFKC normalization, lowercasing and token extraction; it does not require you to convert the name to ASCII. Among the available candidate records, the API selects the record with the largest stored total. That candidate can be a later component of the name, so do not assume the first word or the given name was selected.

This dataset-only request makes the selected evidence easier to inspect. Read data.input.value for the submitted full name, data.match.name for the lookup candidate and data.match.method for the matching method. The example does not promise a particular gender or selected token. Dataset candidates must be longer than two characters; short inputs may be unresolved. Use ordinary AI fallback when that additional inference is appropriate for your application.

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.

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

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.

**cURL**

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

```bash
curl --silent --show-error --fail-with-body --max-time 30 \
  --request POST 'https://api.genderapi.io/api/v2/gender' \
  --header "Authorization: Bearer ${GENDERAPI_API_KEY:?Set GENDERAPI_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data '{
  "type": "name",
  "value": "Ayşe Yılmaz",
  "country": "TR",
  "options": {
    "ai_mode": "off"
  }
}'
```

**JavaScript / Node.js**

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

```javascript
// 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 = {
  "type": "name",
  "value": "Ayşe Yılmaz",
  "country": "TR",
  "options": {
    "ai_mode": "off"
  }
};

const response = await fetch("https://api.genderapi.io/api/v2/gender", {
  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.
}
```

**Python**

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

```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("{\"type\":\"name\",\"value\":\"Ayşe Yılmaz\",\"country\":\"TR\",\"options\":{\"ai_mode\":\"off\"}}")

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",
    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.
```

**PHP**

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

```php
<?php
$apiKey = getenv('GENDERAPI_API_KEY');
if (!$apiKey) {
    throw new RuntimeException('Set GENDERAPI_API_KEY');
}
$body = json_decode('{"type":"name","value":"Ayşe Yılmaz","country":"TR","options":{"ai_mode":"off"}}', true, 512, JSON_THROW_ON_ERROR);

$ch = curl_init('https://api.genderapi.io/api/v2/gender');
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.
```

**Java**

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

```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 = "{\"type\":\"name\",\"value\":\"Ayşe Yılmaz\",\"country\":\"TR\",\"options\":{\"ai_mode\":\"off\"}}";
        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"))
            .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.
    }
}
```

**C# / .NET**

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

```csharp
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");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
request.Content = new StringContent("{\"type\":\"name\",\"value\":\"Ayşe Yılmaz\",\"country\":\"TR\",\"options\":{\"ai_mode\":\"off\"}}", 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.
}
```

**Go**

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

```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 := "{\"type\":\"name\",\"value\":\"Ayşe Yılmaz\",\"country\":\"TR\",\"options\":{\"ai_mode\":\"off\"}}"
    request, err := http.NewRequest("POST", "https://api.genderapi.io/api/v2/gender", 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)
    }
}
```

- [Choose dataset-only or AI fallback](https://www.genderapi.io/docs/v2/ai-options)
- [When the input is an email address](https://www.genderapi.io/determine-gender-from-email)
- [When the input is a username](https://www.genderapi.io/determine-gender-from-username)

## Check which country context actually contributed

Use an ISO country code only when you have relevant context; do not manufacture one from the predicted result. For each candidate, an available country row takes precedence over its global row. If no country row exists, the candidate can use a global row. A country row with tied counts is not replaced by its global row; if the selected row is tied, the dataset result is unknown and an enabled AI fallback can run.

| Response evidence | Interpretation | Application action |
| --- | --- | --- |
| match.scope: country; match.country: TR | The selected dataset candidate used the requested country's row. | Keep the selected candidate and country scope with the prediction. |
| match.scope: global; match.country: null | The selected candidate used a global row, even if the request supplied a country. | Do not label the result as a country-specific match. |
| country_source: dataset or ai_association | Explains the origin of data.country, not the dataset lookup scope or the person's nationality. | Read it separately from match.country; neither field verifies residence or nationality. |
| source: ai; match.scope: null | AI produced the final response, so there is no selected dataset row in that response. | Use the AI confidence guidance and retain unknown outcomes. |

- [Read unknown and confidence outcomes](https://www.genderapi.io/docs/v2/responses#application-decisions)
- [How dataset evidence and AI inference differ](https://www.genderapi.io/data-provenance)

## Related guides

- [AI modes and forceToGenderize](https://www.genderapi.io/docs/v2/ai-options)
- [Batch predictions](https://www.genderapi.io/docs/v2/batch)
- [Credits and usage](https://www.genderapi.io/docs/v2/credits-and-usage)
- [Errors and retries](https://www.genderapi.io/docs/v2/errors-and-retries)
