Infer Record Country
curl --request POST \
--url https://api.minerva.io/v2/infer_record_country \
--header 'Content-Type: <content-type>' \
--header 'x-api-key: <api-key>' \
--data '
{
"records": [
{
"record_id": "<string>",
"emails": [
"<string>"
],
"phones": [
"<string>"
],
"first_name": "<string>",
"last_name": "<string>",
"middle_name": "<string>",
"full_name": "<string>",
"name_suffix": "<string>"
}
]
}
'import requests
url = "https://api.minerva.io/v2/infer_record_country"
payload = { "records": [
{
"record_id": "<string>",
"emails": ["<string>"],
"phones": ["<string>"],
"first_name": "<string>",
"last_name": "<string>",
"middle_name": "<string>",
"full_name": "<string>",
"name_suffix": "<string>"
}
] }
headers = {
"x-api-key": "<api-key>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
records: [
{
record_id: '<string>',
emails: ['<string>'],
phones: ['<string>'],
first_name: '<string>',
last_name: '<string>',
middle_name: '<string>',
full_name: '<string>',
name_suffix: '<string>'
}
]
})
};
fetch('https://api.minerva.io/v2/infer_record_country', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.minerva.io/v2/infer_record_country",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'records' => [
[
'record_id' => '<string>',
'emails' => [
'<string>'
],
'phones' => [
'<string>'
],
'first_name' => '<string>',
'last_name' => '<string>',
'middle_name' => '<string>',
'full_name' => '<string>',
'name_suffix' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: <content-type>",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.minerva.io/v2/infer_record_country"
payload := strings.NewReader("{\n \"records\": [\n {\n \"record_id\": \"<string>\",\n \"emails\": [\n \"<string>\"\n ],\n \"phones\": [\n \"<string>\"\n ],\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"full_name\": \"<string>\",\n \"name_suffix\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "<content-type>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.minerva.io/v2/infer_record_country")
.header("x-api-key", "<api-key>")
.header("Content-Type", "<content-type>")
.body("{\n \"records\": [\n {\n \"record_id\": \"<string>\",\n \"emails\": [\n \"<string>\"\n ],\n \"phones\": [\n \"<string>\"\n ],\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"full_name\": \"<string>\",\n \"name_suffix\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.minerva.io/v2/infer_record_country")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"records\": [\n {\n \"record_id\": \"<string>\",\n \"emails\": [\n \"<string>\"\n ],\n \"phones\": [\n \"<string>\"\n ],\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"full_name\": \"<string>\",\n \"name_suffix\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body[
{
"record_id": "user_001",
"is_intl": true,
"most_likely_country": "United Kingdom",
"inferred_countries": ["United Kingdom"],
"email_metadata": [
{
"email": "john.smith@example.co.uk",
"is_valid": true,
"is_intl": true,
"country_code": "UK",
"location": "United Kingdom"
},
{
"email": "j.smith@gmail.com",
"is_valid": true,
"is_intl": null,
"country_code": null,
"location": null
}
],
"phone_metadata": [
{
"phone": "+44 20 7123 4567",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+442071234567",
"country_code": "GB",
"location": "United Kingdom"
}
]
},
{
"record_id": "user_002",
"is_intl": true,
"most_likely_country": "France",
"inferred_countries": ["France"],
"email_metadata": [
{
"email": "marie@example.fr",
"is_valid": true,
"is_intl": true,
"country_code": "FR",
"location": "France"
}
],
"phone_metadata": [
{
"phone": "+33 1 23 45 67 89",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+33123456789",
"country_code": "FR",
"location": "France"
},
{
"phone": "+33 6 12 34 56 78",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+33612345678",
"country_code": "FR",
"location": "France"
}
]
},
{
"record_id": "user_003",
"is_intl": false,
"most_likely_country": "United States",
"inferred_countries": ["United States"],
"email_metadata": [
{
"email": "contact@example.com",
"is_valid": true,
"is_intl": null,
"country_code": null,
"location": null
}
],
"phone_metadata": [
{
"phone": "+1-555-123-4567",
"is_valid": true,
"is_intl": false,
"standardized_phone": "+15551234567",
"country_code": "US",
"location": "United States"
}
]
}
]
{
"code": "bad_request",
"message": "Input data must contain a 'records' key with a list of inputs",
"api_request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
{
"code": "unauthorized",
"message": "Unauthorized",
"api_request_id": "b2c3d4e5-f6a7-1234-bcde-f12345678901"
}
{
"code": "payload_too_large",
"message": "Maximum number of records for /v2/infer_record_country endpoint is 1000",
"api_request_id": "d4e5f6a7-b8c9-3456-def0-234567890123"
}
{
"code": "unprocessable_entity",
"message": "Input data must contain a 'records' key with a list of inputs",
"api_request_id": "e5f6a7b8-c9d0-4567-ef01-345678901234"
}
{
"code": "rate_limit_reached",
"message": "You reached your total request-rate limit, please contact help@minerva.io for help",
"api_request_id": "f6a7b8c9-d0e1-5678-f012-456789012345"
}
Validation Workflows
Infer Record Country
Infer country location from email addresses and phone numbers
POST
/
v2
/
infer_record_country
Infer Record Country
curl --request POST \
--url https://api.minerva.io/v2/infer_record_country \
--header 'Content-Type: <content-type>' \
--header 'x-api-key: <api-key>' \
--data '
{
"records": [
{
"record_id": "<string>",
"emails": [
"<string>"
],
"phones": [
"<string>"
],
"first_name": "<string>",
"last_name": "<string>",
"middle_name": "<string>",
"full_name": "<string>",
"name_suffix": "<string>"
}
]
}
'import requests
url = "https://api.minerva.io/v2/infer_record_country"
payload = { "records": [
{
"record_id": "<string>",
"emails": ["<string>"],
"phones": ["<string>"],
"first_name": "<string>",
"last_name": "<string>",
"middle_name": "<string>",
"full_name": "<string>",
"name_suffix": "<string>"
}
] }
headers = {
"x-api-key": "<api-key>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
records: [
{
record_id: '<string>',
emails: ['<string>'],
phones: ['<string>'],
first_name: '<string>',
last_name: '<string>',
middle_name: '<string>',
full_name: '<string>',
name_suffix: '<string>'
}
]
})
};
fetch('https://api.minerva.io/v2/infer_record_country', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.minerva.io/v2/infer_record_country",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'records' => [
[
'record_id' => '<string>',
'emails' => [
'<string>'
],
'phones' => [
'<string>'
],
'first_name' => '<string>',
'last_name' => '<string>',
'middle_name' => '<string>',
'full_name' => '<string>',
'name_suffix' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: <content-type>",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.minerva.io/v2/infer_record_country"
payload := strings.NewReader("{\n \"records\": [\n {\n \"record_id\": \"<string>\",\n \"emails\": [\n \"<string>\"\n ],\n \"phones\": [\n \"<string>\"\n ],\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"full_name\": \"<string>\",\n \"name_suffix\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "<content-type>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.minerva.io/v2/infer_record_country")
.header("x-api-key", "<api-key>")
.header("Content-Type", "<content-type>")
.body("{\n \"records\": [\n {\n \"record_id\": \"<string>\",\n \"emails\": [\n \"<string>\"\n ],\n \"phones\": [\n \"<string>\"\n ],\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"full_name\": \"<string>\",\n \"name_suffix\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.minerva.io/v2/infer_record_country")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"records\": [\n {\n \"record_id\": \"<string>\",\n \"emails\": [\n \"<string>\"\n ],\n \"phones\": [\n \"<string>\"\n ],\n \"first_name\": \"<string>\",\n \"last_name\": \"<string>\",\n \"middle_name\": \"<string>\",\n \"full_name\": \"<string>\",\n \"name_suffix\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body[
{
"record_id": "user_001",
"is_intl": true,
"most_likely_country": "United Kingdom",
"inferred_countries": ["United Kingdom"],
"email_metadata": [
{
"email": "john.smith@example.co.uk",
"is_valid": true,
"is_intl": true,
"country_code": "UK",
"location": "United Kingdom"
},
{
"email": "j.smith@gmail.com",
"is_valid": true,
"is_intl": null,
"country_code": null,
"location": null
}
],
"phone_metadata": [
{
"phone": "+44 20 7123 4567",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+442071234567",
"country_code": "GB",
"location": "United Kingdom"
}
]
},
{
"record_id": "user_002",
"is_intl": true,
"most_likely_country": "France",
"inferred_countries": ["France"],
"email_metadata": [
{
"email": "marie@example.fr",
"is_valid": true,
"is_intl": true,
"country_code": "FR",
"location": "France"
}
],
"phone_metadata": [
{
"phone": "+33 1 23 45 67 89",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+33123456789",
"country_code": "FR",
"location": "France"
},
{
"phone": "+33 6 12 34 56 78",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+33612345678",
"country_code": "FR",
"location": "France"
}
]
},
{
"record_id": "user_003",
"is_intl": false,
"most_likely_country": "United States",
"inferred_countries": ["United States"],
"email_metadata": [
{
"email": "contact@example.com",
"is_valid": true,
"is_intl": null,
"country_code": null,
"location": null
}
],
"phone_metadata": [
{
"phone": "+1-555-123-4567",
"is_valid": true,
"is_intl": false,
"standardized_phone": "+15551234567",
"country_code": "US",
"location": "United States"
}
]
}
]
{
"code": "bad_request",
"message": "Input data must contain a 'records' key with a list of inputs",
"api_request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
{
"code": "unauthorized",
"message": "Unauthorized",
"api_request_id": "b2c3d4e5-f6a7-1234-bcde-f12345678901"
}
{
"code": "payload_too_large",
"message": "Maximum number of records for /v2/infer_record_country endpoint is 1000",
"api_request_id": "d4e5f6a7-b8c9-3456-def0-234567890123"
}
{
"code": "unprocessable_entity",
"message": "Input data must contain a 'records' key with a list of inputs",
"api_request_id": "e5f6a7b8-c9d0-4567-ef01-345678901234"
}
{
"code": "rate_limit_reached",
"message": "You reached your total request-rate limit, please contact help@minerva.io for help",
"api_request_id": "f6a7b8c9-d0e1-5678-f012-456789012345"
}
Quick Answer
How do I determine someone’s country from their contact information? Use this endpoint to infer country location by analyzing email domains and phone number country codes.Common questions this endpoint answers:- How do I find out what country someone is from?
- How can I detect international contacts?
- How do I identify non-US leads?
- How can I route leads based on country?
- How do I check if a contact is international?
- How can I filter contacts by location?
- International lead routing and assignment
- Geographic segmentation for campaigns
- Compliance filtering (e.g., GDPR vs US regulations)
- Sales territory assignment
- Multi-market customer analysis
Overview
The Infer Record Country endpoint analyzes email addresses and phone numbers to determine the likely country location of a person. This endpoint infers country information by:- Analyzing email domain top-level domains (TLDs) such as
.co.uk,.fr,.de - Parsing phone number country codes and validating phone number formats
Request
Headers
string
required
Your API key for authentication
string
required
application/json
Request Body
object[]
required
An array of records containing contact information. Maximum 1000 records per request.
Note: At least one of
Show Record object properties
Show Record object properties
string
required
Your unique identifier for this record
string[]
Array of email addresses to analyze. Emails are validated and analyzed for country-specific TLDs.
string[]
Array of phone numbers to analyze. Supports various formats including E.164, international format with
+, and local formats.string
First name (optional, accepted but not used for country inference)
string
Last name (optional, accepted but not used for country inference)
string
Middle name (optional, accepted but not used for country inference)
string
Full name (optional, accepted but not used for country inference)
string
Name suffix (optional, accepted but not used for country inference)
emails or phones should be provided for meaningful country inference. Name fields are accepted for compatibility with other endpoints but are not used in the country inference logic.Request Example
{
"records": [
{
"record_id": "user_001",
"emails": ["john.smith@example.co.uk", "j.smith@gmail.com"],
"phones": ["+44 20 7123 4567"]
},
{
"record_id": "user_002",
"first_name": "Marie",
"last_name": "Dubois",
"emails": ["marie@example.fr"],
"phones": ["+33 1 23 45 67 89", "+33 6 12 34 56 78"]
}
]
}
Response
Response Structure
The endpoint returns an array of result objects, one for each input record. Results maintain the same order as the input records.Result Object
string
Your identifier from the request
boolean | null
Whether the record appears to be international (non-US).
true: Non-US country detectedfalse: US country detectednull: No country could be determined from the provided information
string | null
The most likely country name based on the analysis. If multiple countries are detected, returns the first one from the inferred list.
null if no country could be determined.string[] | null
Array of unique country names inferred from the contact information. Combines results from both email TLDs and phone number country codes.
null if no countries could be inferred.array
Detailed metadata for each email address analyzed
array
Detailed metadata for each phone number analyzed
Email Metadata Object
string
The email address as provided in the request
boolean
Whether the email address passed basic validation (format check, sanitization)
boolean | null
Whether the email domain indicates a non-US location based on TLD analysis
true: Non-US TLD detected (e.g.,.co.uk,.fr,.de)false: US TLD detected or generic TLD with no country inferencenull: Email is invalid or no country could be determined
string | null
Uppercase ISO country code extracted from the email TLD (e.g., “GB”, “FR”, “DE”).
null if no country-specific TLD detected or email is invalid.string | null
Full country name corresponding to the TLD (e.g., “United Kingdom”, “France”, “Germany”).
null if no country-specific TLD detected or email is invalid.Phone Metadata Object
string
The phone number as provided in the request
boolean
Whether the phone number passed validation and could be parsed successfully
boolean | null
Whether the phone number is international (non-US)
true: Non-US country code detectedfalse: US country code detected (+1)null: Phone is invalid or country could not be determined
string | null
Phone number in E.164 format (e.g., “+442071234567”).
null if the phone number is invalid.string | null
Uppercase ISO country code (e.g., “GB”, “FR”, “US”).
null if the phone number is invalid or country could not be determined.string | null
Full country name (e.g., “United Kingdom”, “France”, “United States”).
null if the phone number is invalid or country could not be determined.Error responses include
statusCode and body fields for backward compatibility with existing integrations. These are deprecated — prefer the HTTP status code and the top-level code / message / api_request_id fields directly. (The deprecated nested body still carries the legacy error_message.)[
{
"record_id": "user_001",
"is_intl": true,
"most_likely_country": "United Kingdom",
"inferred_countries": ["United Kingdom"],
"email_metadata": [
{
"email": "john.smith@example.co.uk",
"is_valid": true,
"is_intl": true,
"country_code": "UK",
"location": "United Kingdom"
},
{
"email": "j.smith@gmail.com",
"is_valid": true,
"is_intl": null,
"country_code": null,
"location": null
}
],
"phone_metadata": [
{
"phone": "+44 20 7123 4567",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+442071234567",
"country_code": "GB",
"location": "United Kingdom"
}
]
},
{
"record_id": "user_002",
"is_intl": true,
"most_likely_country": "France",
"inferred_countries": ["France"],
"email_metadata": [
{
"email": "marie@example.fr",
"is_valid": true,
"is_intl": true,
"country_code": "FR",
"location": "France"
}
],
"phone_metadata": [
{
"phone": "+33 1 23 45 67 89",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+33123456789",
"country_code": "FR",
"location": "France"
},
{
"phone": "+33 6 12 34 56 78",
"is_valid": true,
"is_intl": true,
"standardized_phone": "+33612345678",
"country_code": "FR",
"location": "France"
}
]
},
{
"record_id": "user_003",
"is_intl": false,
"most_likely_country": "United States",
"inferred_countries": ["United States"],
"email_metadata": [
{
"email": "contact@example.com",
"is_valid": true,
"is_intl": null,
"country_code": null,
"location": null
}
],
"phone_metadata": [
{
"phone": "+1-555-123-4567",
"is_valid": true,
"is_intl": false,
"standardized_phone": "+15551234567",
"country_code": "US",
"location": "United States"
}
]
}
]
{
"code": "bad_request",
"message": "Input data must contain a 'records' key with a list of inputs",
"api_request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
{
"code": "unauthorized",
"message": "Unauthorized",
"api_request_id": "b2c3d4e5-f6a7-1234-bcde-f12345678901"
}
{
"code": "payload_too_large",
"message": "Maximum number of records for /v2/infer_record_country endpoint is 1000",
"api_request_id": "d4e5f6a7-b8c9-3456-def0-234567890123"
}
{
"code": "unprocessable_entity",
"message": "Input data must contain a 'records' key with a list of inputs",
"api_request_id": "e5f6a7b8-c9d0-4567-ef01-345678901234"
}
{
"code": "rate_limit_reached",
"message": "You reached your total request-rate limit, please contact help@minerva.io for help",
"api_request_id": "f6a7b8c9-d0e1-5678-f012-456789012345"
}
Error Responses
400- Bad Request: Invalid input format401- Unauthorized: Invalid API key413- Payload Too Large: More than 1000 records in request422- Unprocessable Entity: Invalid data format429- Too Many Requests: Rate limit exceeded500- Internal Server Error
Notes
API Version Support
- This endpoint only supports API version v2 (
/v2/infer_record_country) - Maximum 1000 records per request
Country Inference Logic
Country inference is based on:- Email TLD analysis: Extracts country from top-level domains (e.g.,
.co.uk→ United Kingdom,.fr→ France,.de→ Germany)- Generic TLDs like
.com,.org,.netdo not provide country information - Email addresses without country-specific TLDs will have
nullvalues for country fields
- Generic TLDs like
- Phone number parsing: Uses international phone number validation library to:
- Parse and validate phone numbers in various formats
- Extract country codes
- Standardize to E.164 format
Field Behavior
is_intl: Determined by checking if any non-US country was inferredtrue: At least one non-US country detectedfalse: Only US detectednull: No country information could be extracted
most_likely_country: Returns the first country from theinferred_countrieslist- When multiple countries are detected from different emails/phones, the order depends on the order they appear in your input
inferred_countries: Contains unique country names from all emails and phones analyzed- Duplicates are removed
- Returns
nullif empty (no countries inferred)
Validation
- Invalid emails (failed format validation) are included in results with
is_valid: falseandnullcountry fields - Invalid phone numbers are included in results with
is_valid: falseandnullcountry fields - Duplicate emails and phones within a single record are automatically deduplicated before processing
Input Field Compatibility
- Name fields (
first_name,last_name,middle_name,full_name,name_suffix) are accepted for API compatibility with the resolve endpoint but are not used in country inference logic - The endpoint uses the same
ResolveInputmodel as the resolve endpoint, allowing seamless integration
Was this page helpful?