CCCD & Tax Code Validator API
Validate Vietnamese citizen ID (CCCD), old ID (CMND) and tax code (MST) numbers: structure, province, gender, birth year and tax code check digit.
The Vietnamese ID API checks the structure of identity numbers before you store them. A 12-digit CCCD number is decoded according to Circular 07/2016 and 59/2021 of the Ministry of Public Security: the first 3 digits are the province of birth registration (returned with its name and, since the 2025 merger, the province it now belongs to), the 4th digit encodes gender and century, the next 2 the birth year, and the last 6 are a serial number.
A 10-digit tax code (mã số thuế) is validated with the official check digit (weights 31, 29, 23, 19, 17, 13, 7, 5, 3), and a 13-digit code (0101248141-001) is recognised as a branch / dependent unit. Since July 2025 the personal tax code is the CCCD number, so a 12-digit tax code is checked as a CCCD. Old 9-digit CMND numbers have no checksum: only their format is checked. type=auto (default) guesses the type from the length.
This is a structure check: it does not query any government database and cannot prove that a card or company exists. Numbers are processed in memory and never stored or logged; prefer POST so the number does not appear in URLs.
Parameters
| Name | In | Type | Required | Default | |
|---|---|---|---|---|---|
number | body|query | string | yes | CCCD, CMND or tax code; spaces, dots and dashes are ignored. | |
type | body|query | string | no | auto | auto, cccd, cmnd or tax_code (alias mst). |
Example
curl -X POST "https://apibox.io.vn/v1/vn-id" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"number":"001099012345"}'const res = await fetch('https://apibox.io.vn/v1/vn-id', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"number": "001099012345"
}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://apibox.io.vn/v1/vn-id",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"number": "001099012345"},
timeout=30,
)
print(res.json())<?php
$ch = curl_init('https://apibox.io.vn/v1/vn-id');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"number":"001099012345"}',
]);
$response = curl_exec($ch);
print_r(json_decode($response, true));Response
{
"input": "001099012345",
"normalized": "001099012345",
"type": "cccd",
"valid": true,
"errors": [],
"details": {
"province_code": "001",
"province": "Hà Nội",
"province_since_2025": "Hà Nội",
"gender": "male",
"gender_code": 0,
"birth_year": 1999,
"age_this_year": 27,
"serial": "012345"
},
"note": "Since 07/2025 the CCCD number is also the personal tax code. Structure check only: this does not prove the card exists."
}
Use cases
- Catch typing mistakes in CCCD and tax code fields of sign-up and e-invoice forms
- Pre-fill gender and birth year from the CCCD in eKYC flows
- Clean customer and supplier databases before importing them
- Tell company tax codes, branch codes and personal tax codes apart
FAQ
Does a valid result mean the CCCD is real?
No. It means the number is well formed (known province code, possible birth year). Only the national population database can confirm a card, and it is not publicly accessible.
Is the number stored?
No. The number is checked in memory and is not written to logs or to the database. Use POST with a JSON body so it does not end up in access logs of proxies.
Why is the province different from where the person lives?
The first 3 digits are the province where the birth was registered, not the address. Codes refer to the 63 provinces before 07/2025; province_since_2025 gives the province after the merger.
Related APIs
IP Geolocation
Look up the country, region, city, coordinates, ASN and ISP of any IPv4 or IPv6 address – or your own IP – in one fast JSON call.
DNSDNS Lookup
Query A, AAAA, MX, TXT, NS, CNAME, SOA, CAA, SRV and more for any domain, or reverse-lookup an IP (PTR), via DNS over HTTPS. Clean JSON output.
@Email Validator
Validate e-mail addresses: syntax, MX/A records, ~120k disposable domains, role accounts, free providers and typo hints like gmial.com → gmail.com.