SGST vs UTGST: Which One Applies, and the Delhi Trap
Why some union territories charge UTGST and three charge SGST instead, the full code-by-code list, and how to get it right in a tax engine.
On an intra-state supply the tax splits into two halves. The central half is always CGST. The local half is SGST where the region has its own legislature, and UTGST where it does not. That is the whole rule, and it is not the rule most tax engines implement.
Most implement "union territory means UTGST", which is wrong for three of them. This article gives the correct test, the complete code-by-code list, and the reason a boolean flag will never get you there.
is_union_territory flag.',
]" />
The rule in one sentence
When the place of supply falls in the same state or union territory as the supplier, the supply is intra-state and two levies attach to it simultaneously. CGST is levied by the Union under the CGST Act, 2017 on every such supply, everywhere in India, without exception. The other half depends on who has the power to tax locally.
A state has a legislature, so it has its own SGST Act, and it levies SGST. A union territory without a legislature has no state government to pass such an Act, so the UTGST Act, 2017 supplies the missing half and the levy is called UTGST — Union Territory Goods and Services Tax. Same rate, same base, same line on the invoice, different statute and different collecting authority.
If the place of supply is in a different state or union territory from the supplier, none of this matters: the supply is inter-state, the Centre levies IGST alone, and there is no local half to label. The general shape of that choice is covered in CGST, SGST and IGST compared, and the determination itself sits in the place of supply rules. This article is only about the second half of the intra-state case.
The Delhi trap
Here is where systems break. Delhi, Puducherry and Jammu and Kashmir are union territories, and all three levy SGST, not UTGST — because each has a legislature of its own and therefore its own SGST Act.
Delhi is the expensive one, because Delhi is where the invoices are. A tax engine that carries an
is_union_territory boolean and branches on it will label every intra-Delhi supply as UTGST, and
it will do so silently and consistently, on every invoice, until somebody downstream notices. Puducherry and
Jammu and Kashmir fail the same way for the same reason; they are simply lower volume.
The correct test is not a property of the territory's constitutional category. It is whether that particular territory has a legislature, which is a fact about nine specific jurisdictions and cannot be derived from anything else in the record. In practice that means a hardcoded list — and a list is fine. It changes only when Parliament reorganises a territory, which has happened twice since GST began and both times with advance notice.
Every code, and what it levies
All 41 codes in the published table, with the local half each one attracts on an intra-state supply. The first two digits of any GSTIN carry this code, so you can read the answer straight off the supplier's number — see the GSTIN format for the rest of the fifteen characters, or the GST state code list for the jurisdictional detail behind each row.
| Code | Name | Kind | Local half | Note |
|---|---|---|---|---|
01 | Jammu and Kashmir | Union territory | SGST | Has a legislature. Union territory since 31 Oct 2019; kept its state-era code |
02 | Himachal Pradesh | State | SGST | |
03 | Punjab | State | SGST | |
04 | Chandigarh | Union territory | UTGST | No legislature |
05 | Uttarakhand | State | SGST | |
06 | Haryana | State | SGST | |
07 | Delhi | Union territory | SGST | Has a legislature — the classic misclassification |
08 | Rajasthan | State | SGST | |
09 | Uttar Pradesh | State | SGST | |
10 | Bihar | State | SGST | |
11 | Sikkim | State | SGST | |
12 | Arunachal Pradesh | State | SGST | |
13 | Nagaland | State | SGST | |
14 | Manipur | State | SGST | |
15 | Mizoram | State | SGST | |
16 | Tripura | State | SGST | |
17 | Meghalaya | State | SGST | |
18 | Assam | State | SGST | |
19 | West Bengal | State | SGST | |
20 | Jharkhand | State | SGST | |
21 | Odisha | State | SGST | |
22 | Chhattisgarh | State | SGST | |
23 | Madhya Pradesh | State | SGST | |
24 | Gujarat | State | SGST | |
25 | Daman and Diu | Union territory | UTGST | Legacy — merged into 26 on 26 Jan 2020, no longer issued |
26 | Dadra and Nagar Haveli and Daman and Diu | Union territory | UTGST | No legislature. Absorbed 25 |
27 | Maharashtra | State | SGST | |
28 | Andhra Pradesh (before bifurcation) | State | SGST | Legacy — replaced by 36 and 37, no longer issued |
29 | Karnataka | State | SGST | |
30 | Goa | State | SGST | |
31 | Lakshadweep | Union territory | UTGST | No legislature |
32 | Kerala | State | SGST | |
33 | Tamil Nadu | State | SGST | |
34 | Puducherry | Union territory | SGST | Has a legislature |
35 | Andaman and Nicobar Islands | Union territory | UTGST | No legislature |
36 | Telangana | State | SGST | |
37 | Andhra Pradesh | State | SGST | The post-bifurcation code |
38 | Ladakh | Union territory | UTGST | No legislature. Separated from 01 in 2019 |
96 | Other Country | Special | — | Not a place. No intra-state tax applies |
97 | Other Territory | Special | — | Not a place. No intra-state tax applies |
99 | Centre Jurisdiction | Special | — | Not a place. No intra-state tax applies |
Two things worth pulling out of that table. First, six codes levy UTGST and one of them is legacy, so a live
UTGST engine deals with five active territories — a small enough set that there is no excuse for getting it
wrong. Second, 96, 97 and 99 are not geographic jurisdictions and
should never be handed to a "which local half?" branch at all. Treat them as a separate kind and let the
caller decide what to do, rather than defaulting them to SGST because they are not on the UTGST list.
On the invoice and in the return
A tax invoice for an intra-state or intra-territory supply shows the two halves as separate line amounts, each with its own rate and its own value: CGST first, then either SGST or UTGST. A single consolidated "GST" line is not a compliant tax invoice, and the invoice format rules set out the rest of the required particulars.
Getting the label wrong on a printed invoice is a presentation defect. It is not free — a recipient whose own accounting system expects SGST from a Delhi supplier will raise a query, and somebody will spend an afternoon on it — but it is fixable in isolation.
The return is the serious case. Once the amounts are filed, they sit under the wrong head in the ledgers, and both parties inherit the problem: your liability is reported against a levy you did not incur, and the recipient's credit lands somewhere their own set-off logic did not expect. Correcting it means amending the filed data rather than reprinting a document. The cheapest place to fix a head is before it is filed, and the cheapest way to do that is to stop deriving it by hand.
Input tax credit works the same way
For credit purposes UTGST behaves exactly as SGST does. Credit of UTGST is set off against UTGST liability first and then against IGST, and — as with SGST — it can never be used against CGST. The bar is structural: the central half and the local half belong to different authorities, and letting one pay the other would move revenue between them with nothing to settle it.
The full sequence, including the order in which IGST credit must be exhausted first, is in the input tax credit rules. Nothing in it changes because the local half is called UTGST rather than SGST. If your set-off logic already handles SGST correctly, it handles UTGST correctly, provided the credit was recorded under the right head in the first place — which brings the problem back to classification.
Getting it right in code
Do not store an is_union_territory boolean and branch on it. It is the right answer to the
wrong question, and it fails on exactly the three highest-volume territories. Store a lookup table keyed by
the two-digit state code and read the levy straight out of it.
Our libraries ship that table. Both are MIT-licensed and dependency-free, on PyPI and npm:
from gstin_api import state_for_code, UTGST_CODES
state_for_code("04").intra_state_tax # 'UTGST' -- Chandigarh
state_for_code("07").intra_state_tax # 'SGST' -- Delhi, a union territory
state_for_code("27").intra_state_tax # 'SGST' -- Maharashtra
state_for_code("07").kind # 'union_territory'
state_for_code("99").kind # 'special' -- not a place
state_for_code("25").legacy # True -- still parses, never issued
# The first two digits of a GSTIN are the state code.
supplier = "07AABCU9603R1ZP"
state_for_code(supplier[:2]).intra_state_tax # 'SGST'
sorted(UTGST_CODES) # ['04', '25', '26', '31', '35', '38']
The Node and TypeScript package exposes the same table:
import { stateForCode, isUtgstState, UTGST_CODES } from '@dlminds/gstin-api';
stateForCode('04')?.intraStateTax; // 'UTGST'
stateForCode('07')?.intraStateTax; // 'SGST'
isUtgstState('04'); // true
isUtgstState('07'); // false <- the Delhi trap, handled
const gstin = '07AABCU9603R1ZP';
const localHalf = stateForCode(gstin.slice(0, 2))?.intraStateTax; // 'SGST'
Worked through: a supplier holding GSTIN 07AABCU9603R1ZP makes a supply where the place of
supply is also in Delhi. Code 07, intra-territory, so the halves are CGST and
SGST — despite Delhi being a union territory. At a notional 18%, that is 9% CGST and 9% SGST; the
GST calculator does the arithmetic, and
how to calculate GST covers the inclusive-price case. Rates move
with GST Council notifications, so confirm the live rate for your own HSN before invoicing.
Both packages also expose allStates() for the full table and a search helper for
name-to-code lookups, which is what the state code finder runs
on. If you want the levy resolved server-side alongside a live registry check, the
API documentation covers the endpoints, and
GST number search answers a single number in the browser. The
fifteenth character's arithmetic, if you are validating as well as classifying, is in
the GSTIN checksum algorithm.
Two codes that changed
Two codes are no longer issued but still appear in historic invoices, archived returns and vendor master data. A parser that rejects them as malformed will fail on real records.
| Code | Was | What happened | Now |
|---|---|---|---|
25 | Daman and Diu | Merged with Dadra and Nagar Haveli on 26 January 2020 into a single union territory | New registrations carry 26 |
28 | Andhra Pradesh, before bifurcation | Telangana was given 36; the remainder of Andhra Pradesh moved to 37 | Neither state issues 28 |
Both changes are reorganisations of territory, not of tax policy, and both landed with enough notice to plan for. The lesson for a tax engine is the same one the Delhi trap teaches: the mapping from a code to a levy is data, it changes on its own schedule, and it belongs in a table you can update rather than in a condition you have to rewrite.
Frequently asked questions
A note on accuracy. GST rules change often. This article reflects our understanding as of 8 September 2026 and is general information, not tax or legal advice. For the authoritative position, check gst.gov.in and cbic-gst.gov.in, or speak to a qualified tax professional about your specific situation.
Check a GSTIN right now, free
Five lookups a day, no account required. Status, filing history, e-invoicing and jurisdiction.
Free GST search toolBuild it into your product
One REST call, JSON back. Get an API key and 20 free verification credits in under a minute.
Start freeMore on gst rules & compliance
Browse every guide in the GST API blog.