Skip to content
PRS India

Sahaj Credit

Rebuilding an NBFC lending stack to survive an RBI inspection

Digital lending and field collections for an NBFC, rebuilt around a double-entry ledger that is only ever added to, money that moves straight between borrower and lender, and offline receipts that cannot be denied later.

Client
Sahaj Credit
Industry
Fintech / NBFC Lending
Location
Pune, India
Duration
24 weeks
Published
Mar 2024
Updated
Oct 2026

11 min

Median KYC turnaround, down from 3 days

94.6%

UPI / NACH mandate success rate, up from 81%

0.03%

Of postings become matching exceptions, each with an owner

0

Rupees in transit through an account we control

01

The challenge

Sahaj Credit is an RBI-registered NBFC writing small-ticket unsecured business loans — ₹50,000 to ₹5 lakh, twelve to twenty-four months, to kirana stores and small traders across five states. They came to us with a growth problem and left with a compliance rebuild, because the growth problem was only a sign of a deeper issue.

The stack they had would not survive an inspection

The RBI's Digital Lending Guidelines are very clear on one point: all loan disbursals and repayments must flow directly between the borrower's bank account and the regulated entity's bank account. No middle account, and no pooling in an account controlled by a lending service provider or a technology vendor.

Their existing vendor setup pooled collections in a middle account before moving them to the NBFC. It was easy. It was also exactly what the guidelines forbid, and no new features on top of it could have made it acceptable.

And the operational numbers were bad on their own terms

  • KYC turnaround was three days. Documents were emailed, a person looked at them, and the answer came back after the applicant had usually already borrowed from someone faster.
  • 19% of NACH mandate registrations were failing, mostly because names and account details did not match, and nobody checked them before submission. Every failed mandate is a customer who must be collected from by hand, forever.
  • Balances were a mutable column. There was a loans.outstanding field that code updated. When it did not match the bank, and it often did not, there was no way to tell which was wrong, because there was no history to replay. This kind of bug does not get fixed in testing. An auditor finds it.
  • Field collection agents gave paper receipts from a book. Cash matching ran a week behind and depended on trust.

02

What we built

Money does not touch us

We rebuilt the money flow so that no account we control ever holds a rupee. Disbursals go from the NBFC's own bank account to the borrower's; repayments go from the borrower's account to the NBFC's, through a payment aggregator that works with the bank. Our system runs the steps and records them. It does not hold the money.

So every ledger entry in our system is a projection of a bank event, never a number we invent. We do not write a repayment when we ask for one. We write it when the bank tells us it happened. This sounds fussy until the day your ledger and the bank disagree, and you find out which of the two the regulator believes.

A double-entry ledger, append-only, no exceptions

Outstanding balance is not a column. It is SUM(postings) over a posting table that can never be changed. Every night, bank statements are matched against the ledger, and anything that does not match goes into an exception queue with a named owner and an SLA. Exceptions are normal. A system that reports zero exceptions is hiding them.

Decisioning as an explicit state machine

Application state (draft → kyc_pending → kyc_verified → underwriting → approved → mandate_pending → disbursed, plus every rejection and expiry path) is a clearly declared state machine, not a pile of if-else rules scattered across controllers. Every change is logged with who did it, when, and why. When an auditor asks "why was this application rejected on 14 March", the answer is a lookup, not an investigation.

KYC itself is Aadhaar OKYC plus DigiLocker plus PAN verification, run in parallel, with a video-KYC backup for the cases that fail automatic checks. Bank account details are penny-drop verified before mandate submission — which is where most of that 19% mandate failure rate was hiding.

Webhooks are hostile; treat them that way

Payment gateways retry. They send events out of order. They sometimes send the same event twice, months apart. A simple handler posts twice to the ledger, and in a lending book a repayment posted twice means a customer is told they owe less than they do. Every incoming event is checked for repeats using the provider's event ID, handled inside a transaction, and made safe to repeat at the posting level. Exactly-once is not something the network gives you. You have to build it.

Offline receipts that are still non-repudiable

Field agents collect in places with no signal. The collections app pre-issues blocks of cryptographically signed receipt numbers to each agent's device. A receipt written offline carries a number that could only have come from that device's own block, signed with its key. It can be checked when it syncs, and the agent cannot make one up. Trust is replaced by maths.

The compliance surface, done properly

Key Fact Statements made for each borrower in four languages. The required cool-off period is enforced by the state machine, not just by policy. Pre-debit notices go out at T-1 as NPCI requires. PII sits in an envelope-encrypted vault with tokens everywhere else. And data clean-up jobs really delete.

03

The outcome

The move put a live book of 14,000 loans onto the new ledger over one weekend. It was matched to the rupee against the bank before the switch was declared done. We had practised it three times on a copy of live data.

Results

  • KYC turnaround: 3 days → 11 minutes (P50). Running the checks in parallel is most of the gain. The rest is that automatic checks now settle 87% of applicants without a person ever looking. People look at the 13% where looking is worth the time.
  • Mandate success: 81% → 94.6%. Nearly all of that came from penny-drop checking the bank account before submitting the mandate, not after. It was about two days of work that had been waiting there for two years.
  • Reconciliation exceptions: 0.03% of postings, each with a named owner and an SLA. They now have a number for this. Before, they only had a feeling.
  • Zero rupees in transit through a PRS-controlled account. There is no such account. This was what the board cared about most, and it is the one we are proudest of, because it would have ended the company had it gone the other way.

What changed structurally

Their compliance officer can now answer a regulator's question about any loan in the book (every state, every change, every posting, every consent) from a screen, in front of the person asking. Before this, that answer took a week and a spreadsheet, and they only hoped it was right.

Field collection cost per ₹100 collected fell. The signed-receipt system removed the delay in matching cash and, with it, a kind of leakage nobody had wanted to talk about.

Under the hood

How it's built.

Technology

  • Laravel
  • PostgreSQL
  • Redis
  • Laravel Horizon
  • React Native
  • Aadhaar OKYC / DigiLocker
  • UPI Autopay & NACH
  • AWS KMS
  • Docker
  • Terraform

Services used

  • Fintech Software Development
  • Custom Software Development
  • Mobile App Development
  • API Integration
  • Cloud & DevOps

We hired them to make onboarding faster. In week two they told us our money flow would not survive an inspection, and stopped the project until we agreed to fix it first. Nobody else had even looked.

Karan Sethi Chief Technology Officer, Sahaj Credit

Same problem?

Let's build something that ships.