EKYC 3.0 — Stage 13: Aadhaar eSign

Backend-Only Developer Implementation Guide • AOF Signing via Aadhaar OTP + Vendor Routing + Post-eSign Data Verification
Stage ID: ESIGN_DONE Trigger: Customer initiates AOF eSign BRD Section: 21 — Stage 13 Version: 1.0

Table of Contents

  1. Stage 13 Objective
  2. Preconditions
  3. eSign Vendor Routing
  4. Backend Flow
  5. Post-eSign Data Verification (CRITICAL)
  6. Post-eSign Scenarios
  7. eSign OTP Scenarios
  8. Backend Validations
  9. Existing Stored Procedure Mapping
  10. Error / Drop Codes
  11. Exit State
  12. Vendor & Integration Calls
  13. Database Tables
  14. Implementation Notes

1. Stage 13 Objective

The customer signs the Account Opening Form (AOF) via Aadhaar OTP-based electronic signature. This constitutes a legally binding signature under the Information Technology Act, 2000 (Section 3A — electronic signature). The eSign is performed through a vendor portal (NSDL or Emudhra), with routing determined by a daily budget counter system.

Post-eSign Data Verification is a HARD GATE After the customer signs, the backend extracts 5 fields from the signed document and verifies them against previously collected data. This verification determines whether the lead proceeds (STP), goes for ops review (NON_STP), or is dropped. There is no manual override for verification failures.
Vendor Budget Limits Hyperverge is the primary eSign vendor. Emudhra is the first fallback. NSDL is the last-resort fallback. Vendor selection cascades: HV → Emudhra → NSDL. Daily budget counters are tracked in-memory and reset at midnight IST. (Updated per Product team: order is HV first, then Emudhra, then NSDL as last resort. No Claude API integration.)

2. Preconditions

ConditionRequired ValueNotes
lead.state AOF_GENERATED New code uses KRA_RECHECKED as the entry state. Both must be handled during migration.
AOF Document Must exist in aof_documents The unsigned AOF PDF must be present and accessible at the configured file storage path.
eSign Vendor Determined by daily budget counter In-memory counter checked at eSign initiation. If both vendors are at capacity, the request is queued.
State Migration Note The legacy system uses AOF_GENERATED as the entry state for Stage 13. The new backend uses KRA_RECHECKED. During migration, both states must be accepted as valid preconditions for eSign initiation.

3. eSign Vendor Routing

Vendor routing is determined by an in-memory daily budget counter. The BRD specifies Redis for this purpose, but the current implementation uses in-memory counters (ConcurrentDictionary). Counters reset at midnight IST via a scheduled background task.

3.1 Routing Decision Table

ConditionNSDL UsageEmudhra UsageSelected VendorAction
NSDL budget < 80% < 2,400 Any NSDL Route to NSDL eSign portal
NSDL budget ≥ 80% ≥ 2,400 < 1,600 Emudhra Route to Emudhra eSign portal
NSDL circuit breaker tripped N/A (down) < 1,600 Emudhra (100%) All traffic routed to Emudhra until NSDL recovers
Emudhra also down / at capacity N/A (down) N/A (down/full) Queue 15-minute retry queue + CS Journey initiated for the customer
Both vendors at daily capacity ≥ 3,000 ≥ 1,600 None P0 Alert raised. No eSign possible until next day or capacity increase.
Counter Implementation Daily counters are maintained in-memory (not Redis as the BRD suggests). They are keyed by vendor name + date (e.g., NSDL_2026-04-01). A background task resets all counters at 00:00 IST. In a multi-instance deployment, each instance tracks its own counter — this is an accepted trade-off for simplicity.

3.2 Circuit Breaker Logic

4. Backend Flow

1
Determine eSign Vendor — Check in-memory daily budget counters. Apply routing decision table (Section 3.1). If both vendors unavailable, queue the request and initiate CS Journey. Record selected vendor in esign_transactions.
2
Generate eSign Redirect URL — Call the selected vendor's API (NSDL or Emudhra) with the unsigned AOF document, lead details, and callback URL. Vendor returns a redirect URL for the eSign portal.
3
Redirect Customer to Vendor Portal — Frontend receives the redirect URL and navigates the customer to the vendor's eSign page. Backend logs the redirect event and starts a session timeout timer.
4
Customer Enters Aadhaar Last 4 Digits — On the vendor portal, the customer enters the last 4 digits of their Aadhaar number. This happens entirely on the vendor side.
5
OTP Sent to Aadhaar-Registered Mobile — The vendor triggers an OTP to the customer's Aadhaar-registered mobile number. Important: This mobile number may differ from the eKYC mobile number used in earlier stages.
6
Customer Enters OTP and Signs — Customer enters the OTP on the vendor portal. Upon successful OTP verification, the vendor applies the electronic signature to the AOF document.
7
Callback Received from Vendor — Vendor sends a callback to the backend with the signed document, signature metadata, and transaction status. Backend validates the callback authenticity.
8
Extract 5 Fields from Signed Document — Parse the signed PDF/XML response to extract: Pincode, Year of Birth (YOB), Gender, Full Name, Aadhaar Last 4 Digits. Store all 5 fields in esign_transactions.
9
Post-eSign Data Verification (HARD GATE) — Compare the 5 extracted fields against previously collected data (KRA, Aadhaar, PAN). Apply the verification rules defined in Section 5. This step has no manual override.
10
Store Signed PDF — Save the signed AOF PDF to the configured file storage drive. Update document_path_info and aof_documents with the signed document path.
11
Route Based on Verification Result
STP (all match): Set lead.state = ESIGN_DONE, proceed to Stage 14.
NON_STP (name fuzzy < 70): Set lead.state = NON_STP_REVIEW, flag for ops review.
DROP (hard field mismatch): Set lead.state = DROPPED, record DROP_ESIGN_DATA_MISMATCH.
Aadhaar Mobile vs eKYC Mobile The OTP for eSign is sent to the customer's Aadhaar-registered mobile number, which may be different from the mobile number used during the eKYC journey (Stage 1). The backend must not assume these are the same number.

5. Post-eSign Data Verification (CRITICAL)

After the eSign callback is received and the 5 fields are extracted, the backend performs a mandatory verification against previously collected data. This is a HARD GATE — no manual override is permitted.

5.1 Verification Rules

FieldMatch TypeReference SourceOn MatchOn Mismatch
Pincode Exact match KRA data (if VALIDATED / MOD) or Aadhaar data (if NON_KRA / API_DOWN) Pass Hard BlockDROP_ESIGN_DATA_MISMATCH
Year of Birth Exact match PAN DOB (year component) Pass Hard BlockDROP_ESIGN_DATA_MISMATCH
Gender Exact match Aadhaar data (gender field from eKYC) Pass Hard BlockDROP_ESIGN_DATA_MISMATCH
Full Name Fuzzy match ≥ 70% ekyc_name (name from Aadhaar eKYC stage) Pass NON_STP flag only (score < 70%). Does NOT block the lead.
Aadhaar Last 4 Exact match Aadhaar last 4 from eKYC stage Pass Hard BlockDROP_ESIGN_DATA_MISMATCH

5.2 Reference Data Priority

KRA StatusReference Source for PincodeRationale
KRA_VALIDATED KRA data (pincode from KRA record) KRA data is the most authoritative source for validated customers
KRA_MOD KRA data (pincode from KRA record) KRA MOD data is still authoritative despite modification flag
NON_KRA Aadhaar data (pincode from eKYC) No KRA record exists; fall back to Aadhaar eKYC data
API_DOWN Aadhaar data (pincode from eKYC) KRA data unavailable; fall back to Aadhaar eKYC data
No Manual Override The post-eSign data verification is a regulatory compliance requirement. If Pincode, Year of Birth, Gender, or Aadhaar Last 4 do not match, the lead must be dropped. There is no ops workflow to override this decision. Only the Name field allows a soft mismatch (NON_STP flag).

6. Post-eSign Scenarios

6.1 Verification Outcome Scenarios

ScenarioConditionActionLead State
All fields match All 5 fields pass verification (Name ≥ 70%) Proceed to Stage 14 ESIGN_DONE (STP)
Pincode mismatch eSign pincode does not match KRA/Aadhaar pincode Hard block — drop the lead DROPPED with DROP_ESIGN_DATA_MISMATCH
Year of Birth mismatch eSign YOB does not match year from PAN DOB Hard block — drop the lead DROPPED with DROP_ESIGN_DATA_MISMATCH
Gender mismatch eSign gender does not match Aadhaar gender Hard block — drop the lead DROPPED with DROP_ESIGN_DATA_MISMATCH
Aadhaar Last 4 mismatch eSign Aadhaar last 4 does not match eKYC Aadhaar last 4 Hard block — drop the lead DROPPED with DROP_ESIGN_DATA_MISMATCH
Name fuzzy < 70% eSign name fuzzy score against ekyc_name is below 70% Flag as NON_STP for ops review. Does NOT block. NON_STP_REVIEW
Vendor missing fields Vendor callback does not contain one or more of the 5 required fields Initiate CS Journey — manual review required CS_ESIGN_VENDOR_DOWN
Name match service down Fuzzy matching service is unavailable Default to NON_STP — flag for ops review NON_STP_REVIEW
Name Mismatch is Soft A name fuzzy match score below 70% results in a NON_STP flag only. The lead is not dropped — it proceeds to ops review. This is by design, as name variations (spelling, transliteration, initials vs. full name) are common in Aadhaar records.

7. eSign OTP Scenarios

The OTP flow happens entirely on the vendor portal (NSDL/Emudhra). The backend receives the outcome via callback. These scenarios describe the expected vendor-side behavior and how the backend handles each outcome.

ScenarioVendor BehaviorBackend Handling
OTP correct Vendor applies eSign to AOF. Returns signed document via callback. Process callback, extract fields, run post-eSign verification.
Wrong OTP (attempt 1-4) Vendor shows error, allows retry. Remaining attempts displayed. No backend action needed. Vendor handles retries internally.
5th wrong OTP Vendor locks the session for 10 minutes. The same eSign link remains valid after the lock period. No immediate callback. Backend waits for eventual success/failure callback. Session timeout timer continues.
OTP expired Vendor allows customer to request a new OTP on the same session. No backend action needed. Vendor handles OTP regeneration.
Browser closed Vendor session may expire. On resume, backend generates a fresh eSign link (new redirect URL). The customer starts the eSign flow again.
Session timeout Vendor session expires after inactivity. On resume, backend generates a fresh eSign link. Previous transaction is marked as expired.
10-Minute Lock When the customer enters the wrong OTP 5 times, the vendor locks the session for 10 minutes. The same link remains valid after the lock expires — the customer does not need a new link. However, if the customer closes the browser and resumes, a fresh link is generated.

8. Backend Validations

ValidationDescriptionWhen AppliedOn Failure
eSign Callback Verification Validate callback authenticity — verify vendor signature, check transaction ID matches, ensure callback is from the expected vendor endpoint On receiving vendor callback Reject callback. Log as suspicious. Do not process.
Post-eSign 5-Field Verification Extract and verify Pincode, YOB, Gender, Name, Aadhaar Last 4 against reference data (see Section 5) After successful callback processing DROP (hard fields) or NON_STP (name only)
Signed PDF Storage Validate that the signed PDF is complete, non-corrupt, and successfully stored to the configured file storage drive After callback processing Retry storage. If persistent failure, CS Journey.
Vendor Capacity Check Verify that the selected vendor has not exceeded its daily budget before initiating the eSign request At eSign initiation (Step 1) Route to alternate vendor or queue (see Section 3.1)
OTP Lock Detection Handle scenarios where the vendor reports that the Aadhaar OTP has been locked due to excessive wrong attempts On vendor callback or session status check Wait for lock expiry (10 min). Same link remains valid.

9. Existing Stored Procedure Mapping

9.1 Stored Procedures (Old System)

These stored procedures from the legacy system map to Stage 13 eSign functionality. They serve as reference for what the new backend must replicate:

Stored ProcedurePurposeNew Backend Equivalent
USP_ALLOW_ESIGN_SJET Check if eSign is allowed for the lead (precondition validation) eSign eligibility check in eSign service — validates lead.state, AOF existence, vendor capacity
USP_INSERT_EMUDHRA_Req_Resp Log Emudhra eSign request/response payloads esign_transactions table insert with vendor = EMUDHRA
USP_INSERT_UPDATE_NSDL_ESIGN_LOG_SJET Log NSDL eSign request/response payloads esign_transactions table insert/update with vendor = NSDL
USP_ESIGN_MATCHING_LOGIC_SJET Post-eSign data verification logic — compares extracted fields against reference data Post-eSign verification service (Section 5 rules). Implements exact + fuzzy matching.
USP_ESIGNMATCHING_FLAG_SJET Set STP/NON_STP/DROP flags based on eSign matching results Verification result handler — updates esign_data_verification_result and routes lead
USP_UPDATE_ESIGNSTAGE_SJET Update lead state after eSign completion lead.state update to ESIGN_DONE / NON_STP_REVIEW / DROPPED
USP_INSERT_UPDATE_PreESIGNFINAL_FILEPATH_INFO_SJET Store the pre-eSign (unsigned) AOF file path aof_documents table — unsigned_pdf_path field
USP_INSERT_UPDATE_ESIGN_FILEPATH_INFO_SJET Store the signed AOF file path after eSign completion aof_documents table — signed_pdf_path field + document_path_info entry
USP_CLIENT_GENERATECLIENTCODE_REVAMP_SJET Generate client code after successful eSign (downstream process) Client code generation service — triggered after ESIGN_DONE state transition

9.2 Old External API Calls

Legacy API methods that the new backend must integrate with (or replace):

Old API MethodVendorPurposeNotes
PERFORM_EMUDHRA_ESIGN Emudhra Initiate Emudhra eSign — sends AOF document and receives redirect URL Part of EsignAPI controller
PERFORM_NSDL_ESIGN_REQUEST_STDAPI NSDL Initiate NSDL eSign — sends AOF document and receives redirect URL Part of EsignAPI controller. Uses standard API mode.
EsignAPI (controller) Both Main eSign controller handling initiation, callback, and status endpoints Routes to NSDL or Emudhra based on vendor selection logic
Migration Note The old system uses separate stored procedures for NSDL and Emudhra logging (USP_INSERT_UPDATE_NSDL_ESIGN_LOG_SJET vs USP_INSERT_EMUDHRA_Req_Resp). The new backend unifies these into a single esign_transactions table with a vendor column to distinguish between providers.

10. Error / Drop Codes

CodeTypeTriggerUser Impact
DROP_ESIGN_DATA_MISMATCH Hard Drop Post-eSign verification fails for Pincode, YOB, Gender, or Aadhaar Last 4 lead.state = DROPPED. Journey terminated. No manual override. Customer cannot proceed.
CS_ESIGN_VENDOR_DOWN CS Journey Both eSign vendors are down or vendor callback is missing required fields Lead enters CS queue. Customer is notified to wait. Manual intervention by CS team.
CS_AOF_FAIL CS Journey AOF document is missing, corrupt, or cannot be sent to vendor Lead enters CS queue. AOF must be regenerated before eSign can proceed.
DROP_SESSION_TIMEOUT Soft Drop eSign session expires without completion and customer does not resume Lead remains in current state. On resume, a fresh eSign link is generated.
BE_ESIGN_INIT_FAILED Backend Error eSign initiation fails — vendor API returns error or timeout during redirect URL generation Retry with same or alternate vendor. If persistent, CS Journey.
DROP_ESIGN_DATA_MISMATCH is Final This is the most critical drop code in Stage 13. It indicates a fundamental data mismatch between the eSign identity and the previously verified identity. There is no ops workflow, no manual override, and no retry path. The lead is permanently dropped.

11. Exit State

After Stage 13 completes, the following fields are populated:

FieldValue / SourceNotes
lead.state ESIGN_DONE (STP) or NON_STP_REVIEW (Non-STP) STP leads proceed to Stage 14. Non-STP leads go to ops review queue.
signed_pdf_path File path on configured drive Full path to the signed AOF PDF stored on the configured file storage drive.
esign_vendor NSDL or EMUDHRA Which vendor was used for this eSign transaction.
esign_completed_at Timestamp (UTC) When the eSign callback was successfully processed.
esign_transaction_id Vendor-assigned transaction ID Unique transaction identifier from the eSign vendor for audit trail.
esign_data_verification_result STP | NON_STP | DROP Outcome of the post-eSign 5-field verification.
esign_pincode Extracted from signed document Pincode from the eSign response. Compared against KRA/Aadhaar pincode.
esign_yob Extracted from signed document Year of Birth from the eSign response. Compared against PAN DOB year.
esign_gender Extracted from signed document Gender from the eSign response. Compared against Aadhaar gender.
esign_name Extracted from signed document Full name from the eSign response. Fuzzy matched against ekyc_name.
esign_aadhaar_last4 Extracted from signed document Last 4 digits of Aadhaar from the eSign response. Compared against eKYC Aadhaar last 4.
STP Exit When all 5 fields match (including Name ≥ 70%), the lead exits Stage 13 with lead.state = ESIGN_DONE and proceeds automatically to Stage 14 (Client Code Generation / Final Processing).

12. Vendor & Integration Calls

Vendor / SystemPurposeWhen CalledSync / Async
NSDL eSign Primary eSign vendor — initiate eSign, receive callback with signed document eSign initiation (when NSDL selected by routing logic) Sync (initiation) / Async (callback)
Emudhra eSign Secondary eSign vendor — initiate eSign, receive callback with signed document eSign initiation (when Emudhra selected by routing logic) Sync (initiation) / Async (callback)
In-Memory Counter Daily budget tracking for vendor routing (NSDL: ~3000/day, Emudhra: ~1600/day) eSign initiation — checked before vendor selection Sync
File Storage (Configured Drive) Store signed AOF PDF and update file path references After callback processing Sync
CleverTap Event tracking (eSign initiated, eSign completed, eSign failed, verification result) After eSign initiation; after callback processing; after verification Async
Zoho CRM Lead status update — eSign stage transition After lead state change (ESIGN_DONE / NON_STP_REVIEW / DROPPED) Async
CDP Customer data platform update with eSign status and verification result After eSign completion and verification Async
Datalake Analytics event logging for eSign metrics (vendor usage, verification pass/fail rates) After eSign completion and verification Async
Appsflyer Attribution tracking — eSign completion event After successful eSign completion Async
Firebase Push notification and analytics events After eSign completion or failure (notify customer of result) Async

13. Database Tables

13.1 Operational Tables

TablePurposeKey Fields (Stage 13 Relevant)
esign_transactions Master eSign transaction record — one row per eSign attempt lead_id, vendor (NSDL/EMUDHRA), transaction_id, status (INITIATED/COMPLETED/FAILED/EXPIRED), redirect_url, callback_payload, esign_pincode, esign_yob, esign_gender, esign_name, esign_aadhaar_last4, verification_result (STP/NON_STP/DROP), name_match_score, initiated_at, completed_at
aof_documents AOF document records — tracks unsigned and signed PDFs lead_id, unsigned_pdf_path, signed_pdf_path, esign_transaction_id, generated_at, signed_at
leads Master lead record state (ESIGN_DONE / NON_STP_REVIEW / DROPPED), esign_vendor, esign_completed_at, esign_transaction_id, esign_data_verification_result
document_path_info File path reference for all documents lead_id, document_type (SIGNED_AOF), file_path, storage_type, created_at

13.2 Reference / Audit Tables

TablePurposeKey Fields
journey_stage_events Stage transition audit trail lead_id, stage (STAGE_13), event (ESIGN_INITIATED / ESIGN_COMPLETED / ESIGN_FAILED / VERIFICATION_PASS / VERIFICATION_FAIL), metadata, created_at
lead_state_transitions State machine audit log lead_id, from_state (AOF_GENERATED / KRA_RECHECKED), to_state (ESIGN_DONE / NON_STP_REVIEW / DROPPED), reason, triggered_by, created_at
downstream_events Async events dispatched to external systems lead_id, target (clevertap / zoho / cdp / datalake / appsflyer / firebase), event_type, status, dispatched_at

14. Implementation Notes

File Storage via Configured Drive Signed AOF PDFs are stored on a configured file storage drive (not cloud blob storage). The path is determined by the application configuration. Ensure the drive is accessible, has sufficient space, and that file paths are stored in both aof_documents.signed_pdf_path and document_path_info.
In-Memory Counter (Not Redis) The BRD specifies Redis for daily budget counters, but the current implementation uses in-memory counters (ConcurrentDictionary). This means counters are per-instance and not shared across multiple backend instances. In a multi-instance deployment, each instance independently tracks its own counter. The total daily budget must be divided across instances or a shared counter mechanism must be implemented in a future iteration.
Post-eSign Verification is a HARD GATE This cannot be overemphasized: the post-eSign 5-field data verification is a regulatory compliance requirement. There is no manual override, no ops workflow to bypass it, and no retry path for hard field mismatches (Pincode, YOB, Gender, Aadhaar Last 4). Only the Name field allows a soft mismatch resulting in NON_STP flag. Developers must not build any override mechanism for the hard fields.
Vendor Callback Security All vendor callbacks must be validated for authenticity before processing. Verify the vendor's digital signature on the callback payload, confirm the transaction ID matches an initiated transaction, and ensure the callback originates from the vendor's known IP range. Reject and log any suspicious callbacks.