Design problems
Payments & fintechMediumSDE-2 30 min

Design an instant loan approval pipeline

Asked at
AmazonCREDGoldman SachsPaytmPhonePePolicyBazaar

The interviewer asks

“Design the backend for an instant personal loan product: a user applies in the app, and within about two minutes gets a decision and an offer, signs the agreement and receives money in their bank account.”

What a strong answer looks like

A strong answer models the application as a long-running, resumable workflow, not one big synchronous API call. The workflow gathers data from slow, costly and unreliable third parties: KYC (PAN, Aadhaar-based eKYC or CKYC), the credit bureau report, bank statements via the Account Aggregator framework, and device and fraud signals. It then builds features, scores the applicant with a versioned ML model plus a policy rules engine, and produces an explainable decision and offer. Accepted offers go through a Key Fact Statement, e-sign, an e-mandate for EMIs, and disbursal by the regulated lender directly to the borrower's bank account, as RBI's digital lending rules require. The hard parts are orchestrating the vendor calls with retries and caching, keeping every decision reproducible for audit, and keeping fraud out without slowing honest users.

Concepts to mention

Durable workflow with persisted steps and signalsIdempotent, cost-aware vendor callsOrder checks by cost: cheap filters before paid pullsPolicy rules plus ML model plus pricingImmutable decision records with model and rule versionsFeature store with point-in-time correctnessFraud signals: device, identity, graph, velocityAccount Aggregator consent-based dataDirect lender-to-borrower disbursal and KFS (RBI digital lending)Shadow mode and champion-challenger rollout

1 Requirements

Functional

  • User applies with basic details and consent; the app shows progress through steps
  • Verify identity: PAN check, Aadhaar-based eKYC or CKYC, selfie liveness and face match
  • Pull the credit bureau report and, where needed, bank statements through the Account Aggregator framework
  • Score the application with policy rules and an ML model; decide approve, reject or refer to manual review
  • Generate an offer (amount, tenure, interest rate, fees) and a Key Fact Statement (KFS)
  • Collect e-sign on the loan agreement and set up an e-NACH or UPI AutoPay mandate for EMIs
  • Disburse to the borrower's verified bank account and notify them
  • Keep a complete, reproducible record of every decision for audit and customer queries

Non-functional

  • Decision for ~80% of applications in under 2 minutes end to end; scoring step itself under 500 ms
  • Every application resumable after app close or a server crash, with no step done twice that costs money
  • Peak ~200 applications/s during campaigns and festive sales; ~2M applications/day
  • Decision reproducibility: the exact inputs, model version and rule version stored for at least the loan's life plus years after
  • Data stored in India; PII encrypted; consent captured for each data pull
  • 99.9% availability for the application flow; partner outages degrade, not break, the flow

Out of scope (say it out loud)

  • Loan servicing after disbursal (EMI collection, collections, foreclosure)
  • Model training pipeline in detail (mentioned only)
  • Co-lending arrangements between multiple lenders
  • The lender's core banking or loan management system internals

2 Estimates

Applications~2M/day, ~25/s average, ~200/s peakAssume a large app with a pre-approved base; 2M ÷ 86,400 ≈ 23/s; campaign pushes give 5-10x peaks
Bureau pulls~1M/dayOnly after cheap filters pass (KYC and basic eligibility); ~50% of applications reach the bureau step. Each pull has a cost, so dedupe within a validity window
Account Aggregator fetches~200k/dayOnly for thin-file or higher-amount applicants (~10-20%)
Workflow steps~20M step executions/day~10 steps per application × 2M
Approved and disbursed~100k loans/dayTypical approval ~20-30% and offer acceptance ~20-25% of approvals
Decision record storage~200 KB per application, ~150 TB/yearBureau report JSON + AA statements summary + features + scores ≈ 200 KB × 2M × 365 ≈ 146 TB; raw documents go to S3 with lifecycle rules

3 API

EndpointWhat it does
POST/applicationsStart an application with requested amount and consent ids. Header Idempotency-Key. Returns application_id and the next step
GET/applications/{id}Current step, status and what the user must do next (poll or receive via push)
POST/applications/{id}/kycSubmit KYC inputs (PAN, eKYC OTP reference, selfie upload URL)
POST/applications/{id}/aa-consentStart Account Aggregator consent; returns a redirect to the AA app
POST/applications/{id}/offer/acceptAccept an offer variant (amount, tenure); generates KFS and agreement
POST/applications/{id}/esignStart e-sign and mandate setup; callbacks complete the step
POST/webhooks/{partner}Callbacks from AA, e-sign, mandate and disbursal partners (signature verified, idempotent)
gRPCDecisionService.ScoreInternal: features in, decision + reasons + model and rule versions out

4 Data model

applicationsPostgres
application_id (PK)user_idproduct_idrequested_amountstatuscurrent_stepworkflow_idlender_idcreated_atupdated_at

Index on user_id and status. One active application per user per product, enforced by a partial unique index.

vendor_callsPostgres
call_idapplication_idvendor (bureau, ckyc, aa, esign)request_hashstatusresponse_ref (S3)costlatency_mscreated_at

Every external call logged with cost. request_hash + user lets you reuse a recent bureau report instead of paying for a new pull.

raw_documentsS3 (encrypted, India region)
bureau reportsAA statementsKYC imagessigned agreement PDFs

Object lock (WORM) for signed agreements and KFS; lifecycle rules per data type and retention policy.

decision_recordsPostgres + S3 snapshot
decision_idapplication_idfeature_vector_refmodel_versionruleset_versionscoredecisionreason_codesofferdecided_at

Immutable. Allows replaying the exact decision and explaining rejections with reason codes.

feature_store (online)Redis / DynamoDB
user_id → precomputed features (app behaviour, repayment history on platform, pre-approved limit)

Low-latency lookups at scoring time. Offline store (Iceberg on S3) holds point-in-time history for training.

loansPostgres (lender LMS is the system of record)
loan_idapplication_idlender_loan_refprincipalratetenuremandate_iddisbursal_utrstatus

Mirror of the lender's record for the app; reconciled daily with the lender's loan management system.

5 Architecture

CLIENTSEDGESERVICESASYNCDATAEXTERNALstart / signalactivitiesPAN, CKYC, bureauFI data fetchraw reportsscorefeaturesdecision recordesign, mandate, disbursestatus eventspush updatesBorrower appAPI gatewayFraud & device checksApplication serviceDecision serviceWorkflow engine(Temporal)Kafka (loan events)Vendor adaptersPostgres (apps,decisions)Online feature storeS3 documents (WORM)KYC / CKYC / bureauAccount AggregatorLender LMS +e-sign/NACH
ClientEdge / gatewayService / workerQueue / streamCacheDatabase / storageAI / modelThird partyrequestasync (event / queue)

Hover a box to highlight its connections.

6 Request flows

Apply and get a decision

  1. 1User taps 'Get loan', gives consent and requested amount. Application service creates the application (idempotent) and starts a workflow with workflow_id = application_id.
  2. 2Workflow runs cheap checks first: eligibility (age, city, existing loan), a negative list, and device risk (rooted device, emulator, many accounts on one device).
  3. 3KYC: PAN verification and CKYC search; if no CKYC record, Aadhaar-based eKYC with OTP and a selfie liveness check with face match.
  4. 4Bureau: the adapter checks vendor_calls for a report for this user pulled in the last N days; if none, it pulls a fresh report and stores it in S3.
  5. 5If the bureau file is thin or the amount is high, the workflow asks the user for Account Aggregator consent and waits for a signal (with a timeout) while the user approves in the AA app.
  6. 6Feature builder combines bureau, AA statement features (salary credits, bounces, average balance), platform behaviour and device signals.
  7. 7Decision service runs policy rules (hard rejects), then the ML model for probability of default, then pricing and limit rules; it writes an immutable decision record with reason codes.
  8. 8Outcome: approve with offers, reject with reason category, or refer to manual review queue. The app receives the result by push and on its next poll.

Accept offer and disburse

  1. 1User picks ₹1,50,000 for 24 months. The system generates the Key Fact Statement with the all-in APR and the agreement from versioned templates.
  2. 2User e-signs (Aadhaar OTP based e-sign); the signed PDF is stored in S3 with object lock.
  3. 3User sets up an e-NACH or UPI AutoPay mandate for EMIs; the workflow waits for the mandate success callback.
  4. 4Workflow calls the lender's LMS to book the loan with an idempotency key = application_id, then requests disbursal to the user's verified bank account (penny-drop verified earlier).
  5. 5Lender disburses via IMPS/NEFT and returns a UTR; the workflow records it, emits 'loan.disbursed' and the user is notified.

7 Deep dives

Workflow orchestration for slow, paid, flaky vendors

An application spends most of its time waiting: for vendors (bureau p99 can be several seconds), for the user (OTPs, AA consent, e-sign), and for callbacks. A synchronous request chain would time out and lose progress. Use a durable workflow engine like Temporal: the workflow code describes steps, and the engine persists every step result, so a crash resumes from the last completed step without repeating it. That last part matters because bureau pulls and eKYC calls cost money and some leave a footprint (a hard inquiry on the credit report). Each activity has its own timeout and retry policy: retry network errors with exponential backoff, but never retry a 'no record found' or a business rejection. Wait for user actions with signals plus timers ('if no AA consent in 30 minutes, decide without AA or send a reminder'). Order steps by cost: run free and fast checks (eligibility, device, negative list) before paid ones, and stop early on hard rejects. Put each vendor behind an adapter with a circuit breaker and a fallback vendor where possible (two bureaus, two KYC providers). If you do not want Temporal, a Postgres step table with a worker pool and a scheduler is a valid answer at this scale; the key ideas are persisted progress and idempotent steps.

Decisioning: rules plus model, versioned and explainable

Use layers. First, policy rules that lenders and regulators require: minimum age, serviceable pin codes, bureau score cut-offs, no recent write-offs, maximum debt-to-income. These are hard rejects and must be readable by risk teams, so keep them in a rules engine with versioned rule sets, not in code. Second, an ML model (often gradient-boosted trees, because they are accurate on tabular data and explainable with SHAP values) predicts probability of default from features. Third, pricing and limit rules map the risk band to an offer: amount, tenure options and interest rate. Every decision writes an immutable record: the feature vector, model version, rule set version, score, reason codes and offer. This gives reproducibility (re-run the same model on the same features and get the same answer), adverse-action reasons for rejected users, and audit support. Roll out new models in shadow mode first (score but do not act), then champion-challenger on a small traffic slice, and watch approval rate and early delinquency. Feature consistency matters: compute features with the same code online and offline, and store point-in-time snapshots so training does not use data that was not available at decision time (leakage).

Fraud and identity risk

Instant loans attract organised fraud: stolen identities, synthetic identities, and 'first-party' fraud where the borrower never intends to pay. Most fraud is caught by signals around the application, not the bureau score. Device intelligence: emulator or rooted device, one device used by many applicants, SIM recently changed. Identity: face match between selfie and KYC photo, liveness, name match across PAN, bank account (penny drop) and KYC. Graph signals: shared phone numbers, addresses, devices or bank accounts across applications; a graph store or simple linked-entity tables with counts catch fraud rings. Behaviour: typing patterns, time spent on the form, and applying from a location far from the KYC address. Velocity: many applications in a short time from the same IP range or pin code. Score fraud separately from credit risk, run it before paid bureau pulls where possible, and send borderline cases to manual review with all evidence on one screen. Feed outcomes back: loans that default in the first EMI (first payment default) are the best fraud labels, and they arrive 30-60 days later, so the training pipeline must handle delayed labels.

Regulatory guardrails built into the design

In India, RBI's digital lending guidelines shape the architecture. Disbursal and repayment must flow directly between the regulated lender's account and the borrower's bank account, not through the app's pool account, so the app calls the lender's LMS to disburse rather than moving money itself. The borrower must get a Key Fact Statement with the all-in annual percentage rate before signing, and a cooling-off period to exit without penalty, so the KFS generator and an 'exit' workflow branch are part of the system. Data collection needs explicit, purpose-specific consent, and apps should not access contacts or media for lending, so consent ids are stored with every data pull and the feature builder must not use unconsented data. Data must be stored in India. The Account Aggregator framework itself is consent-based: the AA never sees decrypted data, and the consent has a purpose, a date range and an expiry. In the interview, keep this short: name these constraints and show where they appear in the design. That shows you can build regulated systems, which fintech interviewers care about a lot.

8 Trade-offs

Synchronous API vs async workflow with polling/push

A synchronous 'apply and wait' API is simple but breaks when any step takes more than a few seconds or needs user action. An async workflow with a status endpoint and push notifications handles minutes-long flows, app restarts and partner delays. The cost is more moving parts and a UI that must show progress states.

Reuse a recent bureau report vs always pull fresh

Reusing a report pulled in the last few days saves cost and avoids extra hard inquiries. A fresh pull catches new loans taken in between, which is a known fraud pattern (loan stacking). Common policy: reuse within a short window for the same product, pull fresh before disbursal for large amounts.

Build the model in-house vs vendor scores

Bureau scores are a good start but generic. In-house models using platform data (transaction history, repayment behaviour) are much better for your users, but need data science, monitoring and governance. Start with bureau score plus rules, add your own model once you have enough repayment outcomes.

9 Bottlenecks

Vendor rate limits during campaigns

At 10x applications, bureau and KYC vendors throttle first. Queue applications at the vendor's allowed rate with per-vendor token buckets, show 'checking your details' in the app, and spread load across two vendors. Pre-approved users (scored in batch overnight from existing data) can skip parts of the flow.

Manual review queue

If rules send too many cases to review, the queue grows and decisions take days. Track referral rate as a metric, tune thresholds, and prioritise the queue by expected value (larger, likely-good loans first).

10 Failure handling

Bureau down

The circuit breaker opens; the workflow waits and retries with backoff, or uses the fallback bureau. Applications are not rejected for a vendor outage; users are told the decision will come shortly by notification.

Disbursal callback never arrives

The loan stays in DISBURSING. The workflow queries the lender for status with the same idempotency key; it never sends a second disbursal request with a new key. Daily reconciliation against the lender's disbursal file closes the gap.

Bad model deployed

Monitor approval rate, score distribution and feature drift in real time; a sudden jump triggers an automatic rollback to the previous model version, which is just a config change because models are versioned and the decision service loads by version.

11 What impresses

  • Treating the application as a resumable workflow that waits on users and vendors
  • Ordering steps by cost and stopping early on hard rejects
  • Storing model version, rule version and features for every decision for reproducibility
  • Separating fraud risk from credit risk and using graph signals for rings
  • Naming RBI digital lending constraints and showing where they live in the design
  • Handling delayed labels (defaults arrive weeks later) in the model feedback loop

12 Mistakes

  • One synchronous API that calls every vendor in sequence
  • Retrying paid vendor calls without idempotency, paying twice or creating multiple hard inquiries
  • Hard-coding credit rules in application code
  • No audit trail of why a user was rejected
  • Ignoring fraud and treating credit score as enough
  • Moving loan money through the app's own account

13 Follow-ups

Q1How would you pre-approve 10M existing users overnight?
Q2How do you explain a rejection to a user without revealing your model?
Q3How would you support multiple lenders and route an applicant to the best one?
Q4How do you detect model drift after a change in the economy?
Q5What happens if the user closes the app during AA consent and returns the next day?
Q6How would you add an LLM to read uploaded salary slips safely?

Saved on this device. Create a free account to keep it on every device.

Practise this with Sam

A real mock interview, out loud, with an honest scorecard. Free to start.

Start free