TIN Validate API

Programmatically validate Tax Identification Numbers (TINs) across all 249 ISO 3166-1 countries and territories.
Format checks, structure validation, and check-digit verification — in a single request.

🔑
Need an API key? Create one from your Account → API Keys page. Each account supports up to 10 active keys.
i
API access requires payment. Buy validation credits or subscribe to Pro before creating API keys. Review pricing or check the supported countries.

Introduction

The TIN Validate API allows you to verify 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, per-rule validation results.

Key capabilities:

Base URL

All API requests are made to:

Base URL
https://tin-validate.com/api

Authentication

Every request must include a valid API key as a Bearer token in the Authorization header:

HTTP Header
Authorization: Bearer YOUR_API_KEY
⚠️
Keep your API key secret. Never expose it in client-side code, public repositories, or browser requests. Always call the API from your backend.

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.

Rate Limiting

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.


Validate a TIN

POST /api/validate

Validates a Tax Identification Number against all known TIN types for the given country. Returns a detailed breakdown of each validation rule for every applicable TIN type.

Request Body

Send a JSON body with Content-Type: application/json.

FieldTypeDescription
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.
Example Request Body
{
  "country": "FR",
  "tin": "01 23 456 789 417"
}

Response Schema

A successful response returns 200 with the following JSON structure:

FieldTypeDescription
submittedValuestringThe original TIN value as submitted.
submittedValueNormalisedstringThe TIN with all whitespace and formatting stripped.
countryobjectCountry info: alpha2Code, alpha3Code, name.
isValidbooleantrue if the TIN matches at least one TIN type for the country.
officialFormatTinstring | nullThe TIN formatted per its official display format, or null if invalid.
tinTypesarrayValidation results per TIN type (see below).
messagestring | nullReserved. Currently always null.

TIN Type Object

Each item in the tinTypes array contains:

FieldTypeDescription
tinTypestringName of the TIN type (e.g. "French Tax Identification Number (NIF/SPI) - Individuals").
isValidbooleanWhether the TIN is valid for this specific TIN type.
issuedToPersonsbooleanWhether this TIN type is issued to natural persons.
issuedToEntitiesbooleanWhether this TIN type is issued to legal entities.
validationStepsarrayOrdered list of rule checks (see below).

Validation Step Object

FieldTypeDescription
ruleDescriptionstringHuman-readable description of the validation rule.
rulePassedbooleantrue if the TIN satisfies this rule.

Full Example Response

200 OK
{
  "submittedValue": "01 23 456 789 417",
  "submittedValueNormalised": "0123456789417",
  "country": {
    "alpha2Code": "FR",
    "alpha3Code": "FRA",
    "name": "France"
  },
  "isValid": true,
  "officialFormatTin": "01 23 456 789 417",
  "tinTypes": [
    {
      "tinType": "French Tax Identification Number (NIF/SPI) - Individuals",
      "isValid": true,
      "issuedToPersons": true,
      "issuedToEntities": false,
      "validationSteps": [
        { "ruleDescription": "Must consist of exactly 13 characters.", "rulePassed": true },
        { "ruleDescription": "All characters must be digits (0-9).", "rulePassed": true },
        { "ruleDescription": "Character in position 1 must be one of ['0','1','2','3'].", "rulePassed": true },
        { "ruleDescription": "Must pass the modulus-511 check-digit algorithm.", "rulePassed": true }
      ]
    },
    {
      "tinType": "French SIREN - Entities",
      "isValid": false,
      "issuedToPersons": false,
      "issuedToEntities": true,
      "validationSteps": [
        { "ruleDescription": "Must consist of exactly 9 characters.", "rulePassed": false },
        { "ruleDescription": "All characters must be digits (0-9).", "rulePassed": true },
        { "ruleDescription": "Must pass the Luhn (mod 10) check-digit algorithm.", "rulePassed": false }
      ]
    }
  ],
  "message": null
}

Error Responses

Errors are returned as JSON with a detail field describing the issue:

Error Response Structure
{
  "detail": "A human-readable error message."
}

HTTP Status Codes

CodeMeaningDescription
200OKValidation completed successfully.
400Bad RequestInvalid input — e.g. missing country or tin, or unsupported country code.
401UnauthorizedMissing or invalid API key.
403ForbiddenAccount is suspended, deleted, or email is not verified.
404Not FoundUser associated with the API key was not found.
422Validation ErrorRequest body does not match the expected JSON schema.
429Too Many RequestsRate limit exceeded. Retry after the indicated period.
500Server ErrorAn unexpected error occurred. Contact support if persistent.

Code Examples

cURL

Shell
curl -X POST https://tin-validate.com/api/validate \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"country": "FR", "tin": "0123456789417"}'

Python

Python (requests)
import requests

response = requests.post(
    "https://tin-validate.com/api/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["tinTypes"]:
    print(f"\n  {tin_type['tinType']}: {'✓' if tin_type['isValid'] else '✗'}")
    for step in tin_type["validationSteps"]:
        icon = "✓" if step["rulePassed"] else "✗"
        print(f"    {icon} {step['ruleDescription']}")

JavaScript

JavaScript (fetch)
const response = await fetch("https://tin-validate.com/api/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.tinTypes.forEach((type) => {
  console.log(`${type.tinType}: ${type.isValid ? "✓" : "✗"}`);
  type.validationSteps.forEach((step) => {
    console.log(`  ${step.rulePassed ? "✓" : "✗"} ${step.ruleDescription}`);
  });
});

Supported Countries

TIN Validate supports all 249 ISO 3166-1 countries and territories. Pass the ISO 3166-1 alpha-2 country code in the country field.

If a country code is not supported, the API returns 400 with a descriptive error message.

ℹ️
You can try out any country by using the web validator — select a country from the dropdown to see which TIN types are available.

Changelog

DateChange
2026-02-15API documentation published.
2026-01-31API v1 released — POST /api/validate endpoint.

💬
Questions or feedback? Reach out via our contact page or email [email protected].