gst-validator
Validate Indian GSTINs offline and pull taxpayer details from the public GST portal.
Install · CLI · Library · Data · Contributing
A typed Python library and CLI for the Indian GST taxpayer search. It checks a GSTIN's structure and checksum without touching the network, and wraps the portal's undocumented endpoints in objects you can actually hold.
from gst_validator import GSTIN, GSTClient
GSTIN.is_valid("27AAACR5055K1Z7") # True, offline, no network
with GSTClient() as client:
client.fetch_goods_and_services("27AAACR5055K1Z7") # no captcha needed
Why this exists
The GST portal has no public API for taxpayer search. What it has is a
captcha-gated web form and a handful of undocumented JSON endpoints that
return "NA" for null, dd/mm/yyyy for dates, two different shapes for the
same field, and HTTP 200 for errors. This package absorbs that so your code
sees datetime.date, None and exceptions.
What it does
| Validates offline | Format and mod-36 checksum, plus state, PAN or TAN, entity and registration type decoded from the number. No network, no rate limit |
| Knows every layout | Ordinary, TDS deductor, TCS collector, UIN (UN bodies and embassies) and the separate one used by non-resident online-service providers |
| Finds every registration | One PAN gives you a company's GSTIN in every state it operates in, with each one's status |
| Bulk by default | A CSV column, a file of GSTINs or stdin; CSV, JSON, JSON Lines or table out |
| Typed objects | Dates parsed, "NA" normalised, nothing silently dropped, py.typed shipped |
| Captcha, your way | Raw bytes, base64 or a data: URI, so a browser, a person or a service can solve it |
| Eleven portal searches | Taxpayer, PAN, HSN/SAC codes, composition scheme, applications, notices, practitioners and more |
| Five free endpoints | HSN/SAC search, the practitioner directory, codes, years and filing preferences need no captcha |
| Sync and async | The same API with await, both strict-typed |
| Caches properly | A lookup costs a human-solved captcha, so results persist between CLI runs |
Documentation
| Guide | What is in it |
|---|---|
| CLI guide | Every flag, the five output formats, batching, exit codes |
| Library guide | The Python API, layouts, caching, errors, and every field returned |
| Recipes | Whole tasks: checking a supplier spreadsheet, serving a web app, enriching a list |
| Portal reference | What the portal actually returns, its quirks, and how each claim was verified |
A taste of it
Validate a whole spreadsheet column without touching the network:
gst-validator - --offline --column gstin --format csv < suppliers.csv > checked.csv
Add the portal data that needs no captcha:
gst-validator - --offline --enrich --format json < gstins.txt -o enriched.json
Look one up properly, solving a captcha once:
gst-validator 27AAACR5055K1Z7 --json | jq -r .legal_name
List every GSTIN a company holds, found by its PAN:
gst-validator --pan AAACR5055K --json
Look up a commodity code, or check a notice is genuine:
gst-validator --hsn 3926 # no captcha
gst-validator --rfn RF2701250000001 # was this really issued?
From Python:
from gst_validator import GSTIN, validate_many
GSTIN.is_valid("27AAACR5055K1Z7") # True, offline
for row in validate_many(["27AAACR5055K1Z7", "nope"]):
print(row.value, row.is_valid, row.error)
Install
uv add gst-validator # into a uv project
pip install gst-validator # or plain pip
uvx gst-validator --help # or run it without installing
Python 3.13 or newer. Two runtime dependencies: httpx for the HTTP layer and rich for the CLI output.
Then read the CLI guide or the library guide, depending on how you mean to use it.
Development
uv sync # install, including dev dependencies
uv run pytest # fully offline, via httpx.MockTransport
uv run mypy # strict
uv run pyright # strict
uv run ruff check .
Tests parse payloads with the exact shape the live portal returns
(tests/fixtures/: a service provider, a manufacturer, a statutory body, a
cancelled registration, a composition dealer, a UIN holder and a goods list)
and assert unmapped == {}, so a portal schema change fails the suite
instead of quietly losing data.
The GSTINs used here and in the tests are of two kinds, both deliberate. Some
are real, published registrations of large organisations - 27AAACR5055K1Z7
is Reliance Industries, and the suite also covers ones belonging to Amazon,
Indian Railways, GoDaddy and UNICEF - which are printed on the invoices those
bodies issue and are corporate records, not anyone's personal data. The rest
are invented and checksum-valid, used wherever a payload had to be made up.
No individual's registration appears anywhere in the repository, and the
fixtures captured from live lookups have their identifying values replaced.
Releasing
Releases are automated with
release-please. Commits on
main follow Conventional Commits
(feat:, fix:, portal:, ...); a bot keeps a release pull request up to
date with the next version number and the changelog. Merging it bumps the
version, tags, publishes to PyPI and creates the GitHub release. Nothing is
tagged or edited by hand. Details in CONTRIBUTING.md.
Contributing
Issues and pull requests are welcome. See CONTRIBUTING.md for the setup and the house rules; the short version:
uv sync
uv run pytest -q && uv run ruff check . && uv run mypy && uv run pyright
Two rules matter more than the rest: tests never touch the network
(everything goes through httpx.MockTransport), and no real taxpayer's data
in the repo - fixtures use a public company's registration or a fictional,
checksum-valid GSTIN.
If the portal changes shape, that is a
portal change issue;
include the output of --raw with the identifying values replaced.
Everyone taking part is expected to follow the Code of Conduct.
Security reports go through private advisories, not public issues. See SECURITY.md.
Links
- CLI guide · Library guide · Recipes · Portal reference
- PyPI
- Changelog
- Contributing · Code of Conduct · Security policy
- Official GST developer portal - the licensed GSP route for unattended, high-volume use
License
MIT. See LICENSE.
Metadata
Release files for gst-validator 0.5.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gst_validator-0.5.2.tar.gz | 41.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gst_validator-0.5.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 89.6 kB
Release files / gst_validator-0.5.2.tar.gz
| Download URL | gst_validator-0.5.2.tar.gz |
|---|---|
| Size | 41.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
36be966600d01d5412435c6339e410b9c2df8e50e4defed19e63dc7e9a6ba4c8
|
|
BLAKE2b-256 checksum How to use checksums |
927cba98ff3611889c48947b1268321442a0dd2898b2d544bc877a1345779fcc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / gst_validator-0.5.2-py3-none-any.whl
| Download URL | gst_validator-0.5.2-py3-none-any.whl |
|---|---|
| Size | 47.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2bee3317dd0832c437a7b19e99eb0620ebdde66c6f109dc5fa4775705c73a790
|
|
BLAKE2b-256 checksum How to use checksums |
893744694d38e11bf649fb6d61091c80760dbab2eace8d5e449b7765b07228c7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log