Skip to content
PRS India

RBI · UPI/NPCI · eKYC · PCI-DSS

Fintech Software Development

In fintech a bug is a reconciliation break. We build double-entry ledgers that match the bank every day. Our UPI integrations handle the ways the UPI system really fails. We build KYC as clear steps from the first sprint.

Last updated

  • Double-entry ledger, append-only
  • Daily automated bank reconciliation
  • Idempotent UPI with status sweeps
  • PCI scope kept at zero
The real problem

A balance is not a column. It is a consequence.

The most common thing we are called in to fix in fintech is a product where the user's balance is just a number in a table. It gets updated inside a transaction. Somebody writes a data fix to correct a mismatch. Within a year the total of the balances does not match the money in the bank. A stored balance has no history, so nobody can say why. A balance is the sum of a double-entry ledger that can never be changed, only added to. A correction is a new reversing entry, never an edit. You can work out any account's balance at any moment in the past. It is matched against the bank statement every day, automatically, with an alarm on any mismatch. We build that first — before the app, before sign-up, before anything a founder wants to show. Everything else in a fintech product depends on the money being provably correct.

Talk about your product
0
Unexplained breaks

Every day we match the books to the bank statement, automatically. A mismatch raises an alarm. It does not wait to be found at month end.

100%
Idempotent writes

Every payment request carries an idempotency key. A retry cannot debit twice. That is the bug you cannot say sorry for.

T+0
Reconciliation cycle

Against the NPCI settlement file. A payment succeeding and the money arriving are two different events — we track both.

0
PCI scope

No card number ever touches your servers. We use tokens and hosted fields. PCI becomes a questionnaire instead of a big project.

What fintech engineering actually demands

Fintech is the one domain where a bug is not a bug. It is a reconciliation break, a regulatory breach, or somebody's salary that did not arrive. The way we build is different, and it starts before the first line of code with a question most teams answer too late: what licence are you working under, and whose?

Every rupee is double-entry. There is no shortcut.

The most common design failure we are called in to fix is a fintech product where the balance is a column on the users table. It gets updated in a transaction, somebody writes a data fix for a mismatch, and within a year nobody can explain why the total of the balances does not match the money in the bank.

A balance is not a number you store. It is the sum of a ledger that can never be changed. Every movement of value is a double-sided entry, entries can only be added, and a correction is a reversing entry that leaves the original safe and visible. For any account at any moment in the past, the system must work out a balance from its entries. That balance must match the bank statement, every single day, automatically, with an alarm on any mismatch. This is not optional and it is not something you add in year two.

UPI is not a payment gateway

UPI is a bank-to-bank rail, and it fails in its own ways. A collect request can be approved by the user thirty seconds after your system timed it out. A callback can arrive twice, or never. A transaction can sit in a state where you cannot be sure it worked or failed — and the only right action is to keep asking for the status, waiting a little longer each time, until the rail tells you.

So: idempotency keys on every request, so a retry cannot debit twice. A status check job that sweeps pending transactions instead of waiting for callbacks to arrive. Never mark a payment successful on a callback alone; check with the rail. And match the money against the NPCI settlement file, because a payment succeeding and the money arriving are two different events, a day apart and sometimes split by a dispute.

KYC has tiers, and the tier decides the product

eKYC through Aadhaar has limits on who may use it and how. Video KYC has a process set by RBI with recording, geotagging and a real person. Minimum KYC limits what a wallet may hold and what it may do. CKYC lets you fetch an existing record instead of collecting it again.

These are product decisions dressed up as rules, and they must be made before design, not during it. A wallet whose limits change when a user completes full KYC needs that built as clear steps from the first sprint. Adding it later means changing every transaction path in the code, and you will miss one.

The unglamorous rest

Data localisation: payment data stays in India, full stop. PCI-DSS scope, kept small by never touching a card number — use tokens and the gateway's hosted fields, and keep your servers out of scope entirely. Audit logs that can only be added to and that an engineer with live-system access cannot edit. Separate environments with test rails. And a guide for the day the rail is down, because it will be, and "we will figure it out then" is not a plan when money is on the way.

Modules

What we build into a fintech platform.

Double-entry ledger

Never changed, only added to, every movement double-sided. Balances worked out, never stored. Corrections are reversing entries.

Reconciliation engine

Daily automatic matching against bank statements and NPCI settlement files, with an alarm on every mismatch we cannot explain.

UPI and payment rails

Idempotency keys, status check jobs for payments that are not clear, and never taking a callback as proof of success.

KYC state machine

Minimum, full eKYC, video KYC and CKYC fetch — built as clear steps where limits and permissions follow the tier.

Risk and fraud rules

Speed checks, device fingerprinting, a rules engine an analyst can edit without a new release, and a queue of cases for review.

Onboarding and consent

Aadhaar eKYC, PAN and bank penny-drop verification, with drop-off measured at every step, because that is where CAC is decided.

Regulatory reporting

The reports the regulator asks for, made from the ledger and not put together by hand in a spreadsheet the night before.

Operations console

Two-person approval on every manual change, a full audit trail, dispute handling and a refund flow that cannot be run twice.

Customer app

Biometric unlock, certificate pinning, no sensitive data stored on the phone, and security built to pass a review.

India, specifically

The regulatory surface, stated plainly.

None of this is advice from a compliance consultant. It is what the rules mean for how we build, and we have built to these rules before.

  • RBI data localisation

    Payment system data stays in India. That includes an overseas error tracker that logs full request data, which is where teams quietly fail an audit.

  • PCI-DSS, scoped to zero

    Tokens and hosted fields keep card numbers off your servers entirely, which turns PCI from a big project into a questionnaire.

  • KYC tiers and limits

    Minimum KYC, full eKYC, video KYC set by RBI with recording and geotag, CKYC fetch. The tier decides what the product may do.

  • UPI / NPCI rails

    Idempotency, status checks, settlement file matching. A payment succeeding and the money arriving are separate events.

  • Audit trails that hold

    Only added to, and not editable by an engineer with live-system access. If your audit log is a table someone can UPDATE, it is not an audit log.

  • Secrets and key management

    A managed vault, regular key changes, and no credentials in environment files or CI logs. Assume the code repository will leak one day and plan for it.

The metrics that matter

What a fintech board asks about.

Uptime is the basic minimum and nobody will thank you for it. These are the numbers that decide whether the business works. Every one of them should come from the ledger without anyone opening a spreadsheet.

Talk to us
94%
Payment success rate

By rail, by bank, by hour. A drop on one issuing bank is a warning sign, not noise, and it should alert somebody.

2.1%
KYC drop-off

Per step, not overall. The step that leaks is where the cost of winning a customer is really set.

<0.01
Reconciliation breaks

And every one of them is looked into. A mismatch you put up with becomes a habit.

11min
Dispute first response

Median. A customer whose money is missing is not checking your uptime.

Does your balance tie out to the bank today?

Not at month end — today, automatically, with an alarm if it does not. If that question makes you uncomfortable, it is the right time to talk. It is much cheaper to fix now than after you hold live customer balances.

The stack

Built on tools that will still be here in five years.

  • Laravel
  • Node.js
  • PostgreSQL
  • Redis
  • Kafka
  • UPI / NPCI
  • Razorpay
  • Cashfree
  • Aadhaar eKYC
  • CKYC
  • Karza / Signzy
  • AWS (India region)
  • HashiCorp Vault

FAQ

The questions you were going to ask on the call.

You can, and it will work for about a year. Then the total of your balances will not match the money in your bank account. A stored balance has no history, so nobody will be able to explain why. A balance is the sum of a double-entry ledger that is never changed. Entries are only added, and a correction is a reversing entry that leaves the original visible. That is what lets you work out any account's balance at any point in the past. It also lets you match it to the bank statement daily, automatically, with an alarm on any mismatch.

Teams treat it like a card gateway and it is not — it is a bank-to-bank rail that fails in its own ways. A collect request gets approved thirty seconds after you timed it out. A callback arrives twice, or never. A transaction sits in a state where it is not clear if it worked, and guessing success or failure are both unsafe. The fixes are plain: idempotency keys so a retry cannot double-debit, a status check job that sweeps pending transactions instead of trusting callbacks, never marking success on a callback alone, and matching the settlement against the NPCI file.

That is a product question before it is a rules question, and it has to be answered before design, not during it. Minimum KYC limits what a wallet may hold and do. Full KYC via Aadhaar eKYC has limits on who may use it. Video KYC follows a process set by RBI with recording, geotagging and a live person. CKYC lets you fetch an existing record instead of collecting it again. If your product's limits change as a user moves up a tier, that must be built as clear steps from sprint one. Adding it later means changing every transaction path, and you will miss one.

By never letting a card number touch your servers. Tokens, the gateway's hosted fields or iframe, and saved-card tokens held by the gateway and not by you. That keeps your servers out of scope. It turns PCI from a big project that costs lakhs and takes months into a self-check questionnaire. If scope is truly unavoidable, we will tell you plainly what it costs, but most products do not need it.

Payment system data stays in India. We put your system on servers in India, keep backups in the country, and are careful about which outside services ever see payment data. An overseas analytics SDK or an error tracker with full request data is a quiet breach that shows up during an audit, not before. We also keep secrets in a managed vault and not in config files. Audit logs can only be added to, so an engineer with live-system access cannot change them.

A focused product — ledger, KYC, one payment rail, an admin and reconciliation — is typically 20 to 30 weeks and starts around ₹30,00,000. We build the ledger and reconciliation first, before any feature users see, because everything else depends on the money being provably correct. It is not the order founders want. It is the order that means you are not rebuilding the core in year two while holding live customer balances.

Let's talk fintech software development

Bring us the hard version of the problem.

A senior engineer reads every enquiry. You'll get a real answer — scope, risk and a number — within one business day.