API reference
The Nationalize API predicts nationality from a name. Send a name, receive ranked country candidates. Authentication uses an API key from your account dashboard.
Overview
Requests are
GET
. Responses are JSON. There is one endpoint:
https://api.nationalize.io
Every successful response includes a
country
array of up to five candidates ordered by probability,
plus the
count
of data points behind the prediction. The same API key works for all three Demografix services
— Nationalize, Genderize, and Agify.
Basic usage
Pass a
name
query parameter. The response contains the top candidate countries and their probabilities.
curl "https://api.nationalize.io?name=nguyen"import requests
response = requests.get("https://api.nationalize.io", params={"name": "nguyen"})
print(response.json())const response = await fetch("https://api.nationalize.io?name=nguyen");
const data = await response.json();
console.log(data);$response = file_get_contents("https://api.nationalize.io?name=nguyen");
echo $response;require "net/http"
require "json"
response = Net::HTTP.get(URI("https://api.nationalize.io?name=nguyen"))
puts JSON.parse(response)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("https://api.nationalize.io?name=nguyen")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"name": "nguyen",
"country": [
{ "country_id": "VN", "probability": 0.561 },
{ "country_id": "US", "probability": 0.035 },
{ "country_id": "AU", "probability": 0.019 },
{ "country_id": "MO", "probability": 0.018 },
{ "country_id": "CA", "probability": 0.011 }
],
"count": 360408
}
| Field | Type | Description |
|---|---|---|
name
|
string | The name as it was processed by the API. |
country
|
array | Up to five candidates ordered by descending probability. Empty when no prediction can be made. |
country[].country_id
|
string | Two-letter ISO 3166-1 alpha-2 country code. |
country[].probability
|
number | Confidence ratio between 0 and 1 for that country. |
count
|
integer | Data points the prediction was based on. |
A last name produces the most accurate prediction. Full names are accepted and parsed — see Input fallbacks.
Authentication
Log in
to get your API key, then pass it as an
apikey
query parameter:
curl "https://api.nationalize.io?name=nguyen&apikey=YOUR_API_KEY"import requests
response = requests.get(
"https://api.nationalize.io",
params={"name": "nguyen", "apikey": "YOUR_API_KEY"},
)
print(response.json())const url = new URL("https://api.nationalize.io");
url.searchParams.set("name", "nguyen");
url.searchParams.set("apikey", "YOUR_API_KEY");
const response = await fetch(url);
console.log(await response.json());$response = file_get_contents(
"https://api.nationalize.io?name=nguyen&apikey=YOUR_API_KEY"
);
echo $response;require "net/http"
require "json"
uri = URI("https://api.nationalize.io")
uri.query = URI.encode_www_form(name: "nguyen", apikey: "YOUR_API_KEY")
puts JSON.parse(Net::HTTP.get(uri))package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("https://api.nationalize.io?name=nguyen&apikey=YOUR_API_KEY")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Batch usage
Send up to 10 names per request using repeated
name[]
parameters. The response is an array in the same order as the input.
curl "https://api.nationalize.io?name[]=nguyen&name[]=schmidt&name[]=garcia"import requests
response = requests.get(
"https://api.nationalize.io",
params={"name[]": ["nguyen", "schmidt", "garcia"]},
)
print(response.json())const params = new URLSearchParams();
["nguyen", "schmidt", "garcia"].forEach(n => params.append("name[]", n));
const response = await fetch(`https://api.nationalize.io?${params}`);
console.log(await response.json());$query = http_build_query(["name" => ["nguyen", "schmidt", "garcia"]]);
$response = file_get_contents("https://api.nationalize.io?$query");
echo $response;require "net/http"
require "json"
uri = URI("https://api.nationalize.io")
uri.query = URI.encode_www_form("name[]" => ["nguyen", "schmidt", "garcia"])
puts JSON.parse(Net::HTTP.get(uri))package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
q := url.Values{}
for _, n := range []string{"nguyen", "schmidt", "garcia"} {
q.Add("name[]", n)
}
resp, _ := http.Get("https://api.nationalize.io?" + q.Encode())
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
[
{
"name": "nguyen",
"country": [
{ "country_id": "VN", "probability": 0.561 },
{ "country_id": "US", "probability": 0.035 },
{ "country_id": "AU", "probability": 0.019 },
{ "country_id": "MO", "probability": 0.018 },
{ "country_id": "CA", "probability": 0.011 }
],
"count": 360408
},
{
"name": "schmidt",
"country": [
{ "country_id": "DE", "probability": 0.224 },
{ "country_id": "DK", "probability": 0.120 },
{ "country_id": "US", "probability": 0.084 },
{ "country_id": "AT", "probability": 0.057 },
{ "country_id": "CH", "probability": 0.026 }
],
"count": 187032
},
{
"name": "garcia",
"country": [
{ "country_id": "GT", "probability": 0.086 },
{ "country_id": "MX", "probability": 0.073 },
{ "country_id": "US", "probability": 0.064 },
{ "country_id": "ES", "probability": 0.058 },
{ "country_id": "VE", "probability": 0.048 }
],
"count": 1776794
}
]
Each name in the batch counts toward your quota. A batch of 10 names consumes 10 from your monthly allowance.
Input fallbacks
The API tries three lookups in order before giving up on a name:
- Direct match. The input is looked up as-is.
-
Diacritic-stripped match.
If the direct match fails, diacritics are removed and the lookup is retried.
Joséfalls back toJose. -
Last-name extraction.
If a row contains a multi-word string — for example, a full-name field from a CRM export —
the parser extracts what looks like the last name and retries.
Sarah Johnsonfalls back toJohnson.
Responses and errors
Success
200 OK
returns a single JSON object for single-name requests, or an array for batch requests.
Field shapes are documented under Basic usage.
Rate-limit headers
Every response — success or error — includes the current rate-limit state:
X-Rate-Limit-Limit
|
Total names allowed in the current window. |
X-Rate-Limit-Remaining
|
Names remaining in the current window. |
X-Rate-Limit-Reset
|
Seconds until the window resets. |
Errors
Errors return JSON with an
error
field and an appropriate HTTP status code.
| Status | Error | Cause |
|---|---|---|
| 401 |
Invalid API key
|
The key was not recognized. |
| 402 |
Subscription is not active
|
The subscription tied to the key is paused, expired, or unpaid. |
| 422 |
Missing 'name' parameter
|
No name was sent. |
| 422 |
Invalid 'name' parameter
|
The name value is empty, too long, or otherwise malformed. |
| 429 |
Request limit reached
|
The monthly quota or per-IP limit is exhausted. |
| 429 |
Request too low to process
|
The request was throttled. Retry after a short delay. |
{
"error": "Invalid API key"
}