Send a JPG, PNG or PDF of a PAN card and get its fields back as JSON — the PAN itself, the name as printed, the father's name and the date of birth. Built for KYC and document pipelines at banks, NBFCs, housing finance companies and fintechs.
Talk to our technical team → — for integration questions, accuracy benchmarks on your own documents, or a volume estimate.
Synchronous and stateless. Same request shape as every other endpoint here, so an existing integration needs no new plumbing.
curl -X POST https://api.maskaadhaar.com/api/v1/extract-pan -H "X-API-Key: " -F "file=@pan.jpg"
Full reference, warning codes and language examples are in the API documentation.
{
"success": true,
"document_type": "pan",
"fields": {
"pan": "ABCPE1234F",
"name": "RAHUL KUMAR",
"father_name": "SURESH KUMAR",
"date_of_birth": "1990-05-12",
"holder_type": "individual"
},
"format_valid": true,
"warnings": []
}
format_valid does and does not tell youThis is the field most likely to be over-trusted, so it is worth being precise about.
A PAN is ten characters with a fixed structure: five letters, four digits, one letter. The fourth
character encodes the holder type — P for an individual, C for a
company, H for a Hindu Undivided Family, F for a firm, and so on. The
fifth is the first letter of the surname for an individual, or of the entity name otherwise.
format_valid checks that structure. It catches the errors that actually happen in
practice: a transposed character, an O read where a 0 was printed, a
nine-character read from a cropped scan.
It deliberately does not gate on the holder-type character. That is reported separately
as holder_type, and a code we have no label for comes back null rather
than failing the document — rejecting a real customer's PAN because our table of codes is
short would be a far worse failure than reporting one we cannot name, and it would surface as an
onboarding rejection nobody could explain.
It is not a check against the Income Tax department. A string can be perfectly
well-formed and belong to nobody. If you need to know that a PAN exists and matches a name, that is
a verification API from an authorised provider, and it is a different product from this one. We say
so here rather than let the field name imply otherwise, because a team that reads
format_valid: true as "this PAN is real" has built a control that does not exist.
| Field | Notes |
|---|---|
pan | Ten characters, uppercased. Returned in full — see the note below on why this differs from the Aadhaar endpoint |
name | As printed on the card, which is upper case on every PAN issued. We do not case-normalise: the printed form is what matches other KYC documents |
father_name | Present on individual PANs. Absent on company, firm and HUF cards, where it comes back null rather than as an empty string |
date_of_birth | ISO YYYY-MM-DD. On non-individual PANs this is the date of incorporation as printed, still in the same field |
holder_type | Decoded from the fourth character of the PAN itself, not from the card's QR: P individual, C company, H Hindu Undivided Family, F firm, T trust. null where we have no label for the code, which means unrecognised rather than invalid |
format_valid | Structural check only, as described above |
Warnings are non-fatal and returned as an array, empty when clean: low_contrast,
rotated_input, partial_read.
The Aadhaar extraction endpoint masks the number by default, and people reasonably ask why this one does not do the same.
Three differences, and they all point the same way. An Aadhaar number is governed by the Aadhaar Act, which restricts its display and disclosure; a PAN is not. An Aadhaar number is a cross-database lookup key that most organisations are not registered with UIDAI to verify, so holding it is liability without capability; a PAN is the identifier your organisation is generally required to record for tax reporting, and recording it is the point. And a masked PAN would be useless for the purpose most callers have, which is populating a field that has to match what the Income Tax department holds.
So the default here is the one that fits the document. If you also want a redacted copy of the card for filing — which is a different requirement from recording the number — that is the PAN masking API, and a pipeline commonly calls both: extract to populate the record, mask to produce the copy it archives.
Cards photographed sideways or upside down are corrected before reading rather than returning a failure the caller has to interpret.
A read that does not satisfy the five-four-one structure and a valid holder-type code is reported as invalid rather than returned as a PAN.
Phone photographs of laminated cards under tube lighting are the normal input. A field that cannot be read comes back null with a warning, not as a plausible guess.
Requests are served from AWS ap-south-1, so processing stays in-country for a data-residency answer.
Documents are processed in memory and not written to a database or object store. Extracted values are never logged: a log of PAN numbers and names is a more attractive target than the document store and usually less well protected.
Keys are stored securely and can be rotated or revoked from your dashboard, with revocation taking effect immediately. Quota and rate limits apply per key.
The most common way a PAN extraction integration causes trouble has nothing to do with reading the card. It is what happens next.
A PAN carries the name in upper case, usually as SURNAME FIRSTNAME or with initials
expanded or not depending on what was submitted at application. An Aadhaar card carries the same
person's name in title case, frequently in a different order, sometimes with a middle name the PAN
omits, sometimes with an initial where the PAN spells the word out. Neither is wrong. They were
captured by different processes, years apart, from different forms.
A pipeline that extracts both and compares them as strings will therefore reject a large share of entirely legitimate customers. Teams discover this after go-live, usually as an unexplained spike in manual review, and the instinct is to blame the OCR.
Three things help, and they are all decisions to make before you integrate rather than after.
This is why the endpoint returns the name exactly as printed and does not helpfully expand
S. Kumar into Suresh Kumar. That expansion is a guess, and a guess written
into a KYC name field fails a match somewhere downstream in a way nobody traces back to the
extraction step.
The same interface for Aadhaar cards, returning name, date of birth, gender and address — with the Aadhaar number masked by default and the last four digits supplied separately.
curl -X POST https://api.maskaadhaar.com/api/v1/extract-aadhaar -H "X-API-Key: " -F "file=@aadhaar.jpg"
No. It reads what is printed and checks the structure. A well-formed PAN can belong to nobody, and confirming that one exists and matches a name is a verification service from an authorised provider — a different product from extraction. We state this plainly because format_valid is easy to over-read.
Yes. The holder type is encoded in the fourth character and is validated. On non-individual cards there is no father's name, so that field returns null rather than an empty string, and the date field carries the date of incorporation as printed.
No, they are separate endpoints by design. Pipelines usually want both on the same document — extraction to populate the record, masking to produce the copy that gets archived — and keeping them separate means a failure in one does not silently affect the other. Both consume the same quota.
No. Documents are processed in memory and streamed back; nothing is written to a database or object store, and extracted field values are not logged either. We log the field count, the warnings and the key.
Tell us your expected monthly volume and peak throughput and we will provision a key with a test quota, so you can benchmark accuracy on your own documents before committing.