# Determine gender from Indian names

> Try names used in India with GenderAPI V2. Preserve original spellings, choose IN context deliberately and interpret full-name, AI and unknown outcomes.

Canonical HTML: https://www.genderapi.io/determine-gender-from-indian-names

Last reviewed: 2026-09-26

## Use the original name without assuming one script or naming pattern

This demonstration uses a Devanagari example and IN country context. It is one input example, not a definition of all names used in India. The API receives Unicode strings, so you can submit the spelling present in your record without first converting it to Latin script.

The dataset path uses normalized tokens and does not perform general script conversion or promise that Latin and original-script spellings resolve to the same record. Keep the original input alongside any returned name. Accepting a script does not establish independently measured accuracy for that language or community.

Do not assume that the first or last token has a fixed role. V2 selects the available candidate record with the largest stored total, rather than guaranteeing a particular given-name position. Initials, short tokens and missing stored matches can leave the dataset result unresolved; AI fallback may attempt the full submitted value.

| Example input | What it represents | What to check |
| --- | --- | --- |
| `प्रिया शर्मा` | Devanagari full-name example | Several tokens may become candidates. Inspect the chosen name and match instead of assuming the first token wins. |
| `Priya Sharma` | Latin-script example | This is a separate input spelling; no identical-match promise is made across scripts. |
| `A. Kumar` | Initial plus name token | The one-letter initial does not become a dataset candidate. A match to another token does not establish the intended given name. |
| `country: IN` | India demo context | Use it when your record has relevant country context, not simply because the name appears in this guide. |

## Choose IN context deliberately

The live demo sends country: IN (India). The API does not choose this country from the name's script. In your integration, use known, relevant context or omit country; do not turn this sample value into a default for every record.

For each candidate, the dataset path prefers an existing country-specific record and otherwise considers the global record. It then selects the available candidate with the largest stored total. Inspect data.match.scope and data.match.country to see the actual match scope. An ambiguous country-specific record is not automatically replaced by a global result; fallback may use AI instead.

data.input.country describes the request context. data.country and data.country_source describe a returned association. They are different fields and do not establish citizenship, ethnicity or residence.

- [Country context and matching reference](https://www.genderapi.io/docs/v2/gender-from-name#country-evidence-workflow)

## Send a Indian name with V2

Run the request on your server with GENDERAPI_API_KEY set to your existing key. The example explicitly enables ordinary AI fallback. It illustrates a request, not a measured prediction or coverage result. Use options.ai_mode: off for dataset-only processing.

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": "प्रिया शर्मा",
  "country": "IN",
  "options": {
    "ai_mode": "fallback"
  }
}'
```

**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": "प्रिया शर्मा",
  "country": "IN",
  "options": {
    "ai_mode": "fallback"
  }
};

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\":\"प्रिया शर्मा\",\"country\":\"IN\",\"options\":{\"ai_mode\":\"fallback\"}}")

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":"प्रिया शर्मा","country":"IN","options":{"ai_mode":"fallback"}}', 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\":\"प्रिया शर्मा\",\"country\":\"IN\",\"options\":{\"ai_mode\":\"fallback\"}}";
        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\":\"प्रिया शर्मा\",\"country\":\"IN\",\"options\":{\"ai_mode\":\"fallback\"}}", 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\":\"प्रिया शर्मा\",\"country\":\"IN\",\"options\":{\"ai_mode\":\"fallback\"}}"
    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)
    }
}
```

- [Name request parameters](https://www.genderapi.io/docs/v2/gender-from-name)
- [Set up authentication](https://www.genderapi.io/docs/v2/authentication)

## Keep the result and its evidence together

An inferred association is not a person's self-declared gender. Keep the original input, the returned evidence and any information provided by the person separate. An unknown result is a valid outcome; it should not become a guessed category in your application.

| Field | How to use it |
| --- | --- |
| `data.gender / data.result_status` | Use male or female only when identified. Preserve native JSON null when the result is unknown. |
| `data.name / data.match` | Inspect the returned name and selected candidate. A substring match does not prove that the input belongs to someone with that given name. |
| `data.confidence / data.confidence_kind` | Confidence is on a 0–1 scale or null. observed_frequency comes from stored counts; model_reported is an AI score. Evaluate thresholds separately for each kind. |
| `data.source / data.sample_count` | Distinguish dataset, ai and none. AI results have no stored sample count. A sample count is not a measured accuracy score. |
| `meta.access.mode` | Confirm api_key for an account integration. Missing or unrecognized keys can instead use the shared IP trial. |
| `meta.usage` | Read charged_credits and billing_status. A successful unknown is billable. A lost response does not establish that the request was free. |

- [Response fields and unknown outcomes](https://www.genderapi.io/docs/v2/responses)
- [Accuracy and confidence explained](https://www.genderapi.io/accuracy-methodology)
- [Data sources and the dated database profile](https://www.genderapi.io/data-provenance)

## Choose when to use AI

forceToGenderize is optional for names, email addresses and usernames. With it enabled, omit ai_mode or use fallback; off and always conflict with it and return 422. A positive starting balance is enough to begin a request even if its final charge takes the balance below zero.

Nickname mode can return a gender with name: null. It can also return an unknown result. Neither ordinary fallback nor nickname inference guarantees a correct or non-null answer.

| Request option | Behavior | Credits for a successful lookup |
| --- | --- | --- |
| options.ai_mode: off | Use the dataset only. | 1, including an unknown result |
| options.ai_mode: fallback | Try the dataset, then ordinary AI when no gender is returned. This is the single-request default. | 1 total, including AI fallback |
| options.ai_mode: always | Ask AI directly. | 2 |
| forceToGenderize: true | Try the dataset first, then allow AI to interpret a personal nickname or alias even without a real given name. | 1 for a resolved dataset result; 2 total if AI is used |

- [AI options and nickname inference](https://www.genderapi.io/docs/v2/ai-options)
- [Credits and usage](https://www.genderapi.io/docs/v2/credits-and-usage)

## Process a name list without losing its context

Use POST /api/v2/gender/batch for up to 50 items with registered API-key access or 10 items in the IP trial. Assign unique item IDs and retain the original value for each row. Each item can have its own country and AI policy; omit a country when it is unknown.

Batch items default to dataset-only mode, unlike the single-request fallback default. Set options.ai_mode: fallback on each item that needs AI. Check every result, even after HTTP 200, preserve unknown outcomes and review item errors and billing before another submission. Each successful ordinary item uses one credit; one batch HTTP request is not one prediction credit.

- [Batch examples and partial failures](https://www.genderapi.io/docs/v2/batch#batch-application-workflow)
- [Handle unknowns in your application](https://www.genderapi.io/docs/v2/responses#application-decisions)

## Understand what you send

The live demo sends the entered value to GenderAPI only when you submit it. If AI is invoked, the submitted type, value and country context are sent to the configured inference service. For dataset-only prediction, use options.ai_mode: off without forceToGenderize in your integration.

The Privacy Policy, processing agreement and subprocessor register describe the published handling terms. A result is an inferred association; let information supplied by the person take precedence. Do not use it as the basis for consequential decisions about an individual.

- [Privacy Policy](https://www.genderapi.io/privacy-policy)
- [Data Processing Agreement](https://www.genderapi.io/data-processing-agreement)
- [Subprocessor register](https://www.genderapi.io/subprocessors)

## Does the Indian-name demo support only Hindi names?

The demo uses one Devanagari example, but the API accepts Unicode name strings. That input capability is not a claim of complete dataset coverage or measured accuracy for every language used in India.

## Will a Latin spelling return the same result as the original script?

That is not guaranteed. The current dataset path does not provide general transliteration equivalence. Keep each submitted spelling and its returned source, match and confidence information together.

## Is accuracy measured for every Indian name?

No such measurement is published here. Input acceptance, stored counts and a confidence value are not an independent accuracy benchmark. Review the methodology page for the available evidence and the measurements that remain unpublished.

## Does an unknown result use credits?

A successful unknown is billable. Ordinary dataset or fallback mode costs one credit total. With forceToGenderize enabled, a resolved dataset result costs one credit and using AI costs two total, including an unknown AI result. Errors have separate billing rules; inspect meta.usage.
