The KYC PAN Status API queries the CVL KRA public portal to retrieve KYC registration status for a given PAN number across all five SEBI-registered KRAs (CVL, NDML, CAMS, Karvy, KFin).What you get:
A normalized kyc_status enum — no raw portal strings to parse
A single kyc_compliant boolean for quick onboarding gate decisions
Per-KRA breakdown with dates, mode, and remarks
What you need:
PAN number (10 characters)
This endpoint queries the CVL KRA portal and may take up to 60 seconds. Set your client timeout to at least 60 seconds.
When kyc_status is on_hold, check remarks on the active KRA object for the reason:
data = response.json()if data["kyc_status"] == "on_hold": active = data["active_kra"] remarks = data["kras"][active]["remarks"] # e.g. "APPLICANT PHOTO MISMATCH IN THE APPLICATION" print(f"KYC on hold: {remarks}")
remarks may contain multiple comma-separated reasons (e.g. "APPLICANT PHOTO MISMATCH IN THE APPLICATION,FATCA NOT APPLICABLE"). FATCA NOT APPLICABLE is informational and not an error.
For exact-matched statuses (the common case), raw_status is null.raw_status is non-null when the portal returned a string the API hadn’t seen before and used a fuzzy match instead of an exact one. If you see a non-null raw_status in production, please report it so we can add it to the exact map.
import requestsAPI_KEY = "YOUR_API_KEY"def check_kyc_status(pan: str) -> dict: """ Check KYC status for a PAN number. Returns the normalized response or raises on error. """ response = requests.post( "https://api.casparser.in/v1/kyc/pan/status", headers={"x-api-key": API_KEY}, json={"pan_no": pan}, timeout=60 # CVL KRA portal queries can take up to 60s ) response.raise_for_status() return response.json()# Basic onboarding gatedata = check_kyc_status("ABCDE1234F")if data["kyc_compliant"]: # Allow onboarding print(f"KYC verified ({data['kyc_status']}) via {data['active_kra'].upper()} KRA") print(f"Registered on: {data['registered_on']}")else: status = data["kyc_status"] if status == "on_hold": active = data["active_kra"] remarks = data["kras"][active]["remarks"] print(f"KYC on hold — reason: {remarks}") elif status == "not_available": print("No KYC record found. Investor needs to complete KYC.") elif status == "rejected": print("KYC rejected. Investor must submit fresh KYC.") elif status == "under_process": print("KYC is being processed. Check again later.") elif status == "legacy": print("Old KYC record. Re-KYC recommended.") else: print(f"KYC status: {status}")
try: data = check_kyc_status("ABCDE1234F")except requests.exceptions.Timeout: print("Request timed out — CVL KRA portal is slow. Retry.")except requests.exceptions.HTTPError as e: if e.response.status_code in (503, 504): print("KYC service unavailable — retry in a few seconds") else: raise