Voice AI engineering
The PIN code nightmare: fixing digit capture on Indian phone calls
Stop Indian PIN codes, account fragments, and mixed digit strings from mutating between noisy mobile audio, transcripts, normalization, and APIs.

Run the Indian digit-string torture set
A CSV of PIN codes, grouped digits, Hindi-English variants, corrupt audio conditions, expected candidates, and confirmation rules.
indian-pin-code-voice-test-set.csv
“Five six double zero three eight.”
The transcript says 560038. The normalizer stores 56038. The agent repeats 560083. All three components believe they helped.
Nobody did.
That is the PIN code nightmare. Small field. Huge blast radius.
And by the time a delivery worker is calling from the wrong gate, the original audio has usually disappeared behind a clean transcript, a “successful” tool call, and three dashboards owned by teams who each see only their own correct-looking value.
First, one correction to the usual framing: an India Post PIN is a six-digit number. It is not alphanumeric. DIGIPIN, IFSC codes, booking references, vehicle numbers, and policy IDs can be alphanumeric, and they need their own validators. Mixing all of these into one generic “code” extractor is how silent corruption starts.
Voxeval’s rule is simple. A language model may help interpret how a caller grouped the digits. It does not get to decide whether an invalid identifier is probably fine.
Six digits means six
The Government of India’s e-governance data standard records a Postal Index Number as an integer with a maximum size of six, based on Department of Posts data. Current India Post regulations describe the PIN as a six-digit postcode mapped to a delivery post office.
So if a caller says “four double zero zero one,” your pipeline has five digits: 40001.
Do not pad it. Do not search for a nearby PIN and quietly pick one. Ask for the code again, perhaps in two chunks.
That sounds obvious until a general-purpose model sees an address, recognizes the city, and repairs the number with a plausible local code. Helpful autocomplete is exactly the wrong behavior at this boundary.
Scroll diagram horizontally on smaller screens.
The damage happens between layers
Digit errors are rarely one clean ASR miss. They compound.
A recognizer hears double zero as the word “double” plus one zero. A formatter removes the spoken grouping. An LLM converts oh to the letter O. A database field casts the result to an integer and drops a leading zero. Then the agent reads the new value back as individual English digits even though the caller used Hindi.
Keep five representations:
- The audio span, untouched.
- Raw words:
five six double zero three eight. - Candidates, which may include
560038and a lower-confidence560308. - The validated value and the rule that passed it.
- Directory result: the post office or service area returned by the source your business trusts.
That chain turns a ghost story into a debuggable failure.
Narrowband audio eats tiny distinctions
Phone audio removes detail. Packet loss removes more. A scooter, fan, second speaker, or call-waiting beep can land right on the digit that matters.
The 2026 Voice of India preprint uses unscripted telephonic speech across 15 Indian languages and 139 regional clusters. It also warns that strict single-reference scoring can punish valid transcript variants. Useful context, but a PIN has less room for generosity. 560038 and 560083 are not spelling variants.
Build a separate digit accuracy measure:
exact_digit_sequence_pass = final_validated_value == expected_value
No fuzzy match. No semantic similarity. Exact.
Then report it by mobile route, codec, packet-loss lane, language pattern, speaking pace, and confirmation strategy. The carrier route that looks acceptable on ordinary sentences may still chew through grouped numbers.
Keyterms can help. They cannot validate
Deepgram’s current keyterm guidance supports domain phrases and proper nouns, with up to 500 tokens across supplied keyterms. Flux can update keyterms during a stream. That is handy when the conversation moves from a general support turn into address capture.
Use keyterms for locality names, apartment names, bank names, or recurring product words. Do not feed every possible six-digit PIN into a prompt and hope probability becomes a database constraint.
The pattern we prefer:
- Bias the speech model with likely locality words once the address step begins.
- Generate digit candidates from the exact spoken forms your callers use.
- A deterministic validator checks length, character class, and approved directory lookup.
- Low confidence? Confirm. Wrong length? Ask again.
And clear the address-specific keyterms when the step ends. Otherwise they can leak into later turns and create bizarre substitutions.
A fictional Bengaluru delivery call
This is an invented example, not a real caller or production event.
Caller: “PIN is five six double zero three eight.”
Agent hears candidate 560038. The directory lookup maps it to an expected Bengaluru service area. The agent does not say the whole address is correct. It asks, “I got five-six-zero-zero-three-eight. Is that right?”
Caller: “No, last two are eight three.”
Now the system must preserve the first four digits, replace only the corrected suffix, validate 560083, and read back the new candidate. A lazy conversation state often keeps both suffixes and chooses the old one.
Test that exact repair. It catches more real engineering mistakes than another clean read of six digits.
Codes should have different contracts
Do not send every identifier through one prompt template.
| Identifier | Shape | Safe release behavior |
|---|---|---|
| India Post PIN | Six numeric digits | Exact length plus approved lookup |
| DIGIPIN | Ten allowed characters | Character set, length, and official decoder |
| IFSC | Eleven alphanumeric characters | Format check plus bank-branch lookup |
| UPI ID | Handle with provider suffix | Exact confirmation and payment-provider validation |
| Booking reference | Business-specific | Versioned regex or lookup, never guess |
The spoken forms differ too. B-204 may arrive as “bee two zero four,” “B two oh four,” or “B dash two zero four.” Your candidate generator can be flexible. The executor cannot.
Confirm without exhausting the caller
Reading back every digit three times is not safety. It is friction wearing a hard hat.
Use risk and ambiguity. A PIN used to narrow a delivery zone can be confirmed once in two chunks. A bank account fragment may need masking. An OTP should never be repeated into logs or stored as an ordinary transcript field.
For low-confidence audio, ask the caller to say digits one by one. If the call remains noisy, offer keypad entry or a secure link. Push-to-talk can also be cleaner on a web call than an always-open microphone beside traffic.
The alternative matters. “Please repeat” forever is not a fallback.
Watch the database type
The call can be perfect and the storage layer can still eat the identifier.
Postal PINs are identifiers, not quantities. You do not add them, divide them, or compare their numeric size. Store the confirmed six-character value as a string. The same goes for account fragments, phone numbers, and any field where a leading zero carries meaning.
Then validate again at the API boundary. The browser, voice model, and orchestration service may all say six digits, but the receiving service should reject anything else. A database cast should never become your secret normalizer.
Voxeval would inspect the value at four checkpoints: after recognition, after caller confirmation, inside the tool request, and in the final record. If those four screenshots or trace fields do not match, the case fails even when the agent’s final sentence sounds right.
Build a repair ladder, not a loop
“Sorry, please repeat” is not a strategy. After the first failed capture, change the interaction.
Try a chunked read: first three digits, then the final three. Ask for one digit at a time when the audio is clipping. On a web or app call, offer keypad entry. For an ordinary phone call, DTMF may be available, but keep sensitive fields out of general logs and confirm that your telephony path does not expose tones to systems that do not need them.
After two or three failed attempts, stop blaming the caller. Offer a human or a secure follow-up route. Keep the digits already confirmed only if your policy allows partial state and the caller understands what remains.
That ladder needs tests too. A keypad entry should update the same canonical field as speech. A human handoff should carry the raw evidence and the reason for failure, not a model’s best guess.
What we would block at Voxeval
We would fail the release if any of these happen:
- A five-digit candidate is padded into a valid-looking PIN.
Oand0are changed after caller confirmation.- The correct transcript becomes the wrong API value.
- A correction updates the spoken reply but not the stored field.
- Sensitive digit strings appear in ordinary application logs.
- No keypad or human path exists after repeated audio failure.
Run the Indian digit-string torture set through audio, not text. Keep the bad mobile recordings. Make the validator say no.
Reference list