API reference
The Agify API predicts age from a name. Send a name, receive an estimated age. Authentication uses an API key from your account dashboard.
Overview
Requests are
GET
. Responses are JSON. There is one endpoint:
https://api.agify.io
Every successful response includes an
age
and the
count
of data points
behind the prediction. The same API key works for all three Demografix services — Agify, Genderize, and Nationalize.
Basic usage
Pass a
name
query parameter. The response contains the predicted age.
curl "https://api.agify.io?name=michael"import requests
response = requests.get("https://api.agify.io", params={"name": "michael"})
print(response.json())const response = await fetch("https://api.agify.io?name=michael");
const data = await response.json();
console.log(data);$response = file_get_contents("https://api.agify.io?name=michael");
echo $response;require "net/http"
require "json"
response = Net::HTTP.get(URI("https://api.agify.io?name=michael"))
puts JSON.parse(response)package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("https://api.agify.io?name=michael")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"name": "michael",
"age": 65,
"count": 298219
}
| Field | Type | Description |
|---|---|---|
name
|
string | The name as it was processed by the API. |
age
|
integer | Estimated age in years. null when no prediction can be made. |
count
|
integer | Data points the prediction was based on. |
A first 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.agify.io?name=michael&apikey=YOUR_API_KEY"import requests
response = requests.get(
"https://api.agify.io",
params={"name": "michael", "apikey": "YOUR_API_KEY"},
)
print(response.json())const url = new URL("https://api.agify.io");
url.searchParams.set("name", "michael");
url.searchParams.set("apikey", "YOUR_API_KEY");
const response = await fetch(url);
console.log(await response.json());$response = file_get_contents(
"https://api.agify.io?name=michael&apikey=YOUR_API_KEY"
);
echo $response;require "net/http"
require "json"
uri = URI("https://api.agify.io")
uri.query = URI.encode_www_form(name: "michael", 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.agify.io?name=michael&apikey=YOUR_API_KEY")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
Localization
Names rise and fall in popularity at different times in different countries — the same name can skew older in one place and younger in another. Pass
country_id
to scope the prediction to a specific country. The value is a two-letter
ISO 3166-1 alpha-2
code.
curl "https://api.agify.io?name=michael&country_id=US"import requests
response = requests.get(
"https://api.agify.io",
params={"name": "michael", "country_id": "US"},
)
print(response.json())const url = new URL("https://api.agify.io");
url.searchParams.set("name", "michael");
url.searchParams.set("country_id", "US");
const response = await fetch(url);
console.log(await response.json());$response = file_get_contents(
"https://api.agify.io?name=michael&country_id=US"
);
echo $response;require "net/http"
require "json"
uri = URI("https://api.agify.io")
uri.query = URI.encode_www_form(name: "michael", country_id: "US")
puts JSON.parse(Net::HTTP.get(uri))package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, _ := http.Get("https://api.agify.io?name=michael&country_id=US")
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
{
"name": "michael",
"age": 58,
"count": 108496,
"country_id": "US"
}
The response echoes
country_id
when localization is applied. Without
country_id
,
the API uses the global frequency model. In a batch request,
country_id
applies to every name in the batch.
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.agify.io?name[]=michael&name[]=matthew&name[]=jane"import requests
response = requests.get(
"https://api.agify.io",
params={"name[]": ["michael", "matthew", "jane"]},
)
print(response.json())const params = new URLSearchParams();
["michael", "matthew", "jane"].forEach(n => params.append("name[]", n));
const response = await fetch(`https://api.agify.io?${params}`);
console.log(await response.json());$query = http_build_query(["name" => ["michael", "matthew", "jane"]]);
$response = file_get_contents("https://api.agify.io?$query");
echo $response;require "net/http"
require "json"
uri = URI("https://api.agify.io")
uri.query = URI.encode_www_form("name[]" => ["michael", "matthew", "jane"])
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{"michael", "matthew", "jane"} {
q.Add("name[]", n)
}
resp, _ := http.Get("https://api.agify.io?" + q.Encode())
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
[
{ "name": "michael", "age": 65, "count": 298219 },
{ "name": "matthew", "age": 47, "count": 53379 },
{ "name": "jane", "age": 71, "count": 40935 }
]
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. -
First-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 first name and retries.
Sarah Johnsonfalls back toSarah.
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"
}