Aadhaar Secure QR
1 endpoint · Core API
What is it?
The Aadhaar Secure QR API parses the UIDAI-issued QR code printed on every Aadhaar letter / e-Aadhaar PDF and returns the demographic fields (name, DOB, gender, address, masked mobile, masked email, photo) as structured JSON. The QR carries a UIDAI RSA-2048 digital signature — so we can also prove the data was actually issued by UIDAI and has not been tampered with.
No Aadhaar number is ever exposed — the QR only contains the last 4 digits.
What can I do with this product?
- Reception / help-desk demographic capture — staff scans the printed Aadhaar, the form auto-fills.
- Address auto-fill on signup / onboarding forms when the user voluntarily uploads their own Aadhaar.
- Tamper detection — verify a scanned or photographed Aadhaar wasn't edited (signature check).
- Bulk back-office workflows — re-process pre-uploaded Aadhaar copies offline, no consent UI needed.
- Offline / air-gapped verification — pure parsing, no network call to UIDAI at request time.
How is this different from OVSE and DigiLocker?
All three return demographics, but they solve different problems:
| Aadhaar Secure QR | Aadhaar OVSE | DigiLocker | |
|---|---|---|---|
| Source data | The QR printed on the Aadhaar letter | UIDAI Aadhaar App (live) | UIDAI central DB (live) |
| End-user friction | Zero — just upload an image | Aadhaar App scan + consent | DigiLocker login + consent |
| Photo quality | Thumbnail (~1 KB compressed) | Higher resolution | Original resolution |
| Proves UIDAI-issued | ✅ RSA-2048 signature | ✅ SD-JWT | ✅ XML signature |
| Proves live consent | ❌ | ✅ | ✅ |
| Proves holder is present | ❌ | ✅ Face auth | ✅ Login + OTP |
| Replay risk (someone else's QR) | ⚠️ Yes | ❌ | ❌ |
| Fits regulated KYC (RBI / SEBI / IRDAI) | ❌ | ✅ | ✅ |
Use Secure QR when you need fast, low-friction extraction of demographics with tamper-detection — and you accept that the data is whatever was on the printed Aadhaar at issuance time.
Use OVSE or DigiLocker when you need to prove the holder is currently consenting and physically present — account opening, loan origination, anything regulated.
Request modes
You can submit the QR in either of two ways:
- Image upload — Base64-encoded PNG/JPEG of the Aadhaar QR. We decode the QR for you.
- Decimal payload — the raw decimal string that some QR scanners return directly. Skips image decode (faster).
Photo quality
The photo embedded in the QR is a heavily compressed JPEG2000 thumbnail (~700-1000 bytes of source data) decoded server-side to PNG. This is by UIDAI's design — the entire QR has to fit on a printed Aadhaar letter. The photo is suitable for visual help-desk identification, NOT face-recognition or biometric matching. For a high-resolution photo, use the Aadhaar OVSE or DigiLocker API.
Benefits
- Zero end-user friction — no app install, no OTP, no consent screen
- Works offline — no live UIDAI dependency at request time
- Tamper detection — optional RSA signature verification catches edited QRs
- No Aadhaar number exposed — only last 4 digits are recoverable
- Single API call — one POST, one JSON response with everything
- Drop-in for form auto-fill — perfect for reception desks, onboarding flows, and bulk back-office processing
Note on signature verification
When you pass verify_signature: true, we attempt to verify the UIDAI RSA-2048 signature using every UIDAI public certificate we have on file. UIDAI periodically rotates their signing certificate (2017 → 2020 → 2023 → …) and does not always publish the new public key at predictable URLs. If the QR was signed by a cert we don't yet have, verified returns false — not because the QR is forged, but because we cannot prove authenticity without UIDAI's current public key. Treat verified: true as a strong positive signal; treat verified: false as inconclusive (could be tampered, could just be a cert-rotation gap). The demographic fields and photo are still extracted in either case.
Parse a UIDAI Aadhaar Secure QR.
Returns demographic fields (name, DOB, gender, address), masked mobile, and a server-decoded
PNG photo. Optionally verifies the UIDAI RSA-2048 signature (set verify_signature to true).
Request parameters:data (base64 QR image) or payload (decimal string) is required;
send exactly one. include_photo (default true) and verify_signature (default false) are optional.
data_content_type and reference_id are accepted but not used.
No Aadhaar number is exposed — the QR only carries the last 4 digits.
Photo is a UIDAI-compressed thumbnail suitable for visual identification, NOT biometric matching.
For higher-resolution photos use the Aadhaar OVSE or DigiLocker APIs.
Headers
- X-API-KEYstringrequiredYour secret API key for the environment you are calling (Stage and Live use different keys).
- X-API-APP-IDstringrequiredThe App ID issued together with the key.
- Content-Typestringrequiredapplication/json
Body parameters
application/json- consentstringrequiredRequired. The end user's consent to this verification. Send `Y`.minLength 1default Y
- consent_textstringrequiredRequired. The consent statement shown to the end user. Send the default text from the sample.minLength 1default I hear by declare my consent agreeme…
- request_idstringoptionalOptional. Your own id to correlate this call in your logs. A unique id is generated if you leave it out.nullable
- datastringconditionalConditional: required when payload is not sent. Base64-encoded PNG or JPEG image of the Aadhaar Secure QR. Send either data or payload, not both.nullable
- payloadstringconditionalConditional: required when data is not sent. Raw decimal payload string scanned out of the QR by a QR reader. Send either data or payload, not both. Skips image decoding, so it is faster.nullable
- data_content_typestringoptionalOptional. Image format of data: PNG or JPEG. Accepted but not used; the format is detected from the image.nullabledefault PNG
- include_photobooleanoptionalOptional. Defaults to true, which returns the photo decoded to PNG as base64. Set false to skip photo decoding and return null in `photo` for a faster, smaller response.default true
- verify_signaturebooleanoptionalOptional. Defaults to false. Set true to verify the UIDAI RSA-2048 signature on the QR payload.default false
- reference_idstringoptionalOptional. Your own reference for this request. Accepted but not used or returned; the reference_id in the response comes from the QR itself.nullable
Sample request body
Responses
200OK
- successbooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 200
- messagestringoptionalNo description.nullabledefault XXXXX
- dataobjectoptionalResponse model for the Aadhaar Secure QR parser.
5 fields
- qr_formatstringoptionalAlways "secure_qr" in v1 — placeholder for forward compatibility.nullable
- secure_qr_versionstringoptionalUIDAI Secure QR version (e.g. "V5"). Null when the QR omits the version field (older issuances).nullable
- fieldsobjectoptionalDemographic fields parsed from the QR text block.
20 fields
- namestringoptionalNo description.nullable
- dobstringoptionalNo description.nullable
- genderstringoptionalNo description.nullable
- care_ofstringoptionalNo description.nullable
- housestringoptionalNo description.nullable
- streetstringoptionalNo description.nullable
- landmarkstringoptionalNo description.nullable
- locationstringoptionalNo description.nullable
- vtcstringoptionalNo description.nullable
- sub_districtstringoptionalNo description.nullable
- districtstringoptionalNo description.nullable
- statestringoptionalNo description.nullable
- post_officestringoptionalNo description.nullable
- pincodestringoptionalNo description.nullable
- masked_mobilestringoptionalNo description.nullable
- masked_emailstringoptionalNo description.nullable
- aadhaar_last4stringoptionalNo description.nullable
- generated_atstringoptionalNo description.nullable
- email_mobile_indicatorstringoptionalNo description.nullable
- reference_idstringoptionalNo description.nullable
- photoobjectoptionalServer-decoded photo (PNG, base64).
4 fields
- formatstringoptionalNo description.nullable
- mime_typestringoptionalNo description.nullable
- size_bytesinteger (int32)optionalNo description.
- base64stringoptionalPNG bytes as base64 — usable directly as `data:image/png;base64,…`.nullable
- signatureobjectoptionalUIDAI RSA-2048 signature on the QR payload.
3 fields
- presentbooleanoptionalNo description.
- verifiedbooleanoptionalNull when `verify_signature` was false. True/false when verification ran.nullable
- base64stringoptionalRaw 256-byte signature as base64. Empty when the QR carries no signature block.nullable
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- isBillablebooleanoptionalWhether this request was charged: true if it was, false if not. Errors always show false. Flows that finish later (ITR Fetch, SHCIL eStamp, DigiLocker, eSign) show false here, because the charge is made when the result is ready. eSign charges each signer when they complete signing. DigiLocker deducts the credit when the link is created and refunds it automatically if the link expires before the user completes it.
400Bad Request
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 400
401Unauthorized
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 401
500Internal Server Error
- dataobjectoptionalNo description.
- messagesarray<string>optionalNo description.nullable
- request_idstringoptionalNo description.nullable
- successbooleanoptionalNo description.default false
- messagestringoptionalNo description.nullabledefault XXXXX
- isBillablebooleanoptionalNo description.
- statusCodeinteger (int32)optionalNo description.default 500