Programmatically validate Tax Identification Numbers (TINs) across all 249 ISO 3166-1 countries and territories.
Format, structure, and check-digit checks — in a single request.
The TIN Validate API lets you validate whether a given Tax Identification Number is structurally valid for a specific country. The API checks the TIN against all known TIN types for the country (e.g. personal TINs, corporate SIRENs, VAT numbers) and returns detailed validation-check results.
Key capabilities:
All API requests are made to:
https://tin-validate.com/api/v1
The API uses major path versions. Backwards-compatible changes are released in-place within v1; breaking changes will use a new major path such as /api/v2.
Every request must include a valid API key as a Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEY
You can manage your API keys (create, rename, revoke) from the API Keys dashboard. Your full key is shown only once at creation — store it securely.
Validation credits are consumed only by POST /validate. A completed validation consumes 1 validation credit, including an invalid TIN result, because the validation rules were executed.
Request schema errors, invalid validation input, and validation execution errors do not consume validation credits. Reference endpoints such as GET /countries and GET /countries/{countryCode}/tin-types do not consume validation credits, though they remain authenticated and rate limited.
API requests are subject to rate limiting to ensure fair usage. If you exceed the limit, the API responds with 429 Too Many Requests.
Wait for the indicated period before retrying. If you need higher limits, contact us.
Validates a Tax Identification Number against all known TIN types for the given country. Returns a detailed breakdown of each validation check for every applicable TIN type. Pass tinTypeId to validate against one specific TIN type.
Send a JSON body with Content-Type: application/json. Unrecognised fields are rejected with 422.
| Field | Type | Description | |
|---|---|---|---|
| country | string | required | ISO 3166-1 alpha-2 country code (e.g. FR, US, DE). |
| tin | string | required | The Tax Identification Number to validate. Whitespace and formatting characters are automatically stripped. |
| tinTypeId | string | optional | Specific TIN type to validate against. Omit this field to validate against all TIN types for the country; do not send null. |
{
"country": "FR",
"tin": "42226020800026",
"tinTypeId": "fr-siret"
}A successful response returns 200 with the following JSON structure:
| Field | Type | Description |
|---|---|---|
| submittedValue | string | The original TIN value as submitted. |
| normalisedValue | string | The TIN with all whitespace and formatting stripped. |
| country | object | Country info: alpha2Code, alpha3Code, name. |
| isValid | boolean | true if the TIN matches at least one TIN type for the country. |
| matchedFormattedValue | string | null | The matched TIN formatted for display, or null if invalid. |
| tinTypeResults | array | Validation results per TIN type (see below). |
Each item in the tinTypeResults array contains:
| Field | Type | Description |
|---|---|---|
| tinTypeId | string | Stable machine-readable identifier for this TIN type. |
| name | string | Name of the TIN type (e.g. "French Tax Identification Number (NIF/SPI) - Individuals"). |
| isValid | boolean | Whether the TIN is valid for this specific TIN type. |
| issuedToIndividuals | boolean | Whether this TIN type is issued to individuals. |
| issuedToEntities | boolean | Whether this TIN type is issued to legal entities. |
| validationChecks | array | Ordered list of validation checks (see below). |
| Field | Type | Description |
|---|---|---|
| description | string | Human-readable description of the validation check. |
| passed | boolean | true if the TIN satisfies this check. |
{
"submittedValue": "01 23 456 789 417",
"normalisedValue": "0123456789417",
"country": {
"alpha2Code": "FR",
"alpha3Code": "FRA",
"name": "France"
},
"isValid": true,
"matchedFormattedValue": "01 23 456 789 417",
"tinTypeResults": [
{
"tinTypeId": "fr-nif",
"name": "French Tax Identification Number (NIF/SPI) - Individuals",
"isValid": true,
"issuedToIndividuals": true,
"issuedToEntities": false,
"validationChecks": [
{ "description": "Must consist of exactly 13 characters.", "passed": true },
{ "description": "All characters must be digits (0-9).", "passed": true },
{ "description": "Character in position 1 must be one of ['0','1','2','3'].", "passed": true },
{ "description": "Must pass the modulus-511 check-digit algorithm.", "passed": true }
]
},
{
"tinTypeId": "fr-siren",
"name": "French SIREN - Entities",
"isValid": false,
"issuedToIndividuals": false,
"issuedToEntities": true,
"validationChecks": [
{ "description": "Must consist of exactly 9 characters.", "passed": false },
{ "description": "All characters must be digits (0-9).", "passed": true },
{ "description": "Must pass the Luhn (mod 10) check-digit algorithm.", "passed": false }
]
}
]
}Returns the full TIN Validate country catalogue covering all 249 ISO 3166-1 countries and territories. Use this endpoint to populate country pickers, validate country codes before calling POST /validate, or decide when to call the country-specific TIN types endpoint.
This endpoint is authenticated but does not consume validation credits.
| Field | Type | Description |
|---|---|---|
| countries | array | All 249 ISO 3166-1 countries and territories, sorted by country name. |
| countries[].alpha2Code | string | ISO 3166-1 alpha-2 country code used by validation requests. |
| countries[].alpha3Code | string | null | ISO 3166-1 alpha-3 country code, when available. |
| countries[].name | string | Country name. |
{
"countries": [
{
"alpha2Code": "DE",
"alpha3Code": "DEU",
"name": "Germany"
},
{
"alpha2Code": "FR",
"alpha3Code": "FRA",
"name": "France"
}
]
}Returns the TIN types supported for a country. Use this endpoint to discover available identifiers before validation, display country-specific options, or resolve tinTypeId values returned by POST /validate. Countries in the catalogue with no native modelled TIN type return an empty tinTypes array.
This endpoint is authenticated but does not consume validation credits.
| Field | Type | Description | |
|---|---|---|---|
| countryCode | string | required | ISO 3166-1 alpha-2 country code (e.g. FR, US, DE). |
| Field | Type | Description |
|---|---|---|
| country | object | Country info: alpha2Code, alpha3Code, name. |
| tinTypes | array | Supported TIN types for the country, or an empty array when no native TIN type is modelled. |
| Field | Type | Description |
|---|---|---|
| tinTypeId | string | Stable machine-readable identifier for this TIN type. |
| name | string | Name of the TIN type. |
| issuingBody | string | null | Issuing authority when available. |
| issuedToIndividuals | boolean | Whether this TIN type is issued to individuals. |
| issuedToEntities | boolean | Whether this TIN type is issued to legal entities. |
| summary | string | null | Short description when available. |
| aliases | array | Common local names or abbreviations. |
| status | string | null | Status label such as current or transitional, when available. |
| examples | array | Example values in display format. |
| validationChecks | array | Validation check descriptions for this TIN type. |
{
"country": {
"alpha2Code": "FR",
"alpha3Code": "FRA",
"name": "France"
},
"tinTypes": [
{
"tinTypeId": "fr-siret",
"name": "French SIRET - Professional Persons and Entities (Establishments)",
"issuingBody": "Institut national de la statistique et des etudes economiques (National Institute of Statistics and Economic Studies)",
"issuedToIndividuals": true,
"issuedToEntities": true,
"summary": "Fourteen-digit establishment identifier made from a SIREN plus a NIC.",
"aliases": ["SIRET", "Numero Siret"],
"status": "current",
"examples": ["422 260 208 00026"],
"validationChecks": [
{ "description": "Must consist of exactly 14 characters." },
{ "description": "All characters must be digits (0-9)." },
{ "description": "Must pass the Luhn (mod 10) check-digit algorithm." }
]
}
]
}Most API errors are returned as JSON with a string detail field. Schema validation errors use FastAPI's standard detail array.
{
"detail": "A human-readable error message."
}{
"detail": [
{
"loc": ["body", "tinTypeId"],
"msg": "String should match the expected pattern.",
"type": "string_pattern_mismatch"
}
]
}| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Validation completed successfully. |
| 400 | Bad Request | Well-formed JSON, but invalid validation input such as an unsupported country, unknown tinTypeId, empty normalised TIN, or over-length normalised TIN. |
| 401 | Unauthorized | Missing or invalid API key. |
| 402 | Payment Required | Validation credits are exhausted. |
| 403 | Forbidden | Account is suspended, deleted, or email is not verified. |
| 404 | Not Found | User associated with the API key was not found, or the requested country was not found. |
| 422 | Validation Error | Request body or path parameter does not match the expected schema, such as a missing required field, invalid country code shape, invalid tinTypeId format, or unrecognised JSON field. |
| 429 | Too Many Requests | Rate limit exceeded. Retry after the indicated period. |
| 500 | Server Error | An unexpected error occurred. Contact support if persistent. |
curl -X POST https://tin-validate.com/api/v1/validate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"country": "FR", "tin": "0123456789417"}'import requests
response = requests.post(
"https://tin-validate.com/api/v1/validate",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
json={
"country": "FR",
"tin": "0123456789417",
},
)
data = response.json()
print(f"Valid: {data['isValid']}")
for tin_type in data["tinTypeResults"]:
print(f"\n {tin_type['name']}: {'✓' if tin_type['isValid'] else '✗'}")
for check in tin_type["validationChecks"]:
icon = "✓" if check["passed"] else "✗"
print(f" {icon} {check['description']}")const response = await fetch("https://tin-validate.com/api/v1/validate", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
country: "DE",
tin: "12345678901",
}),
});
const data = await response.json();
console.log("Valid:", data.isValid);
data.tinTypeResults.forEach((type) => {
console.log(`${type.name}: ${type.isValid ? "✓" : "✗"}`);
type.validationChecks.forEach((check) => {
console.log(` ${check.passed ? "✓" : "✗"} ${check.description}`);
});
});TIN Validate supports all 249 ISO 3166-1 countries and territories. Pass the ISO 3166-1 alpha-2 country code in the country field. You can also call GET /countries to retrieve the current API country catalogue.
Some countries have no native modelled TIN type, or are documented through another country's tax identifier system. Use GET /countries/{countryCode}/tin-types to discover whether native TIN type rules are available before validating.
| Date | Change |
|---|---|
| 2026-06-28 | Added the API v1 supported countries reference endpoint. |
| 2026-02-15 | API documentation published. |
| 2026-01-31 | API v1 released — POST /api/v1/validate endpoint. |