Every GST-registered business in India has a 15-character GSTIN. It looks random, but every character has a job. If you know what those jobs are, you can catch most typos in your own form, before you spend a single API call on them.
We'll use a fictional sandbox GSTIN throughout: 29AAJCK4821M1Z1.
The five parts of a GSTIN
| Position | Example | What it is |
|---|---|---|
| 1–2 | 29 |
State code |
| 3–12 | AAJCK4821M |
PAN of the business |
| 13 | 1 |
Entity number for that PAN in that state |
| 14 | Z |
Reserved — Z by default |
| 15 | 1 |
Check character |
1. State code (characters 1–2)
The first two digits are the code of the state or union territory where the registration was issued, for example 07 for Delhi, 27 for Maharashtra, 29 for Karnataka and 33 for Tamil Nadu. A business registered in three states has (at least) three GSTINs, each starting with a different code.
2. PAN (characters 3–12)
The next ten characters are the business's PAN, so a GSTIN always belongs to exactly one PAN. The PAN itself follows a fixed shape: five letters, four digits, one letter. Its fourth character tells you the type of holder: C for a company, F for a firm or LLP, P for an individual, H for a Hindu Undivided Family, T for a trust, and so on.
That's why you can look up every GSTIN behind one PAN. It's also why the PAN inside a GSTIN should match the PAN the business gave you.
3. Entity number (character 13)
A business can hold more than one registration under the same PAN in the same state, for example separate business verticals. The 13th character counts them: 1 to 9, then A to Z. Most businesses have 1.
4. The reserved "Z" (character 14)
The 14th character is Z by default. If it's anything else, treat the input as suspect.
5. Check character (character 15)
The last character is computed from the first 14 with a mod-36 checksum. It catches almost every single-character typo and most swapped pairs. That makes it the cheapest validation you can run, because it needs no network at all.
Validating the check character
Map 0–9 to 0–9 and A–Z to 10–35. Walk the first 14 characters left to right, multiplying alternately by 1 and 2. For each product, add the quotient and the remainder of dividing by 36. The check value is (36 − sum mod 36) mod 36, mapped back to a character.
const CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
function gstinCheckChar(first14) {
let sum = 0;
for (let i = 0; i < 14; i++) {
const product = CHARS.indexOf(first14[i]) * (i % 2 === 0 ? 1 : 2);
sum += Math.floor(product / 36) + (product % 36);
}
return CHARS[(36 - (sum % 36)) % 36];
}
function isPlausibleGstin(input) {
const g = input.trim().toUpperCase();
if (!/^\d{2}[A-Z]{5}\d{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/.test(g)) return false;
return gstinCheckChar(g.slice(0, 14)) === g[14];
}
isPlausibleGstin("29AAJCK4821M1Z1"); // true
isPlausibleGstin("29AAJCK4821M1Z2"); // false: the check character doesn't matchYou can try it without writing any code in our free GSTIN validator. It runs entirely in your browser and shows which part of the input is wrong.
What a valid format does not tell you
A GSTIN that passes the checksum is well-formed, nothing more. It doesn't tell you:
- whether the registration exists at all,
- whether it's active, suspended or cancelled,
- whose legal name it's registered to, or
- whether the business actually files its returns.
For that you need the GST records themselves. One call to POST /v1/gst/verify returns the status, legal and trade names, registration date and taxpayer type:
curl https://api.apiserver.in/v1/gst/verify \
-H "Authorization: Bearer as_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"gstin": "29AAJCK4821M1Z1"}'GST Verify costs ₹0.75 per successful call, GST included. Calls that fail cost ₹0. If you also want filing history, the PAN check and the company's MCA record, Business360 returns all of it in one call, capped at ₹10.00 incl. GST.
The short version
- Validate the format and check character in your own form. It's free and instant.
- Make sure the PAN inside the GSTIN matches the PAN you were given.
- Then verify status and name against the GST records before you onboard, pay or claim ITC.