PAN OCR API

PAN OCR API for KYC

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.

Access is issued per organisation. Email contact@maskaadhaar.com with your expected monthly volume and peak throughput, and we will provision a key with a test quota.

One call, structured fields back

Synchronous and stateless. Same request shape as every other endpoint here, so an existing integration needs no new plumbing.

Three lines to integrate

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.

What comes back

{
  "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": []
}

What format_valid does and does not tell you

This 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.

Fields returned

FieldNotes
panTen characters, uppercased. Returned in full — see the note below on why this differs from the Aadhaar endpoint
nameAs 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_namePresent on individual PANs. Absent on company, firm and HUF cards, where it comes back null rather than as an empty string
date_of_birthISO YYYY-MM-DD. On non-individual PANs this is the date of incorporation as printed, still in the same field
holder_typeDecoded 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_validStructural check only, as described above

Warnings are non-fatal and returned as an array, empty when clean: low_contrast, rotated_input, partial_read.

Why PAN comes back in full and Aadhaar does not

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.

What makes the extraction trustworthy

🔄

Any orientation

Cards photographed sideways or upside down are corrected before reading rather than returning a failure the caller has to interpret.

Structure-checked, not guessed

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.

📷

Built for photographs

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.

🇮

Processed in Mumbai

Requests are served from AWS ap-south-1, so processing stays in-country for a data-residency answer.

🗑

No retention, and no field logging

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 rotatable, revocable

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 name mismatch nobody plans for

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.

Also available: Aadhaar extraction

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"

Frequently asked questions

Does the API verify the PAN against the Income Tax department?

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.

Does it work on company and HUF PAN cards?

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.

Can I extract and mask a PAN in one call?

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.

Is the document stored?

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.

Get API access

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.

Related