PAN is the closest thing India has to a universal business identifier, which is why nearly every onboarding flow starts there. It is also routinely misunderstood: teams treat a successful PAN lookup as proof of identity when it is really proof of registration. Knowing exactly what the response does and does not establish is the difference between an onboarding gate that reduces risk and one that just adds a field.
What a PAN verification actually confirms
A PAN verification answers a narrow question: does this number exist on the income tax department's records, and what status and holder name are attached to it? That is genuinely useful, but it is narrower than most product specifications assume.
- It confirms the PAN exists and is currently valid, which filters out typos and fabricated numbers immediately.
- It returns the registered holder name, which you can compare against what the applicant typed.
- It indicates the holder category — individual, company, firm, HUF and so on — encoded in the PAN itself.
- It does not confirm the person submitting the form is the holder. Someone can enter a PAN that is real and not theirs.
Reading the number before you call anything
A PAN is ten characters with a fixed structure, which means a useful amount of validation costs nothing and happens instantly in the browser. Doing this first stops obvious errors consuming an API call and gives the applicant immediate feedback while they are still looking at the field.
- Characters 1–5 are letters, 6–9 are digits, and character 10 is a letter. Anything else is a typo, full stop.
- The fourth character encodes the holder type: P for an individual, C for a company, H for a HUF, F for a firm, T for a trust, among others.
- That fourth character is a free cross-check. If an applicant selects 'Private Limited Company' and submits a PAN whose fourth character is P, one of those two things is wrong and you can say so before calling anything.
- The fifth character is normally the first letter of the surname for individuals, or of the entity name otherwise — a weak signal, but it costs nothing to check.
Catching a mistyped PAN locally turns a failed verification into a corrected field. That matters more than it sounds: a verification that fails feels to the applicant like a rejection, even when the cause was a slipped finger.
What the status field is telling you
Most integrations treat the response as found or not found. The status field carries more than that, and conflating its values produces a poor experience for people who have done nothing wrong.
| Outcome | What it means | Reasonable handling |
|---|---|---|
| Valid and active | Registered and in good standing | Proceed to name matching |
| Not found | No such record — almost always a typo | Let the applicant correct and retry |
| Inactive or deleted | A real status with a real cause | Hold for human review; do not auto-reject silently |
| Marked as fake | Flagged upstream | Stop, and do not offer a retry |
| No response | An upstream problem, not an applicant problem | Pending state, retry with backoff |
Why name matching is the hard part
Most PAN integrations fail in production not on the lookup but on the comparison afterwards. The registered name rarely matches the typed name character for character, and an exact-string check will reject a large share of legitimate applicants on their first attempt.
This is worth dwelling on, because the instinct is to treat a mismatch as a risk signal. In practice the overwhelming majority of mismatches are formatting, not fraud — and a flow that cannot tell the difference will spend its reviewers' attention on the wrong cases.
Where the differences come from
- Word order. Records vary between given-name-first and surname-first, and both appear in real data.
- Initials. 'R Kumar', 'Ramesh Kumar' and 'Kumar R' can all refer to the same person.
- Honorifics and suffixes that one side includes and the other does not.
- Spelling variants from transliteration, where the same name has several defensible spellings in Latin script.
- Married-name changes updated with one authority before another.
- Expanded versus abbreviated entity suffixes — 'Private Limited' against 'Pvt Ltd' against 'P Ltd'.
- Punctuation and spacing inside entity names, which registers and humans treat differently.
A matching approach that survives contact with real data
- Normalise both sidesUpper-case, strip punctuation and honorifics, expand or collapse common entity suffixes consistently, and collapse repeated whitespace. A surprising share of mismatches disappear at this step alone.
- Compare token sets, not stringsTreat the name as an unordered set of tokens so word order stops mattering, and allow a single-letter token to match any token beginning with that letter.
- Score rather than decideProduce a similarity score and set two thresholds: auto-accept above the upper one, auto-reject below the lower one, review in between. A single cut-off forces you to choose between false rejections and false acceptances.
- Weight the rare tokens higherA match on an uncommon surname is far stronger evidence than a match on a common given name. Weighting by token frequency separates genuine matches from coincidental overlap.
- Log the score with the decisionWhen an onboarding is questioned months later, the score and the two names compared are what let you explain it without re-running anything.
Calibrating the thresholds
Thresholds set from intuition are usually wrong in both directions at once. The practical method is to run the matcher over a sample of decisions you already trust, plot where genuine and spurious matches actually fall, and set the bands from that distribution.
- Start with the review band deliberately wide. It is cheap to narrow once you can see what lands in it, and expensive to discover you auto-accepted a category you should not have.
- Review the band composition monthly. If reviewers approve nearly everything in it, raise the auto-accept threshold; if they reject nearly everything, lower the auto-reject one.
- Hold the thresholds as configuration rather than code, so tuning them does not need a deployment.
- Record which threshold version was in force for each decision, or last year's approvals become inexplicable.
Sequencing checks so onboarding stays fast
Verification cost and friction both rise as you move down the stack, so the order matters as much as the checks themselves. Run the cheap, instant, high-yield checks first and escalate only when something does not reconcile.
| Step | What it answers | When to escalate |
|---|---|---|
| Format validation | Is this even a well-formed PAN? | Never — fix it in the browser |
| PAN lookup | Does this tax identity exist and is it active? | Not found, or status inactive |
| Name match | Does the holder name match the applicant? | Score falls in the review band |
| GST lookup | Is the business registered and trading? | Status cancelled, or legal name differs |
| Bank account check | Does the payout destination belong to them? | Any name mismatch at all |
| Director or signatory check | Who actually controls the entity? | Applicant is not a listed signatory |
Most applicants clear the first three steps in seconds. Reserving human review for genuine inconsistencies is what keeps onboarding quick without making it careless. The related piece on GST verification covers the next step in that chain, and bank account verification covers the one after.
Running checks in parallel where you can
Sequencing is about escalation, not about serialising every network call. PAN and GST lookups are independent of each other, so firing them together halves the wait the applicant experiences. What must stay sequential is anything whose input depends on an earlier result.
- Parallel: PAN lookup and GST lookup, when the applicant supplied both.
- Parallel: entity checks and sanctions screening, which share no inputs.
- Sequential: name matching, which needs the lookup response first.
- Sequential: anything gated on an entity type you only learn from a prior response.
Caching, and when it stops being safe
Registration details change rarely, so re-querying the same PAN on every page load is cost without information. Caching is correct — but a cache with no invalidation policy slowly becomes a record of what used to be true.
- Cache the lookup result against the PAN with an explicit expiry rather than indefinitely.
- Invalidate on any material change: a new signatory, a changed registered name, a new payout account.
- Never serve a cached result to a compliance question. Those should read the decision record, which is dated, not the cache.
- Keep the cache and the audit record separate. One is an optimisation; the other is evidence.
Handling the failure cases
A verification API has more interesting failure modes than a plain not-found, and conflating them produces a poor experience for people who have done nothing wrong.
- Not found. Usually a typo. Let the applicant correct and retry rather than failing the application outright.
- Found but inactive. A real status that needs a human decision, not an automatic rejection with no explanation.
- Upstream timeout. Not the applicant's problem. Retry with backoff and keep them in a pending state rather than showing a failure.
- Rate limited. An operational issue on your side. Queue and retry; never surface it as a verification result.
- Malformed response. Rare and worth alerting on, because it usually means the upstream contract changed.
What the applicant should see
Error copy is part of the control. A message that says only 'verification failed' converts a fixable typo into an abandoned application, and generates a support contact that one clearer sentence would have prevented.
| Situation | Poor message | Better message |
|---|---|---|
| Format wrong | Verification failed | That PAN does not look right — it should be five letters, four digits, then a letter |
| Not found | Invalid PAN | We could not find that PAN. Please check it and try again |
| Name mismatch | Rejected | The name does not match our records. We are reviewing it and will be in touch |
| Upstream down | Error | We cannot verify this right now. Your application is saved and we will finish shortly |
Note what the last two do not do: they avoid telling the applicant precisely which field failed where that information would help someone probing the system. There is a balance between helpfulness and disclosure, and it sits differently for a typo than for a mismatch.
Retry policy
- Distinguish retryable from terminal before writing any retry code. A timeout is retryable; a not-found is not, because the same input produces the same answer.
- Back off exponentially with jitter, so a recovering upstream is not hit by every client at once.
- Cap the attempts and then stop, leaving the record in a pending state a human can see.
- Never let a retry loop block the applicant's session — queue it and let them continue.
- Alert when the retry rate crosses a threshold, because that is your earliest signal of an upstream problem.
Verifying at volume
Onboarding one applicant and migrating forty thousand existing records are different problems. Bulk verification is where naive implementations discover rate limits, cost, and the fact that a 2% failure rate means eight hundred cases somebody has to look at.
- Dry-run the format validation firstValidate the whole file locally before a single API call. This is free, and on legacy data it typically removes a meaningful slice of the records that would otherwise fail upstream.
- Deduplicate before submittingThe same PAN often appears under several customer records. Verify the identifier once and attach the result to each record rather than paying for the same lookup repeatedly.
- Throttle deliberatelySet your own concurrency below the published rate limit rather than discovering it. A job that finishes in four hours without errors beats one that finishes in one hour with a thousand rate-limited retries.
- Checkpoint progressWrite results as they arrive so an interrupted run resumes rather than restarting. At volume, restarting is not a minor inconvenience.
- Triage the failures by causeGroup the failed records by reason. One upstream problem affecting six hundred records is one problem, and presenting it as six hundred is how a backlog becomes unmanageable.
Storing what you verified
Verification creates a record you may need to produce later, and it also creates data you now have a duty of care over. Both pull in the same direction: keep the proof, minimise the payload.
- Record the timestamp, which check ran, the decision and the reason. That is what answers a question about why an account was opened.
- Store a reference to the verification rather than the full upstream response where you can.
- Encrypt identifiers at rest and keep them out of logs, analytics events and error reports — the three places they most often leak.
- Mask identifiers in any internal interface where the full value is not needed to do the job.
- Set a retention period deliberately rather than keeping everything indefinitely by default.
The three places identifiers leak
Teams encrypt the database column and then leak the same value through a side channel nobody audited. These are the usual three, and all of them are easier to prevent than to clean up.
- Application logs, where a request body is logged wholesale for debugging and never un-logged.
- Error reporting, where an exception payload carries the full request to a third-party service.
- Analytics, where a form submission event captures every field by default.
The defence is a deny-list applied at the boundary rather than care at each call site. Redact identifiers centrally, in the logger and the error reporter's scrubber, so a new call site cannot reintroduce the leak by forgetting.
Frequently asked questions
Does PAN verification prove the applicant is who they claim to be?
No. It proves the PAN exists and returns the registered holder name. Confirming the applicant is that holder needs a separate control, such as matching the name against a verified bank account or a document check on the individual.
Should an exact name match be required?
No. Legitimate variation in word order, initials and transliteration means exact matching rejects a large share of genuine applicants. Score the similarity and use a review band between automatic acceptance and automatic rejection.
Can I validate a PAN without calling an API?
Partly. The ten-character format is fixed, so a malformed PAN is catchable in the browser. The fourth character also encodes the holder type, which lets you check it against the entity type the applicant selected before making any call.
How often should a PAN be re-verified?
At onboarding, then on a defined refresh cycle or when something material changes — a new signatory, a change of registered name, or a long dormant period. Re-verifying on every transaction adds cost without adding much signal.
What should happen when the verification service is unavailable?
Treat it as a pending state, not a rejection. Keep the application open, retry with backoff, and make sure the stored outcome is 'not yet verified' rather than 'failed', so a transient outage does not permanently mark good applicants.
How do I verify a large batch of existing records?
Validate format locally first, deduplicate so each identifier is looked up once, throttle below the published rate limit, and checkpoint progress so an interrupted run resumes. Budget for the human review of failures, which is usually the larger cost.
Where do PAN numbers most often leak?
Application logs, third-party error reporting, and analytics events — all places where a full request body gets captured by default. Redact centrally at those boundaries rather than relying on care at each call site.