किसी कंपनी की accounts payable टीम रोज़ दर्जनों इनवॉइस पास करती है। हर इनवॉइस पर वेंडर का GSTIN छपा होता है, और कोई नहीं देखता कि वह नंबर चालू है, रद्द हो चुका है, या किसी और का है। जिस दिन ऑडिट में एक रद्द GSTIN वाला वेंडर पकड़ में आता है, उस दिन टीम सोचती है कि यह जाँच कोड में क्यों नहीं थी। यह गाइड उसी जाँच को कोड में लाने का तरीक़ा है।
GSTIN को प्रोग्राम से verify करने के लिए /v1/verify/gstin पर POST भेजिए, जिसमें पंद्रह अक्षर का नंबर और, अगर आपके पास है तो, वह कारोबारी नाम हो जिसकी आप उम्मीद करते हैं। जवाब बताता है कि रजिस्ट्रेशन मौजूद है या नहीं (valid), किस legal और trade name से, किस स्थिति में (registrationStatus) और किस principal place of business पर। Active पास होने की शर्त है। इसके अलावा जो भी आए, उस पर प्रवाह रुकना चाहिए या किसी इंसान के पास जाना चाहिए।
call आसान हिस्सा है। मुश्किल हिस्से उसके आसपास हैं: call से पहले नंबर की जाँच, हर status का आपके कारोबार के लिए मतलब, अच्छे वेंडरों को ठुकराए बिना नामों की तुलना, यह पक्का करना कि GSTIN उसी PAN का है जिस पर आप भरोसा कर चुके हैं, बाद में दोबारा जाँच क्योंकि रजिस्ट्रेशन बदलते हैं, और rate limit तोड़े बिना हज़ारों जाँचें चलाना। यह गाइड हर टुकड़ा StampMitra endpoint के सामने चलते कोड से बनाती है।
मान लिया गया है कि आप जानते हैं GSTIN क्या होता है। न जानते हों तो पहले PAN, GSTIN और CIN में फ़र्क में बनावट देखिए, और फ़ाइनेंस की नज़र से सप्लायर ऑनबोर्डिंग और इनवॉइस के जोखिम के लिए पुरानी GSTIN verification API गाइड है।
मुख्य बातें
- एक endpoint:
POST /v1/verify/gstin, scopeverification.gstin.read। ज़रूरी फ़ील्डgstin, वैकल्पिकbusinessName। प्रमाणीकरणAuthorization: Bearer <key>याx-api-keyसे। - format की विफलता lookup से पहले 400 देती है और उसका कोई शुल्क नहीं। नकारात्मक नतीजा (
valid: false) पूरी हुई lookup है और production में बिल होती है। - जवाब में
valid,legalNameOfBusiness,tradeNameOfBusiness,gstinStatus,taxpayerType,constitutionOfBusiness,dateOfRegistration, अधिकार-क्षेत्र,natureOfBusinessActivities, मुख्य और अतिरिक्त पते (string और हिस्सों में बँटे हुए),message,gstinऔरGSTINमें नंबर, और हमारी दो ids,referenceIdऔरverificationId, होते हैं। पुराने नामlegalName,tradeName,registrationStatusऔरprincipalPlaceOfBusinessमें वही मान आते हैं। registrationStatusको खुला समूह मानिए। docs मेंActiveदिखता है; स्रोत पर और स्थितियाँ हैं जिनकी सूची नहीं दी गई।Activeपर पास, बाक़ी सब समीक्षा में, और कच्चा मान लॉग।- जवाब में रद्द होने की प्रभावी तारीख़ या रिटर्न भरने का इतिहास नहीं है। फ़ैसला इन पर टिके तो दूसरा स्रोत या इंसान चाहिए।
- वेंडर का नाम
legalNameसे मिलाइए,tradeNameसे नहीं, और GSTIN में बैठे PAN को उस PAN से मिलाइए जिसे आप verify कर चुके हैं। - GSTIN किसी एक समय का तथ्य है। तय अंतराल पर और बड़े भुगतान से पहले दोबारा जाँचिए।
- बड़ी मात्रा में जाँच के लिए concurrency सीमित रखिए और 429 पर backoff लगाइए। docs का उदाहरण-सीमा है प्रति endpoint 60 सेकंड में 60 requests।
पहले जवाब पढ़ना सीखिए: status का मतलब क्या है
इस गाइड को उल्टा क्रम देते हैं, क्योंकि call लिखने से पहले यह तय होना चाहिए कि जवाब का क्या करना है। reference में एक उदाहरण मान Active दिखता है और बाक़ी की सूची नहीं मिलती। स्रोत पर GST रजिस्ट्रेशन एक से ज़्यादा स्थितियों में हो सकता है, इसलिए अपना तर्क खुले समूह के लिए लिखिए। नीचे की तालिका वे स्थितियाँ बताती है जो सबसे ज़्यादा मिलती हैं और समझदार integration उनके साथ क्या करता है। मतलब को सामान्य जानकारी मानिए, और जिसका टैक्स पर असर हो उसे अपने सलाहकार से पक्का कीजिए।
registrationStatus | सामान्य मतलब | आम व्यवहार |
|---|---|---|
Active | रजिस्ट्रेशन लागू है | पास, बशर्ते नाम और PAN की जाँच भी ठीक हो |
| Cancelled | रजिस्ट्रेशन रद्द हो गया है, करदाता के आवेदन पर या कर प्राधिकरण द्वारा | नई GST इनवॉइसिंग के लिए रोकिए। रद्द करना बाद में पलटा जा सकता है, इसलिए दोबारा जाँच से जवाब बदल सकता है |
| Suspended | रजिस्ट्रेशन अस्थायी रूप से निलंबित है, आम तौर पर रद्द करने की कार्यवाही लंबित रहने के दौरान | रोक दीजिए। समाधान तक GST वाले लेन-देन के लिए ऑनबोर्ड मत कीजिए |
| कुछ और, या ख़ाली मान | ऐसी स्थिति जिसे आपका कोड नहीं पहचानता | समीक्षा। कच्चा मान और referenceId लॉग कीजिए और समझ आने पर अपनी तालिका में जोड़िए |
तीन स्पष्टीकरण।
पहला, valid: false और ग़ैर-सक्रिय status अलग नतीजे हैं। valid: false का मतलब है कि lookup को उस नंबर से मेल खाता रजिस्ट्रेशन नहीं मिला: टाइपो जो format validation पास कर गया, ऐसा नंबर जो कभी जारी नहीं हुआ, या मिलान की विफलता। valid: true के साथ ग़ैर-सक्रिय registrationStatus का मतलब है कि रजिस्ट्रेशन मौजूद है और ऐसी स्थिति में है जिसकी आपको व्याख्या करनी है। दोनों को अलग शाखाओं में, अलग संदेशों के साथ सँभालिए।
दूसरा, जवाब status देता है, पर यह नहीं कि वह कब बदला। रद्द होने की तारीख़ इस बात पर असर डाल सकती है कि उससे पहले बनी इनवॉइसें input tax credit के लिहाज़ से ठीक हैं या नहीं। इस जवाब में वह तारीख़ नहीं है, इसलिए Cancelled का नतीजा रुककर किसी इंसान से पूछने की वजह है, कोड में तारीख़ों का हिसाब लगाने की नहीं।
तीसरा, जवाब में रिटर्न भरने की स्थिति या रद्द होने की प्रभावी तारीख़ नहीं है। आपकी नीति इनमें से किसी पर टिकी हो तो दूसरा स्रोत या वेंडर से दस्तावेज़ चाहिए। करदाता का प्रकार, जो बताता है कि रजिस्ट्रेशन composition योजना में है या नहीं, और कारोबार की संरचना जवाब में taxpayerType और constitutionOfBusiness के रूप में हैं; इन्हें legal name से अंदाज़े से निकालने की जगह सीधे पढ़िए।
पहली call से पहले क्या चाहिए
| बात | मान |
|---|---|
| Base URL | https://api-b2b.stampmitra.in |
| Path | POST /v1/verify/gstin |
| प्रमाणीकरण | Authorization: Bearer <key> या x-api-key: <key> |
| key पर scope | verification.gstin.read (इसके बिना 403 FORBIDDEN) |
| बॉडी | gstin (ज़रूरी, 15 अक्षर), businessName (वैकल्पिक) |
| बिलिंग | सफल जवाब के बाद gstin.verify के रूप में गिनी जाती है; sandbox कभी wallet नहीं काटता |
| Sync या async | Synchronous। जवाब उसी HTTP response में है। |
| Sandbox key | sk_test_ से शुरू; production key sk_live_ से |
quickstart से sandbox key लगभग पाँच मिनट में मिल जाती है। key अपने सर्वर पर रखिए। ब्राउज़र या मोबाइल ऐप से कभी मत भेजिए।
यह call आपके सिस्टम में कहाँ बैठे
GSTIN की जाँच एक छोटे utility function जैसी दिखती है, पर उसे कहाँ रखते हैं यह भरोसेमंदी तय करता है। तीन जगहें आम हैं, और हर एक अलग प्रोडक्ट को जमती है।
request के भीतर, सीधे। यूज़र फ़ॉर्म में GSTIN डालता है और हरे निशान का इंतज़ार करता है। यह तुरंत प्रतिक्रिया देता है और छोटे प्रवाहों के लिए ठीक है जहाँ ग़लत नंबर वहीं सुधार लिया जाता है। क़ीमत यह है कि आपके पेज की देरी में अब तीसरे पक्ष की call शामिल है, इसलिए पक्का timeout रखिए (दस सेकंड एक वाजिब ऊपरी सीमा है), प्रगति दिखाइए और फ़ॉर्म ऐसा बनाइए कि timeout में यूज़र का टाइप किया हुआ न खोए। ब्राउज़र को StampMitra सीधे कभी call नहीं करना चाहिए, क्योंकि इससे key पेज में आ जाएगी। ब्राउज़र आपके सर्वर को बुलाता है, और आपका सर्वर API को।
बैकग्राउंड job में। वेंडर फ़ॉर्म जमा करता है, आप स्वीकार करते हैं, और एक worker जाँचें चलाता है। यह कई जाँचों वाले प्रवाह (PAN, GSTIN, bank account) के लिए ठीक है, क्योंकि आप उनका क्रम तय कर सकते हैं, पहली पक्की विफलता पर रुक सकते हैं और अस्थायी एरर पर बिना किसी के इंतज़ार किए retry कर सकते हैं। हर नतीजा आते ही आवेदन के साथ सहेजिए। GSTIN और bank account की जाँच के बीच crash हुआ job वहीं से चले जहाँ रुका था, दोबारा शुरू न हो और दो बार पैसे न दे।
तय समय पर चलने वाला sweep। ऊपर वाला re-check job, जो हर वेंडर को एक टाइमर पर छूता है। उसके पास सूचित करने को कोई यूज़र नहीं, इसलिए उसे अपना अलर्ट चाहिए: वेंडर पर flag, टिकट, या procurement मालिक को ईमेल।
जो भी चुनें, call को एक छोटे मॉड्यूल के पीछे रखिए। इस गाइड की हर चीज़ (इनपुट normalise करना, एरर map करना, फ़ैसले का function) वहीं रहती है, ताकि बाक़ी कोडबेस पूछे "क्या यह GSTIN इस वेंडर के लिए स्वीकार्य है?" और उसे कारणों के साथ PASS, REVIEW या FAIL मिले, कच्चा HTTP नहीं।
एक और डिज़ाइन बिंदु: verification endpoint उस अर्थ में idempotent नहीं हैं कि दोहराई गई calls को वे एक कर दें। referenceId हर call की पहचान है, ऐसे request की नहीं जिसे बिना ख़र्च दोहराया जा सके। अगर आपका job runner crash के बाद task दोबारा चलाता है, तो job को खुद idempotent बनाइए: दोबारा call करने से पहले दर्ज कीजिए कि जाँच हो चुकी है।
चरण 1: call से पहले इनपुट को सामान्य कीजिए और जाँचिए
किसी भी चीज़ से पहले खाली जगहें हटाइए और अक्षर बड़े कीजिए। docs format को 07AAAAA1111A1Z1 बताते हैं और छोटे-बड़े अक्षरों को बराबर मानने का वादा नहीं करते, इसलिए उस पर भरोसा मत कीजिए। फिर लागत और उपयोगिता के क्रम में तीन ऑफ़लाइन जाँचें चलाइए: बनावट, राज्य कोड और चेक कैरेक्टर।
import re
SHAPE = re.compile(r"^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$")
CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
STATE_CODES = {
"01","02","03","04","05","06","07","08","09","10","11","12","13","14","15","16","17","18","19","20",
"21","22","23","24","26","27","29","30","31","32","33","34","35","36","37","38","97","99",
}
def check_char(first14: str) -> str:
total = 0
for i, ch in enumerate(first14):
product = CHARSET.index(ch) * (1 if i % 2 == 0 else 2)
total += product // 36 + product % 36
return CHARSET[(36 - total % 36) % 36]
def normalise_gstin(raw, production: bool) -> dict:
gstin = "".join((raw or "").split()).upper()
if not SHAPE.match(gstin):
return {"ok": False, "reason": "FORMAT"}
if gstin[:2] not in STATE_CODES:
return {"ok": False, "reason": "STATE_CODE"}
if production and check_char(gstin[:14]) != gstin[14]:
return {"ok": False, "reason": "CHECK_CHARACTER"}
return {"ok": True, "gstin": gstin, "state_code": gstin[:2], "embedded_pan": gstin[2:12]}production का झंडा मायने रखता है। docs का सैंपल GSTIN और दर्ज sandbox GSTIN का चेक कैरेक्टर सही नहीं है, इसलिए चेक कैरेक्टर का टेस्ट उन्हें ठुकरा देगा। production = api_key.startswith("sk_live_") पास कीजिए।
हर कारण का एक यूज़र संदेश बनता है। FORMAT कहता है कि नंबर पंद्रह अक्षर-अंकों का होना चाहिए। STATE_CODE कहता है कि शुरू के दो अंक किसी वैध राज्य या केंद्र शासित प्रदेश के कोड नहीं हैं। CHECK_CHARACTER कहता है "कृपया आख़िरी अक्षर जाँचिए"। तीनों बिना ख़र्च के टाइपो पकड़ते हैं।
चरण 2: endpoint को call कीजिए
कच्चा अनुरोध छोटा है।
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/gstin" \
-H "Authorization: Bearer $STAMPMITRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"gstin":"07AAAAA1111A1Z1","businessName":"Jane Doe Enterprises"}'docs की बनावट में एक सफल जवाब:
{
"referenceId": "SMV-20260927-9K21P4",
"GSTIN": "07AAAAA1111A1Z1",
"valid": true,
"legalName": "Jane Doe Enterprises Private Limited",
"tradeName": "Jane Doe Enterprises",
"registrationStatus": "Active",
"principalPlaceOfBusiness": "123, MG Road, Bengaluru, Karnataka, 560001",
"message": "GSTIN Exists"
}timeout, एरर की मैपिंग और सामने ऑफ़लाइन validation के साथ Python का क्लाइंट:
import os, requests
BASE = "https://api-b2b.stampmitra.in/v1/verify/gstin"
class GstinError(Exception):
def __init__(self, kind, **detail):
super().__init__(kind)
self.kind, self.detail = kind, detail
def verify_gstin(gstin: str, business_name: str | None = None, api_key: str | None = None) -> dict:
api_key = api_key or os.environ["STAMPMITRA_API_KEY"]
inp = normalise_gstin(gstin, production=api_key.startswith("sk_live_"))
if not inp["ok"]:
raise GstinError("INVALID_INPUT", reason=inp["reason"])
payload = {"gstin": inp["gstin"], **({"businessName": business_name} if business_name else {})}
r = requests.post(BASE, json=payload, timeout=10,
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"})
body = r.json() if r.content else {}
if not r.ok:
err = body.get("error", {})
raise GstinError("API_ERROR", status=r.status_code, code=err.get("code"), request_id=err.get("requestId"))
return {**body, "embedded_pan": inp["embedded_pan"], "state_code": inp["state_code"]}अगर आपको raw HTTP की जगह package चाहिए तो pre-release SDKs इसी endpoint को लपेटते हैं। नीचे का व्यवहार नहीं बदलता।
जवाब, फ़ील्ड-दर-फ़ील्ड
| फ़ील्ड | प्रकार | मतलब | कैसे इस्तेमाल करें |
|---|---|---|---|
referenceId | string | इस call की StampMitra पहचान, रूप SMV-YYYYMMDD-XXXXXXX, नकारात्मक नतीजे पर भी मौजूद | इसे अपने फ़ैसले के साथ सहेजिए। यह idempotency key नहीं है। |
GSTIN | string | जाँचा गया नंबर (बड़े अक्षरों वाला फ़ील्ड नाम ध्यान दीजिए) | जो भेजा उससे मिलाइए |
valid | boolean | उस नंबर का रजिस्ट्रेशन मिला या नहीं | सबसे पहले इस पर शाखा कीजिए |
legalName | string | रजिस्ट्रेशन पर legal name | संस्था के पंजीकृत नाम से मिलाइए |
tradeName | string | ट्रेड या ब्रांड नाम | संदर्भ, पहचान की जाँच नहीं |
registrationStatus | string | स्रोत पर रजिस्ट्रेशन की स्थिति | फ़ैसले वाला फ़ील्ड; ऊपर का हिस्सा देखिए |
principalPlaceOfBusiness | string | मुख्य कारोबारी पता | पते की जाँच का संदर्भ; माल कहाँ से जाता है इसका सबूत नहीं |
message | string | GSTIN Exists जैसा पढ़ने लायक सार | दिखाइए या लॉग कीजिए; तर्क के लिए parse मत कीजिए |
फ़ील्ड के नाम पर एक बात। ज़्यादातर StampMitra verification जवाब camel case इस्तेमाल करते हैं, जबकि GSTIN नंबर की गूँज GSTIN में आती है। असली key reference से पढ़िए, आदतन normalise मत कीजिए।
फ़ैसले का function जिसे दोबारा इस्तेमाल करें
जवाब से फ़ैसले तक की मैपिंग एक ही शुद्ध function में रखिए ताकि उसे परखना और बदलना आसान रहे।
import re
def norm(s):
s = (s or "").upper()
s = re.sub(r"[.,&()\-]", " ", s)
s = re.sub(r"\b(PRIVATE|PVT)\b", "PVT", s)
s = re.sub(r"\b(LIMITED|LTD)\b", "LTD", s)
return re.sub(r"\s+", " ", s).strip()
def decide_gstin(res: dict, expected_pan: str | None = None, expected_name: str | None = None) -> dict:
ref = res.get("referenceId")
if not res.get("valid"):
return {"decision": "FAIL", "reasons": ["NOT_FOUND"], "reference_id": ref}
reasons = []
status = res.get("registrationStatus")
if status != "Active":
reasons.append(f"STATUS_{str(status or 'EMPTY').upper()}")
if expected_pan and res.get("embedded_pan") and res["embedded_pan"] != expected_pan:
reasons.append("PAN_MISMATCH")
if expected_name and norm(res.get("legalName")) != norm(expected_name):
reasons.append("NAME_DIFFERS")
if "PAN_MISMATCH" in reasons:
return {"decision": "FAIL", "reasons": reasons, "reference_id": ref}
return {"decision": "REVIEW" if reasons else "PASS", "reasons": reasons, "reference_id": ref}बनावट जान-बूझकर ऐसी है। PAN_MISMATCH पक्की विफलता है, क्योंकि जिस GSTIN में उस संस्था से अलग PAN है जिसे आपने verify किया, वह उस संस्था का रजिस्ट्रेशन नहीं है। status और नाम का फ़र्क reject की जगह समीक्षा में जाता है, क्योंकि उनकी निर्दोष वजहें हो सकती हैं। function कारण वाक्य नहीं, कोड लौटाता है, ताकि आपकी समीक्षा कतार उन्हें समूहित और गिन सके।
पाँच नतीजे, उदाहरण के साथ
फ़ैसले का function मामलों के साथ पढ़ना आसान होता है। ये गढ़े हुए कारोबारों और docs की जवाब-बनावट पर हैं।
1. साफ़ मिलान। वेंडर Jane Doe Enterprises Private Limited है, जिसका PAN verify हो चुका है और GSTIN में वही PAN बैठा है। जवाब में valid: true, registrationStatus: Active और legalName Jane Doe Enterprises Private Limited है। GSTIN में बैठा PAN verify किए PAN के बराबर है, और सामान्य रूप में आने पर नाम मेल खाते हैं। फ़ैसला: PASS। referenceId, status और समय सहेजिए।
2. रद्द रजिस्ट्रेशन। वेंडर 09SNDBX9999F1Z5 भेजता है, वही sandbox वैल्यू जो not valid और Cancelled status लौटाने के लिए दर्ज है। reference नहीं बताता कि असली रद्द रजिस्ट्रेशन valid: false आता है या valid: true के साथ Cancelled status, इसलिए आपका कोड दोनों को सँभाले: कोई भी ग़ैर-सक्रिय status और हर valid: false वेंडर को मंज़ूरी से पहले रोक देता है। फ़ैसला: status के कारण के साथ REVIEW, या NOT_FOUND के साथ FAIL। वेंडर को संदेश तटस्थ रहे: "हम इस नंबर के लिए सक्रिय GST रजिस्ट्रेशन की पुष्टि नहीं कर सके। कृपया मौजूदा रजिस्ट्रेशन प्रमाणपत्र भेजिए या नंबर की पुष्टि कीजिए।" आरोप मत लगाइए। रद्दीकरण कभी-कभी पलट दिए जाते हैं, और वेंडर की बहाली लंबित हो सकती है।
3. किसी और का PAN समेटे GSTIN। वेंडर का verify किया PAN ABCDE1234F है। वह ऐसा GSTIN बताता है जिसके अक्षर 3 से 12 किसी और PAN के हैं, और lookup उस दूसरे कारोबार के लिए valid: true और Active लौटाता है। फ़ैसला: PAN_MISMATCH के साथ FAIL। यही वह मामला है जिसे नाम की तुलना चूक सकती है अगर दूसरे कारोबार का नाम मिलता-जुलता हो, और PAN की तुलना ठीक इसीलिए है। कुछ और करने से पहले वेंडर से पूछिए कि रजिस्ट्रेशन किस PAN पर हुआ।
4. हानिरहित फ़र्क़ वाला नाम। वेंडर का पंजीकृत नाम "Sharma and Sons Traders" है। लौटा legalName "SHARMA & SONS TRADERS" है। सामान्य रूप में लाने के बाद वे मेल खाते हैं। बिना सामान्य किए सख़्त तुलना एक बिल्कुल ठीक वेंडर को ठुकरा देती। फ़ैसला: PASS।
5. ग़लत टाइप किया नंबर। वेंडर के GSTIN में एक अक्षर ग़लत है। अगर चेक कैरेक्टर ग़लत है तो आपकी ऑफ़लाइन जाँच call से पहले ही पकड़ लेती है और "कृपया आख़िरी अक्षर जाँचिए" दिखाती है। अगर टाइपो से कोई और बनावट-वैध नंबर बन जाए, तो lookup valid: false लौटाता है, या बिल्कुल अलग कारोबार का रिकॉर्ड। दूसरी हालत में फिर से PAN की तुलना ही बचाती है। valid: false का फ़ैसला: NOT_FOUND के साथ FAIL, और यूज़र को वह संदेश जो नंबर दोबारा डालने को कहे, वह नहीं जो कहे कि वेंडर पंजीकृत नहीं है।
ध्यान दीजिए पाँचों में क्या साझा है: हर फ़ैसला कारणों को कोड में रखता है, और हर यूज़र संदेश दोष देने से बचता है।
हर नतीजे पर यूज़र को क्या बताएँ
डेवलपर एरर संदेश बाद की बात की तरह लिखते हैं, और वेंडर उन्हें आरोप की तरह पढ़ते हैं। हर शाखा के शब्द पहले से तैयार रखिए।
| फ़ैसला | कारण | सुझाया संदेश |
|---|---|---|
INVALID_INPUT | format, राज्य कोड या चेक कैरेक्टर | "यह वैध GSTIN जैसा नहीं दिखता। इसमें 15 अक्षर-अंक होते हैं। कृपया जो लिखा है उसे जाँचिए।" |
FAIL | NOT_FOUND | "हमें इस नंबर का रजिस्ट्रेशन नहीं मिला। कृपया दोबारा लिखिए या अपना रजिस्ट्रेशन प्रमाणपत्र भेजिए।" |
REVIEW | status सक्रिय नहीं | "हम अभी सक्रिय रजिस्ट्रेशन की पुष्टि नहीं कर सके। हमारी टीम आपसे संपर्क करेगी, या आप मौजूदा प्रमाणपत्र अपलोड कर सकते हैं।" |
REVIEW | नाम अलग | "रजिस्ट्रेशन पर नाम आपके लिखे नाम से थोड़ा अलग है। कृपया अपने कानूनी नाम की पुष्टि कीजिए।" |
FAIL | PAN बेमेल | "यह GSTIN आपके दिए PAN से अलग PAN पर दर्ज है। कृपया दोनों नंबर जाँचिए।" |
| एरर | timeout या 502 | "हम verification सेवा तक नहीं पहुँच सके। कृपया कुछ मिनट बाद फिर कोशिश कीजिए।" |
आख़िरी पंक्ति भरोसे के लिए सबसे अहम है। timeout या upstream की एरर वेंडर के बारे में कुछ नहीं कहती। उसे कभी verification की विफलता की तरह मत दिखाइए।
GST पोर्टल जो दिखाता है और API नहीं
GST का सार्वजनिक पोर्टल taxpayer search में StampMitra के जवाब से ज़्यादा दिखा सकता है। रजिस्ट्रेशन के हिसाब से पोर्टल जहाँ हो वहाँ रद्द होने की तारीख़ और रिटर्न भरने की स्थिति दिखा सकता है, जो API के जवाब में नहीं होते। पंजीकरण की तारीख़, कारोबार की संरचना, करदाता का प्रकार और अधिकार-क्षेत्र जवाब में हैं (dateOfRegistration, constitutionOfBusiness, taxpayerType, centerJurisdiction, stateJurisdiction)।
यह दो तरह से मायने रखता है। पहला, अपनी compliance टीम से ऐसे फ़ील्ड का वादा मत कीजिए जो जवाब में नहीं है। आपकी नीति को रद्द होने की तारीख़ या रिटर्न की स्थिति चाहिए तो पहले ही कह दीजिए और तय कीजिए कि कोई इंसान पोर्टल पर देखेगा या वेंडर से प्रमाणपत्र माँगा जाएगा। दूसरा, जब कोई समीक्षक पोर्टल खोलकर आपके टूल से भरा-पूरा रिकॉर्ड देखे, तो वह विसंगति नहीं, दायरे का फ़र्क है। एक ही फ़ील्ड API और पोर्टल में अलग क्यों दिख सकता है, यह अलग सवाल API और सरकारी पोर्टल के नतीजों में फ़र्क में है।
नामों की तुलना, अच्छे वेंडर ठुकराए बिना
वैकल्पिक businessName फ़ील्ड प्लेटफ़ॉर्म से तुलना माँगता है, पर आपको अपनी तरफ़ से भी तुलना करनी चाहिए, क्योंकि नीति आपके हाथ में रहनी चाहिए। गड्ढे पहले से अनुमान लायक हैं।
legalNameसे तुलना कीजिए। प्रोपराइटर के लिए PAN का नाम औरlegalNameमिलते हैं, जबकिtradeNameदुकान का ब्रांड है। trade name से तुलना अच्छे वेंडरों पर फ़ेल होती है।- तुलना से पहले सामान्य रूप में लाइए: अक्षरों का केस, विराम चिह्न, "Private Limited" बनाम "Pvt Ltd", "and" बनाम "&", दोहराई खाली जगहें। ऊपर का
normfunction विचार दिखाता है; उसमें अपनी समानताओं की सूची जोड़िए। - तय कीजिए कि अलग नाम विफलता है या समीक्षा। जिन वेंडरों का नाम बदलना जाना-पहचाना है (अधिग्रहण, पार्टनरशिप से कंपनी बनना), उनके लिए समीक्षा ज़्यादा नरम और सुरक्षित है।
- पहचानों पर अनुमानित (fuzzy) तुलना मत कीजिए। नाम अनुमानित हो सकते हैं। PAN और GSTIN ठीक-ठीक मिलने चाहिए।
क्या GSTIN उसी PAN का है जिस पर आपको भरोसा है
किसी भी GSTIN के अक्षर 3 से 12 एक PAN होते हैं। अगर आप संस्था का PAN पहले verify कर चुके हैं, तो दोनों को बिना किसी अतिरिक्त call के मिलाइए। यह अकेली तुलना किसी और के असली और चालू GSTIN को अपना बताने के आम दुरुपयोग को पकड़ लेती है। ऊपर का decide_gstin function इसे embedded_pan से करता है।
क्रम इससे निकलता है। पहले PAN verify कीजिए, क्योंकि वही आधार है, फिर GSTIN verify कीजिए और उसमें बैठे PAN को उससे मिलाइए। क्रम उलटने पर आप ऐसे वेंडर पर GSTIN की call ख़र्च कर सकते हैं जिसका PAN पहले ही फ़ेल हो जाता। पहले आधे के लिए PAN को कैसे verify करें और नाम कैसे मिलाएँ देखिए।
PAN से GSTIN खोजना
कभी आपके पास PAN होता है और GSTIN चाहिए, जैसे वेंडर कहता है "हम GST में पंजीकृत हैं" पर यह नहीं बताता कि किस राज्य में। POST /v1/verify/pan-to-gstin एक pan लेता है और जुड़े रजिस्ट्रेशन लौटाता है। इसके लिए scope verification.pan_to_gstin.read चाहिए और यह pan.to_gstin के रूप में गिना जाता है।
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/pan-to-gstin" \
-H "Authorization: Bearer $STAMPMITRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"pan":"ABCDE1234F"}'{
"referenceId": "SMV-20260927-1L67Z5",
"found": true,
"gstins": [
{ "gstin": "07AAAAA1111A1Z1", "state": "Delhi", "status": "Active" }
]
}| फ़ील्ड | मतलब |
|---|---|
found | PAN से कोई GSTIN जुड़ा है या नहीं |
gstins[].gstin | एक रजिस्ट्रेशन नंबर |
gstins[].state | रजिस्ट्रेशन का राज्य |
gstins[].status | इस सूची में लौटी रजिस्ट्रेशन की स्थिति |
lookup का इस्तेमाल इनवॉइस की supply की जगह के लिए सही GSTIN चुनने में कीजिए, यह पक्का करने में कि वेंडर का बताया नंबर सूची में है, या यह जानने में कि PAN वाले वेंडर का कोई रजिस्ट्रेशन है ही नहीं (found: false)। फिर अगर आपको उसका legal name, trade name और principal place of business चाहिए, तो चुने हुए GSTIN को मुख्य endpoint से verify कीजिए। सूची राज्य और status दिखाती है, नाम नहीं।
कई GSTIN हों तो कौन-सा लें
राष्ट्रीय वेंडर के हर राज्य में एक GSTIN होता है, इसलिए PAN lookup की सूची लंबी हो सकती है। उद्देश्य के हिसाब से चुनिए।
| उद्देश्य | कौन-सा GSTIN | क्यों |
|---|---|---|
| इनवॉइस का भुगतान | जो इनवॉइस पर छपा है | इनवॉइस वही दस्तावेज़ है जिस पर आप दावा करेंगे |
| जाँचना कि वेंडर है | कोई भी सक्रिय, साथ में बैठा PAN | पहचान PAN है; GSTIN एक रजिस्ट्रेशन है |
| supply की जगह तय करना | जिसका राज्य supply से मिले | राज्य कोड शुरू के दो अंक हैं |
| निगरानी | सब | एक रद्द रजिस्ट्रेशन सिर्फ़ एक राज्य को छू सकता है |
कभी मत मानिए कि सूची का पहला GSTIN मुख्यालय है। सूची रजिस्ट्रेशनों का समूह है, पदानुक्रम नहीं।
बाद में दोबारा जाँचना
ऑनबोर्डिंग के समय चालू GSTIN बाद में निलंबित या रद्द हो सकता है। दोबारा जाँच तय कीजिए, इस हिसाब से कि आप रजिस्ट्रेशन पर कितना निर्भर हैं।
| वेंडर का स्तर | दोबारा जाँच का उदाहरण नियम |
|---|---|
| ज़्यादा ख़र्च या नियंत्रित जोखिम | सीमा से ऊपर के हर भुगतान चक्र से पहले, और हर महीने |
| नियमित | तिमाही |
| कभी-कभार | बारह महीने बाद अगले लेन-देन पर |
वेंडर तालिका पर चलकर बदलावों पर flag लगाने वाला एक छोटा Python job:
import time
from your_app import vendors, save_check, raise_flag
def recheck_all(batch_size=30, pause_seconds=60):
queue = list(vendors.due_for_recheck())
for i in range(0, len(queue), batch_size):
for v in queue[i:i + batch_size]:
try:
res = verify_gstin(v.gstin)
except GstinError as e:
save_check(v.id, outcome="error", detail=e.detail)
continue
changed = res["registrationStatus"] != v.last_status
save_check(v.id, outcome="ok", reference_id=res["referenceId"], status=res["registrationStatus"])
if changed:
raise_flag(v.id, f"status {v.last_status!r} -> {res['registrationStatus']!r}")
time.sleep(pause_seconds) # हर endpoint की rate limit के अंदर रहने के लिएproduction में हर दोबारा जाँच बिल होने वाली call है, जिसका अपना referenceId है। आदत से नहीं, जोखिम से दोबारा जाँचिए।
दोबारा जाँच में नतीजा बदला मिले तो सीधा फ़ैसला पलटने के बजाय पूछिए कि बदला क्या है। मान लीजिए एक वेंडर ऑनबोर्डिंग पर Active था और तिमाही की जाँच में Cancelled निकला। पहले देखिए कि उसके कितने भुगतान या इनवॉइस अभी खुले हैं, फिर वेंडर से रजिस्ट्रेशन की स्थिति पर स्पष्टीकरण माँगिए, और नई GST इनवॉइसिंग को तब तक रोकिए। पुराने, स्थिति बदलने से पहले के लेन-देन को छेड़ने या न छेड़ने का फ़ैसला आपके कर सलाहकार का है, कोड का नहीं। कोड सिर्फ़ यह करे कि बदलाव की तारीख़, पुरानी और नई स्थिति और दोनों referenceId दर्ज करे, ताकि कोई भी बाद में पूरी कहानी पढ़ सके।
उलटा मामला भी होता है: जो वेंडर Cancelled था, वह कुछ समय बाद फिर Active दिख सकता है। इस पर अपने-आप भरोसा बहाल मत कीजिए। उसे उसी रास्ते से गुज़ारिए जैसे नया आवेदन गुज़रता है, यानी PAN का मेल, नाम और स्थिति, और बहाली की बात वेंडर से लिखित में लीजिए। इससे आपका रिकॉर्ड भी साफ़ रहता है कि किस तारीख़ से किस आधार पर वेंडर फिर चालू माना गया।
बड़ी मात्रा में जाँच, rate limit तोड़े बिना
दर्ज 429 उदाहरण पढ़ता है "Rate limit exceeded: 60 requests per 60 seconds for this endpoint." आपकी असली सीमा प्लान पर निर्भर है (sandbox प्लान, pay-as-you-go और ऊपर के प्लान अलग हैं), इसलिए उदाहरण को कोड में बैठाने की जगह अपनी सीमा dashboard से पढ़िए। उसी के हिसाब से डिज़ाइन कीजिए।
import asyncio, random
import httpx
BASE = "https://api-b2b.stampmitra.in/v1/verify/gstin"
async def verify_many(gstins, api_key, per_minute=50, concurrency=4):
results = {}
gap = 60 / per_minute
sem = asyncio.Semaphore(concurrency)
async with httpx.AsyncClient(timeout=10) as client:
async def one(g):
async with sem:
for attempt in range(3):
r = await client.post(BASE, json={"gstin": g},
headers={"Authorization": f"Bearer {api_key}"})
if r.status_code == 429 and attempt < 2:
await asyncio.sleep(2 * 2 ** attempt + random.random() * 0.5)
continue
results[g] = {"status": r.status_code, "body": r.json() if r.content else {}}
break
await asyncio.sleep(gap * concurrency)
await asyncio.gather(*(one(g) for g in gstins))
return resultsगति वाली पंक्ति सबसे अहम है: हर worker इतना सोता है कि सबकी मिली-जुली दर per_minute के नीचे रहे। सिर्फ़ 429 पर (और चाहें तो 502 पर) बढ़ते, थोड़े बेतरतीब इंतज़ार और कोशिशों की सख़्त सीमा के साथ retry कीजिए। 400, 401, 402 या 403 पर कभी retry मत कीजिए। क्यों, यह एरर, retry और idempotency में है, इस बात समेत कि verification endpoint कोई idempotency key दर्ज नहीं करते।
cache और ताज़गी
GSTIN के जवाब cache करके calls बचाने का मन होता है। एक ही ऑनबोर्डिंग सत्र में उसी GSTIN के लिए छोटा cache ठीक है, क्योंकि यूज़र फ़ॉर्म दोबारा जमा कर सकता है। लंबा cache जोखिम है, क्योंकि जाँच का मक़सद ही मौजूदा हालत देखना है। cache करें तो नतीजे के साथ referenceId और समय रखिए, ऊपर के दोबारा-जाँच के नियमों से उसे ख़त्म कीजिए, और अपनी नीति से पुराने cached Active को कभी भुगतान के फ़ैसले में मत परोसिए। यह भी याद रखिए कि जवाब डेटा स्रोत की आख़िरी ताज़गी को दिखाता है, ज़रूरी नहीं कि आपकी call के क्षण को; देखिए API और सरकारी पोर्टल के नतीजों में फ़र्क।
इंटीग्रेशन को परखना
दर्ज sandbox GSTIN दोनों नतीजे माँगने पर देते हैं: 09SNDBX0000A1Z5 valid और Active लौटाता है, और 09SNDBX9999F1Z5 not valid और Cancelled। बाक़ी हर वैल्यू का नतीजा स्थिर पर मनमाना है। sandbox कभी किसी असली रजिस्ट्रेशन को verify नहीं करता, इसलिए वह आपके वेंडरों को नहीं, आपके कोड को परखता है। परखने की एक छोटी सूची:
| मामला | इनपुट | क्या assert करें |
|---|---|---|
| सीधा रास्ता | 09SNDBX0000A1Z5 | valid सही, registrationStatus Active, referenceId SMV-\d{8}- से मेल खाए |
| नकारात्मक नतीजा | 09SNDBX9999F1Z5 | HTTP 200, valid ग़लत, आपके एरर वाले रास्ते से कोई exception नहीं |
| format की ग़लती | 12345 | ऑफ़लाइन ठुकराया जाए; भेजा जाए तो BAD_REQUEST के साथ 400 |
| ग़लत key | मनगढ़ंत key | 401 UNAUTHORIZED |
| scope न हो | GSTIN scope के बिना key | 403 FORBIDDEN |
| अनजानी स्थिति | registrationStatus: "Weird" वाला fixture | STATUS_WEIRD कारण के साथ REVIEW |
| PAN बेमेल | जिसमें बैठा PAN अलग हो ऐसा fixture | PAN_MISMATCH के साथ FAIL |
sandbox क्या बता सकता है और क्या नहीं, और असली go-live के चरण, sandbox बनाम production: क्या टेस्ट हो सकता है में हैं।
एक और परीक्षण-मामला जो अक्सर छूट जाता है: GSTIN ठीक है, पर ऊपर की तरफ़ की सेवा धीमी या अनुपलब्ध है। अपने fixture में 502 का जवाब रखिए और देखिए कि आपका कोड वेंडर को "जाँच बाक़ी" की स्थिति में छोड़ता है, मंज़ूर या अस्वीकार में नहीं। यही वह जगह है जहाँ कमज़ोर integration चुपचाप अधूरी जाँच को पास मान लेते हैं, और बाद में किसी को पता नहीं चलता कि उस वेंडर की जाँच कभी पूरी हुई ही नहीं थी।
लॉगिंग और निजता
कंपनी का GSTIN कारोबारी जानकारी है, पर प्रोपराइटर के लिए legal name एक व्यक्ति का नाम है और principal place of business घर का पता हो सकता है। referenceId, फ़ैसला, status और समय लॉग कीजिए। पूरे नंबर की ज़रूरत न हो तो ऐप्लिकेशन logs में GSTIN को पहले दो और आख़िरी चार अक्षरों तक मास्क कीजिए। डिफ़ॉल्ट रूप से पूरे response बॉडी लॉग मत कीजिए। क्या रखना है और कितने समय, यह verification कॉल से क्या लॉग करें में सूचीबद्ध है।
हाथ से समीक्षा का चरण
इस तरह के हर integration में समीक्षा की कतार बन ही जाती है, इसलिए उसे जान-बूझकर डिज़ाइन कीजिए, उसे इनबॉक्स मत बनने दीजिए। GSTIN के मामले पर काम करने वाले समीक्षक को एक स्क्रीन चाहिए जिसमें हों: वेंडर और उसका दावा (नाम, PAN, GSTIN, राज्य, पता); verification का नतीजा उसके referenceId और समय के साथ; वे कारण-कोड जिनसे केस कतार में आया; तुलना के लिए बगल में PAN verification का नतीजा; और वेंडर के अपलोड किए दस्तावेज़, जैसे रजिस्ट्रेशन प्रमाणपत्र।
समीक्षक के फ़ैसले एक छोटी, बंद सूची हों: मंज़ूर, अस्वीकार, दस्तावेज़ माँगें, सुधरा नंबर माँगें, ऊपर भेजें। हर फ़ैसला दर्ज करे कि किसने, कब और क्यों लिया, एक पंक्ति के खुले पाठ में। सूची बंद इसलिए है कि आप बाद में रिपोर्ट बना सकें: कितने केस PAN बेमेल पर अस्वीकार हुए, कितने दस्तावेज़ मिलने पर मंज़ूर हुए, और हर एक में कितना समय लगा।
समीक्षकों को जाँच दोबारा चलाने का तरीक़ा दीजिए। जो वेंडर कहे "हमने पिछले हफ़्ते रजिस्ट्रेशन बहाल करवा लिया" उसे दोबारा verify कीजिए, उससे बहस मत कीजिए। दोबारा चलाना नया referenceId वाली नई बिल होने वाली call है, जो वेंडर के रिकॉर्ड पर पहले के नतीजे की जगह लेती है और मूल को ऑडिट इतिहास में छोड़ देती है।
आख़िर में कतार की सेवा-अवधि तय कीजिए। जो वेंडर नाम के फ़र्क पर किसी इंसान के देखने का हफ़्ते भर इंतज़ार करे, वह कहीं और चला जाएगा। रोज़ का एक मालिक और साफ़ escalation रास्ता उन वेंडरों से सस्ता पड़ता है जिन्हें वह बचाता है।
चालू होने के बाद क्या देखें
verification integration चुपचाप बिगड़ता है। वह शायद ही कभी crash होता है। वह नतीजों का अलग मिश्रण लौटाने लगता है, या wallet ख़त्म हो जाता है, या key रद्द हो जाती है, और ऑनबोर्डिंग अटकने तक किसी को पता नहीं चलता। कुछ मीट्रिक इन विफलताओं को दिखाने लायक़ बनाते हैं।
| मीट्रिक | क्यों मायने रखती है | समझदार अलर्ट |
|---|---|---|
| नतीजे के हिसाब से प्रति घंटा calls (पास, समीक्षा, विफल, एरर) | मिश्रण का बदलना डेटा, नीति या integration के बदलाव का पहला संकेत है | समीक्षा या एरर का हिस्सा अपनी आम पट्टी से बहुत बाहर जाए |
| status और code के हिसाब से एरर की गिनती | 401 और 403 (key की दिक़्क़तें), 402 (wallet), 429 (दर), 5xx (upstream) को अलग करती है | कोई भी 401, 403 या 402; लगातार 429 या 502 |
| call की देरी, माध्यिका और धीमी पूँछ | धीमा upstream एरर बनने से पहले यहाँ दिखता है | पूँछ की देरी आपके timeout से मार्जिन घटाकर ऊपर जाए |
| wallet का बैलेंस और खपत की दर | 402 ऑनबोर्डिंग रोक देता है | बैलेंस उतने दिनों की calls से नीचे जाए जितने में आप सहज हैं |
| समीक्षा कतार की उम्र | बढ़ती कतार का मतलब खोए वेंडर | सबसे पुराना केस आपकी सेवा-अवधि के पार |
| उठे हुए दोबारा-जाँच flag | दिखाता है कि रजिस्ट्रेशन आपके नीचे कितनी बार बदलते हैं | अचानक उछाल, जो डेटा बदलाव का संकेत हो सकता है |
दो आदतें इन मीट्रिकों को भरोसेमंद बनाती हैं। नतीजे अपने फ़ैसले के कोड से गिनिए, सिर्फ़ HTTP status से नहीं, क्योंकि valid: false 200 होता है फिर भी ध्यान देने लायक़ घटना है। और हर एरर पर requestId लॉग कीजिए, ताकि कुछ गड़बड़ दिखे तो आप पैटर्न बताने की जगह support को ख़ास requests दे सकें।
इस integration के लिए तैयारी की checklist
production ट्रैफ़िक को GSTIN जाँच पर मोड़ने से पहले हर पंक्ति की पुष्टि कीजिए।
- key secret manager में है, production में
sk_live_से शुरू होती है और उसमें सिर्फ़ वही scopes हैं जो सेवा को चाहिए (verification.gstin.read, और lookup इस्तेमाल करें तोverification.pan_to_gstin.read)। - इनपुट से खाली जगहें हटती हैं और अक्षर बड़े होते हैं, और चेक कैरेक्टर वाली ऑफ़लाइन जाँच सिर्फ़ live key पर चालू है।
- हर call पर timeout है, और timeout तथा 502 "फिर कोशिश कीजिए" की तरह दिखते हैं, verification की विफलता की तरह कभी नहीं।
- 400, 401, 402 और 403 पर retry नहीं होता। 429 पर बेतरतीबी वाले backoff और सीमा के साथ retry होता है।
- अनजानी स्थितियाँ समीक्षा में जाती हैं और कच्ची लॉग होती हैं।
- वेंडर की मंज़ूरी से पहले GSTIN में बैठे PAN को verify किए PAN से मिलाया जाता है।
- नाम
legalNameसे, सामान्य रूप में लाकर, मिलाए जाते हैं। - हर call के लिए
referenceId, फ़ैसला, कारण और समय सहेजे जाते हैं, और डिफ़ॉल्ट रूप से और कुछ संवेदनशील लॉग नहीं होता। - दोबारा-जाँच की समय-सारणी है और उससे उठे flag का एक मालिक है।
- wallet पर आपकी अपनी निगरानी में कम-बैलेंस का अलर्ट है, ताकि 402 ऑनबोर्डिंग को चुपचाप न रोके।
- sandbox टेस्ट की चलाई ऊपर की परख-तालिका की हर पंक्ति को कवर करती है और live key के साथ चलने से मना करती है।
- आपकी अपनी कंपनी के GSTIN के साथ production smoke test चल चुका है और उसका नतीजा देखा गया है।
आम ग़लतियाँ
valid: trueको "मंज़ूर" समझ लेना। status, PAN और नाम का मेल अभी बाक़ी है।- नामों की तुलना
tradeNameसे करना। - status की सूची कोड में बैठाकर सूची से बाहर की हर चीज़ को चुपचाप ठुकरा देना। अनजाना मतलब समीक्षा।
- sandbox में चेक कैरेक्टर का टेस्ट चलाना।
- वेंडर के बताए पहले GSTIN को ही verify करके रुक जाना।
- API को ब्राउज़र से call करना, जिससे key खुल जाती है।
- 400 या 402 पर लूप में retry करना।
Activeनतीजे को अपनी नीति की मंज़ूर अवधि से कहीं ज़्यादा देर cache रखना।referenceIdको अनदेखा करना, जिससे आपके फ़ैसले और call के बीच कोई कड़ी नहीं बचती।
आगे क्या करें
quickstart से sandbox key लीजिए, 09SNDBX0000A1Z5 के साथ ऊपर की cURL call चलाइए, फिर GSTIN endpoint reference और PAN to GSTIN reference पढ़िए। इन जाँचों जिस पूरी प्रक्रिया का हिस्सा हैं, उसके लिए वेंडर ऑनबोर्डिंग फ़्लो पढ़िए। endpoint का प्रोडक्ट ब्योरा और कीमतें GSTIN प्रोडक्ट पेज और pricing पेज पर हैं। pay-as-you-go पर GSTIN की एक call ₹5 है, और प्लान में कम। सवाल support को भेजिए।
API reference एक नज़र में
GSTIN
POST /v1/verify/gstinRequest parameters
| Field | Type | Description |
|---|---|---|
Authorizationrequired | header | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
gstinrequired | string | 15-character GSTIN, format 07AAAAA1111A1Z1. |
businessName | string | Business (legal or trade) name to cross-check against the registration. |
POST /v1/verify/gstin{
"referenceId": "SMV-20260927-9K21P4",
"verificationId": "VRF-4M8Q2T7XB9KD",
"gstin": "29AAICP2912R1ZR",
"GSTIN": "29AAICP2912R1ZR",
"valid": true,
"legalNameOfBusiness": "UJJIVAN SMALL FINANCE BANK LIMITED",
"tradeNameOfBusiness": "UJJIVAN SMALL FINANCE BANK",
"centerJurisdiction": "I-A RANGE",
"stateJurisdiction": "GUWAHATI - A - 1",
"dateOfRegistration": "2017-09-30",
"constitutionOfBusiness": "Public Limited Company",
"taxpayerType": "Regular",
"gstinStatus": "Active",
"lastUpdateDate": "2022-03-01",
"natureOfBusinessActivities": [
"Retail Business",
"Supplier of Services",
"Recipient of Goods or Services",
"Office / Sale Office",
"Others"
],
"principalPlaceAddress": "First Floor 3512-DISPUR Prithivi Mansion opp. KFC building G.S. Road, Lachit Nagar Assam 781007",
"principalPlaceSplitAddress": {
"buildingName": "Prithivi Mansion",
"street": "G.S. Road",
"location": "Lachit Nagar",
"buildingNumber": "3512-DISPUR",
"district": "Guwahati",
"state": "Assam",
"city": "Dispur",
"flatNumber": "First Floor",
"latitude": "26.1445",
"longitude": "91.7362",
"pincode": "781007"
},
"additionalAddresses": [
{
"address": "Mirza Santipur NH-37 Dist-Kamrup Rural PS-Palashbari, PO Mirza Kamrup Assam 781125",
"splitAddress": {
"buildingName": "",
"street": "NH-37",
"location": "Santipur, Mirza",
"buildingNumber": "",
"district": "Kamrup Rural",
"state": "Assam",
"city": "Palashbari",
"flatNumber": "",
"latitude": "26.0926",
"longitude": "91.5069",
"pincode": "781125"
}
},
{
"address": "N.A.C.C.I. Foundation 3559-Tezpur CHAMBER BHAWAN Binjraj Road, P. o. and P.S. - Tezpur, Dist. Binjraj Road, P. o. and P.S. - Tezpur, Dist. Sonitpur Assam 784154",
"splitAddress": {
"buildingName": "CHAMBER BHAWAN",
"street": "Binjraj Road",
"location": "Tezpur",
"buildingNumber": "3559-Tezpur",
"district": "Sonitpur",
"state": "Assam",
"city": "Tezpur",
"flatNumber": "",
"latitude": "26.6338",
"longitude": "92.8006",
"pincode": "784154"
}
}
],
"message": "GSTIN Exists",
"legalName": "UJJIVAN SMALL FINANCE BANK LIMITED",
"tradeName": "UJJIVAN SMALL FINANCE BANK",
"registrationStatus": "Active",
"principalPlaceOfBusiness": "First Floor 3512-DISPUR Prithivi Mansion opp. KFC building G.S. Road, Lachit Nagar Assam 781007"
}POST /v1/verify/gstinGSTIN: ₹5 per successful call, pay-as-you-go (lower on Growth and Scale).
PAN to GSTIN
POST /v1/verify/pan-to-gstinRequest parameters
| Field | Type | Description |
|---|---|---|
Authorizationrequired | header | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
panrequired | string | PAN to resolve to associated GSTIN(s). |
POST /v1/verify/pan-to-gstin{
"referenceId": "SMV-20260927-1L67Z5",
"found": true,
"gstins": [
{
"gstin": "07AAAAA1111A1Z1",
"state": "Delhi",
"status": "Active"
}
]
}POST /v1/verify/pan-to-gstinPAN to GSTIN: ₹5 per successful call, pay-as-you-go (lower on Growth and Scale).
अक्सर पूछे जाने वाले सवाल
API से GSTIN कैसे verify करें?
/v1/verify/gstin पर POST भेजिए जिसमें gstin फ़ील्ड और वैकल्पिक businessName हो, और verification.gstin.read scope वाली Bearer key से प्रमाणीकरण। जवाब में valid, legalNameOfBusiness, tradeNameOfBusiness, gstinStatus, taxpayerType, constitutionOfBusiness, तारीख़ें, अधिकार-क्षेत्र, व्यावसायिक गतिविधियाँ, मुख्य और अतिरिक्त पते, message, और हमारी referenceId व verificationId आते हैं। पुराने नाम legalName, tradeName, registrationStatus और principalPlaceOfBusiness में वही मान आते हैं।
registrationStatus Active का क्या मतलब है?
इसका मतलब है कि स्रोत पर रजिस्ट्रेशन लागू है, जो ऑनबोर्डिंग के लिए पास होने की शर्त है। रद्द या निलंबित जैसी दूसरी स्थितियाँ स्रोत पर हैं और reference सब नहीं गिनाता, इसलिए Active के अलावा हर चीज़ को समीक्षा में भेजिए और कच्चा मान लॉग कीजिए।
valid false और ग़ैर-सक्रिय status में क्या फ़र्क है?
valid false का मतलब है कि lookup को उस नंबर का रजिस्ट्रेशन नहीं मिला, जैसे ऐसा टाइपो जो format validation पास कर गया। valid true के साथ ग़ैर-सक्रिय status का मतलब है कि रजिस्ट्रेशन है पर लागू नहीं। दोनों को अलग शाखाओं में, अलग यूज़र संदेशों के साथ सँभालिए।
क्या जवाब में रद्द होने की तारीख़ आती है?
नहीं। जवाब में status, करदाता का प्रकार, कारोबार की संरचना, पंजीकरण और आख़िरी अद्यतन की तारीख़ें और अधिकार-क्षेत्र हैं, पर रद्द होने की तारीख़ या रिटर्न का इतिहास नहीं। फ़ैसला इन पर टिके तो दूसरा स्रोत इस्तेमाल कीजिए या वेंडर से प्रमाणपत्र माँगिए।
वेंडर के नाम की तुलना किस नाम से करें?
legalName से, tradeName से नहीं। प्रोपराइटर के लिए PAN का नाम और legal name मिलते हैं जबकि trade name दुकान का ब्रांड है। तुलना से पहले अक्षरों का केस, विराम चिह्न और Private Limited तथा Pvt Ltd जैसे प्रत्यय एक कीजिए।
कैसे जाँचें कि GSTIN वेंडर के PAN का है?
GSTIN के अक्षर 3 से 12 एक PAN होते हैं। उन्हें अपने पहले से verify किए PAN से मिलाइए, बिना किसी अतिरिक्त call के। बेमेल का मतलब है कि रजिस्ट्रेशन किसी और करदाता का है और जाँच फ़ेल होनी चाहिए।
क्या sandbox में GSTIN का चेक कैरेक्टर टेस्ट चलाना चाहिए?
नहीं। docs का सैंपल GSTIN और दर्ज sandbox GSTIN का चेक कैरेक्टर सही नहीं है। वह ऑफ़लाइन जाँच सिर्फ़ तब चालू कीजिए जब key sk_live_ से शुरू हो, और बनावट तथा राज्य कोड की जाँचें हर जगह चालू रखिए।
क्या PAN से वेंडर के GSTIN खोजे जा सकते हैं?
हाँ। pan के साथ POST /v1/verify/pan-to-gstin, verification.pan_to_gstin.read scope के साथ, found और राज्य तथा status वाली gstins की सूची लौटाता है। फिर जिस GSTIN की ज़रूरत है उसे मुख्य endpoint से verify कीजिए ताकि नाम और principal place of business मिलें।
कई GSTIN verify करते समय rate limit कैसे सँभालें?
concurrency सीमित रखिए, requests अपने प्लान की सीमा के नीचे रखिए, और सिर्फ़ 429 और 502 पर बेतरतीब backoff और कोशिशों की सख़्त सीमा के साथ retry कीजिए। दर्ज उदाहरण-सीमा प्रति endpoint 60 सेकंड में 60 requests है, पर अपनी सीमा dashboard से पढ़िए।
GSTIN की दोबारा जाँच कितनी बार करें?
जोखिम के हिसाब से। ज़्यादा ख़र्च वाले वेंडर सीमा से ऊपर के भुगतान चक्र से पहले और हर महीने, नियमित वेंडर तिमाही, कभी-कभार वाले एक साल बाद अगले लेन-देन पर। ऑनबोर्डिंग के बाद रजिस्ट्रेशन निलंबित या रद्द हो सकता है, और हर दोबारा जाँच नई बिल होने वाली call है।
स्रोत
- GST पोर्टल, करदाता पंजीकरण और खोज की जानकारी: https://www.gst.gov.in (रजिस्ट्रेशन की मौजूदा स्थितियाँ और उनका मतलब वहीं देखिए, 2026)।
/v1/verify/gstinऔर/v1/verify/pan-to-gstinके लिए StampMitra API reference डेटा: फ़ील्ड, एरर, scopes और बिलिंग, जैसा इस रिपॉज़िटरी में 2026-10-29 को है।- StampMitra की sandbox टेस्ट वैल्यू, sandbox responder से ली गईं, 2026-10-29।
- इस रिपॉज़िटरी में StampMitra का ऑफ़लाइन GSTIN validation तर्क (format, राज्य कोड, चेक कैरेक्टर), जो सर्वर की जाँच से मेल खाता है, 2026-10-29।