·3 min read·← All posts
KYC RBI Aadhaar FinTech

The two paths

RBI Master Direction KYC. Video-based Customer Identification Process (V-CIP). A live video call with an authorised official; ID document capture; liveness check; declaration. Suitable for full-KYC accounts with high transaction limits.

Aadhaar Offline KYC. XML-signed by UIDAI, downloaded by the customer, uploaded to your service. Signature verification against UIDAI’s public key. Suitable for limited-KYC use cases (deposit accounts up to a ceiling, small transactions).

Both are RBI-approved; different use cases trigger different paths.

When to use which

Use case Pathway
Full bank account opening Master Direction V-CIP
Deposit account up to ₹50K Aadhaar OKYC (with reverse-KYC after)
Sandbox / lite KYC for product trial Aadhaar OKYC
Enhanced due diligence (high-value customer) Master Direction + additional documents
Re-KYC for existing customer Master Direction OR Aadhaar OKYC depending on tier

Most fintechs build both. The customer experience differs: OKYC takes 60-120 seconds; V-CIP takes 10-15 minutes (slot booking + call).

What OKYC actually validates

The Aadhaar OKYC XML contains:

Verification:

  1. Parse the XML.
  2. Verify the signature against the UIDAI public key (rotated annually).
  3. Decrypt the share-code-protected contents.
  4. Match the name + DOB against your service’s input.

What it doesn’t validate:

What V-CIP validates

V-CIP gives you stronger evidence; OKYC gives you faster onboarding.

The Go implementation shape

// Master Direction V-CIP — most of the complexity is the video pipeline,
// scheduling, and review queue, not the verification itself.
func processVCIP(ctx context.Context, session *VCIPSession) (Verdict, error) {
    // Liveness check via the recording
    // Document OCR + match against captured fields
    // Sanctions screening
    // Final verdict; if Approved, persist to the bank's core
}

// Aadhaar OKYC
func processOKYC(ctx context.Context, xml []byte, shareCode string) (Profile, error) {
    decrypted, err := okyc.DecryptZip(xml, shareCode)
    if err != nil { return Profile{}, err }
    if err := okyc.VerifyUIDAISignature(decrypted, uidaiPublicKey); err != nil {
        return Profile{}, ErrSignatureInvalid
    }
    if time.Since(decrypted.GeneratedAt) > 60*24*time.Hour {
        return Profile{}, ErrOKYCExpired
    }
    return decrypted.Profile, nil
}

The audit shape

For each KYC, the audit log captures:

A regulator’s audit ask is usually: “show me 50 random KYC decisions from last month; explain each.” The audit row plus the document store should make this a 30-minute exercise, not a week of compilation.

Genie’s approach

agents/kyc_orchestrator implements both paths as separate decision trees. The supervisor decides which path based on the use case. The audit chain is unified across both. The patterns are documented at the agent-doc level; the implementation is reviewable Go.

For any Indian fintech doing KYC, both paths are non-negotiable. The implementation effort is similar; the operational maturity is what differs (V-CIP requires a trained-operator team).

← Back to all posts