How to verify a GST number in Python

This walks through verifying an Indian GSTIN from Python end to end: validating the format offline so you never waste a credit, making the call, reading the response, and handling every failure the API can return. It takes about five minutes.

Up to 100 free lookups — they never expire. No credit card.

1. Install the Python library

An official client library exists for Python, and it handles the auth header and response parsing for you.

pip install gstinapi

Then verify a GSTIN in three lines:

from gstinapi import GstinApi

client = GstinApi(api_key="gak_your_key_here")

result = client.verify("33AAACC1206D1ZN")

print(result.legal_name)      # "CHENNAI CORPORATION LIMITED"
print(result.status)          # "Active"
print(result.taxpayer_type)   # "Regular"

Source on GitHub · package registry

Without the library (requests)

The API is a single GET with one header, so you can skip the library entirely if you would rather not add a dependency.

import requests

resp = requests.get(
    "https://gstinapi.in/v1/gstin/33AAACC1206D1ZN",
    headers={"x-api-key": "gak_your_key_here"},
    timeout=10,
)
resp.raise_for_status()
data = resp.json()

print(data["legal_name"], data["status"])

2. Validate the GSTIN offline first

A malformed GSTIN returns 400 and costs nothing — but it still costs a round trip. The GSTIN checksum is computable offline, so catch typos before you spend the network call.

CODES = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

def is_valid_gstin(gstin: str) -> bool:
    """Validate a GSTIN's format and check digit without calling the API."""
    gstin = (gstin or "").strip().upper()
    if len(gstin) != 15:
        return False

    total = 0
    for i, ch in enumerate(gstin[:14]):
        if ch not in CODES:
            return False
        product = CODES.index(ch) * (2 if i % 2 else 1)
        total += product // 36 + product % 36

    expected = CODES[(36 - total % 36) % 36]
    return gstin[14] == expected


assert is_valid_gstin("33AAACC1206D1ZN")
assert not is_valid_gstin("33AAACC1206D1ZZ")

This proves the GSTIN is well-formed. It cannot tell you whether the registration exists or is still active — only a live lookup does that, because registrations get cancelled.

3. Handle every status code

CodeMeaningWhat to do
400Invalid GSTIN formatNo credit charged. Validate client-side and this never fires.
401Missing or invalid x-api-keyCheck the header name and that the key is not truncated.
402Out of creditsDifferent from 404 — the lookup never ran. Surface a recharge prompt, not "not found".
404GSTIN not registeredA valid-format GSTIN that the GST network has no record of.
429Rate limit exceeded60 requests/minute on standard accounts. Retry with backoff.
502GST provider unavailableUpstream GSP hiccup. Safe to retry — nothing was charged.

Retry policy. Retry only on 429 and 502, with exponential backoff, maximum 3 attempts. Never retry 400, 401, 402, 403 or 404 — the answer will not change.

import time
import requests

RETRYABLE = {429, 502}

def verify(gstin: str, api_key: str, attempts: int = 3):
    for attempt in range(attempts):
        resp = requests.get(
            f"https://gstinapi.in/v1/gstin/{gstin}",
            headers={"x-api-key": api_key},
            timeout=10,
        )

        if resp.status_code == 200:
            return resp.json()
        if resp.status_code == 404:
            return None                       # valid format, no such registration
        if resp.status_code == 402:
            raise RuntimeError("Out of credits — recharge at https://gstinapi.in/buy-credits")
        if resp.status_code not in RETRYABLE:
            raise RuntimeError(resp.json().get("error", resp.text))

        if attempt < attempts - 1:
            time.sleep(2 ** attempt)          # 1s, then 2s

    raise RuntimeError("GST provider unavailable after retries")

4. Wiring it into Django or FastAPI

Keep the key in an environment variable, never in source. Call the API at the point a vendor record is created or edited, not on every page render — a GSTIN changes rarely, so cache the result against the vendor row and re-check on a schedule instead.

import os
from gstinapi import GstinApi

client = GstinApi(api_key=os.environ["GSTIN_API_KEY"])

Frequently asked questions

Is there a free way to verify GST numbers in Python?

Yes. Every account gets up to 100 free lookups — 25 on signup and 25 for each setup step — and they never expire. That is enough to evaluate the API properly against your own data without paying anything. No credit card is needed to get a key.

Can I validate a GSTIN in Python without an API call?

You can validate the format and the check digit offline — the code on this page does exactly that, and it catches typos for free. What you cannot do offline is confirm the GSTIN is actually registered, who it belongs to, or whether it is still active. Only a live lookup answers that, because registrations get cancelled.

How do I verify GST numbers in bulk from Python?

Loop over your list and call the endpoint per GSTIN, staying inside the 60 requests/minute limit — a short sleep between calls, or a semaphore capped well under 60/min if you go concurrent. Handle 429 by backing off rather than by hammering. There is no separate bulk endpoint; the per-call API is the bulk API.

Which Python version does the library need?

The gstinapi package targets currently supported Python 3 releases. If you are on something older, the raw requests example on this page works anywhere requests does.

The same guide in another language

Ready to integrate?

Create an account, generate a key, and you start with 25 free lookups — up to 100 once you finish the setup steps. No card, and they never expire.

Need to check a single GSTIN right now? Use the free search tool — no signup.