Tax ID Validation - How To
Send a tax ID to POST /tax-id-validations/. Brinta checks it against the official sources of that country and returns what they hold about the taxpayer. Depending on the country this can include:
- legal name and address;
- tax condition;
- activities;
- related registrations;
- provincial registries (padrones) with their rates.
Use it to:
- onboard customers and suppliers with clean data;
- block invalid tax IDs before you invoice;
- keep each counterpart's tax profile up to date, so
/salesand/transferscalculate the right taxes.
API reference: Create a Tax ID validation · Get a Tax ID validation · Validation webhooks · Capabilities per country
Key things to know
- Validations are asynchronous. The
POSTreturns anidwith statusin_process. You get the result with a webhook or withGET /tax-id-validations/{id}.- You can validate a company already in Brinta, or a tax ID on its own. Only the first one can store the result.
- A validation either succeeds or fails as a whole. There is no partial success.
1. Choose what to validate
| You want to | Send | Result stored? |
|---|---|---|
| Validate a company already in Brinta and keep its data up to date | company_id (or company_external_id) + "update_company": true | Yes. Brinta updates the company: legal name, registrations, address, tax condition and registry memberships. Later transactions use them automatically. |
| Validate a company already in Brinta, without changing it | company_id (or company_external_id) | No |
| Check a tax ID that isn't in Brinta | company with the tax ID inline | No |
Send exactly one of company_id, company_external_id or company.
A company already in Brinta
curl -X POST https://api.brinta.com/tax-id-validations/ \
-H "Authorization: Bearer $BRINTA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"locations": ["AR"],
"company_id": "456c6c4f-f64a-4069-9988-8164c015cf80",
"update_company": true
}'Brinta validates the registration stored on the company. If it holds several that can be validated, choose one with a top-level tax_registration.
A tax ID on its own
curl -X POST https://api.brinta.com/tax-id-validations/ \
-H "Authorization: Bearer $BRINTA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"locations": ["CO"],
"company": {
"type": "business",
"legal_name": "Acme S.A.S.",
"tax_registration": { "number": "901701266", "type": "NIT", "level": "country", "location": "CO" }
}
}'2. Request fields
| Field | Required | Notes |
|---|---|---|
locations | Yes | Where to validate, as plain strings. Use ISO 3166-1 for countries ("MX") or ISO 3166-2 for states and provinces ("AR-C"), for example ["AR"] or ["AR", "AR-C"]. All locations must belong to the same country. |
company_id / company_external_id | One of the three | A company already in Brinta. When you use company_external_id under a parent company, add company_parent_id or company_parent_external_id. |
company | One of the three | The tax ID inline. See below. |
update_company | No | true writes the result to the company. Only applies with company_id or company_external_id. |
tax_registration | No | { number, type, level, location }. Selects which of the company's registrations to validate. Send it here or inside company, not both. |
validation_type | Depends on the country | Selects a specific check where a country has more than one. See the country table. |
periods | No | ["YYYY-MM"], up to 24. The months to query for sources that change monthly, such as Argentina's padrones. Defaults to the current month. |
company (inline)
| Field | Notes |
|---|---|
tax_registration | Required. number, type, level (country, state or municipality) and location. Valid types per country are in Company Codes. |
type | business or person. |
legal_name, name | Some checks compare them with the official record. |
address.postal_code | Some checks compare it with the official record. |
phone, email | Required by some checks. |
privacy_agreement | { "url": "...", "ip": "..." }. Required by checks that query personal data: the URL of the privacy notice the person accepted, and the IP they accepted it from. |
Some checks require extra fields. If any are missing, the request is rejected before anything runs, with 400 and the list of missing fields:
{
"message": "Missing data required by the providers that validate this request: MX: company.legal_name is required; MX: company.address.postal_code is required",
"data": [ { "errors": ["MX: company.legal_name is required", "MX: company.address.postal_code is required"] } ]
}3. Get the result
The POST answers right away:
{ "id": "tiv2-188be839-bd78-4692-9fd4-53e67e2d28bc", "status": "in_process" }Keep the id. Brinta then queries the official sources in the background. It usually takes seconds, and longer when an authority answers asynchronously.
Webhook. When the validation succeeds, Brinta notifies your validation webhook with the validation id. Then read it:
curl https://api.brinta.com/tax-id-validations/tiv2-188be839-bd78-4692-9fd4-53e67e2d28bc \
-H "Authorization: Bearer $BRINTA_TOKEN"Polling. If you don't use webhooks, or haven't received one, call GET /tax-id-validations/{id} until status is no longer in_process. Wait a few seconds between calls. Always handle failed this way as well.
Response
{
"id": "tiv2-188be839-bd78-4692-9fd4-53e67e2d28bc",
"status": "succeeded",
"data": [
{
"locationIsoCode": "CO",
"status": "succeeded",
"company": {
"legal_name": "ACME S.A.S.",
"tax_registrations": [
{ "number": "901701266", "type": "NIT", "level": "country", "location": "CO", "activities": ["8299"] }
],
"address": { "state": "CO-BOL", "city": "CARTAGENA" }
},
"registry_lists": []
}
]
}| Field | Notes |
|---|---|
status | Overall result: in_process, succeeded or failed. |
data[] | One entry per location. |
data[].status | Result for that location. If any location fails, the whole validation is failed. |
data[].company | The taxpayer as the official source has it: legal_name, name, tax_registrations[] (with status, activities and authority when available), address, phone, email. Use this data, not what you sent. When the validation updated a company, company.id is its Brinta ID. |
data[].registry_lists | Registries the tax ID belongs to, each with name, type, rate, valid_from and valid_until. Always present; [] means none. Mostly used in Argentina. |
data[].errors | Reasons the location failed, when the source gives them. |
Fields with no value are left out of the response.
4. Using the result
With "update_company": true, Brinta stores the result on the company. Reference that company in your transactions with company_id or company_external_id, and the stored data is used automatically:
-
buyeron/sales; -
counterparton/transfers. -
Data the source returns replaces what the company had. That includes the legal name. Empty values never overwrite existing data.
-
Validate again when the source changes. Argentina's padrones change monthly; see the Argentina guide.
-
Recent results may be reused. An identical query is answered from the last result for a short time, up to 24 hours. In Argentina, national data is kept until the end of the month.
Errors
400 message | Cause |
|---|---|
Send exactly one of companyId, companyExternalId or company | Zero, or more than one, identifiers were sent. |
Send taxRegistration either at the top level or inside company, not both | tax_registration was sent twice. |
taxRegistration (with number) is required when declaring a company via company | The inline company has no tax ID. |
Missing data required by the providers that validate this request: ... | Required fields are missing for that country or check. |
Missing tax id validation configuration for location(s) <code>. Please contact support. | That location or validation_type isn't enabled for your account. |
All locations must belong to the same country | Locations from different countries were mixed. Send one request per country. |
The request lists location <code> more than once | A location appears twice. |
Invalid periods: ... | A period is outside the allowed window. |
Company not found within the clients context | The company_id or company_external_id doesn't exist in your account. |
Common mistakes
| Mistake | Fix |
|---|---|
Expecting the result in the POST response | The POST only returns the id. Read the result with a webhook or with GET. |
| Waiting only for a webhook | Also poll GET /tax-id-validations/{id}, especially to catch failed. |
Expecting an inline company to be saved | Nothing is stored. Create the company with POST /companies, then validate it with company_id and update_company: true. |
Mixing countries in locations | Send one request per country. |
| Keeping your own legal name after a successful validation | Use the name in data[].company.legal_name. It is the official one. |
Updated about 4 hours ago
