Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Low-Level Design (Object-Oriented Design)  Module 14 – Case studies: money and commerce

Low-level design: UPI-style payments and mandates

Design UPI-style collect requests and recurring mandates as state machines: approval, pre-debit notices, pause, revoke, expiry, retries and unknown bank codes.

  • Advanced
  • 40 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot
Free intro, Pro: 10 of 40 minutes free
Free: The prompt, the rules and the questions it must answer. With a pass: the other 11 sections and 3 interview answers, about 30 minutes.

What you will learn

  • Model collect and pay requests, mandates and executions as state machines
  • Handle pre-debit notification, pause, revoke and expiry
  • Store limits and timings in configuration that cites the official rules
  • Map every bank code through an adapter, sending unknown codes to review

Before you start

What you’ll learn · Before you start

What you will learn

  • Model collect and pay requests, mandates and executions as state machines
  • Handle pre-debit notification, pause, revoke and expiry
  • Store limits and timings in configuration that cites the official rules
  • Map every bank code through an adapter, sending unknown codes to review

Before you start

On this page

Designing real-time bank payments with mandates in a low-level design (LLD) round means modelling the merchant’s side of three requests. A pay request is started and approved by the payer at once. A collect request is sent by the merchant and lives until the payer approves it, declines it or lets it expire. A mandate is a standing permission to debit up to a maximum on a schedule, and each of its debits, an execution, is a state machine of its own: scheduled, then notified at least 24 hours before the debit, then debited, or failed after a limited retry. The payer can pause the mandate, opt out of one debit or revoke it all, and every code that comes back from the bank passes through an adapter, so a code nobody knows sends the debit to review instead of to success.

Not affiliated

Based on public information about NPCI. MySmartCoPilot is not affiliated with NPCI, and NPCI’s real systems may differ from what this lesson describes.

UPI and UPI AutoPay are what this design is modelled on

UPI is India’s real-time payment system, run by NPCI, and UPI AutoPay is its service for recurring mandates (NPCI). RBI’s e-mandate rules, which a circular extends to UPI (RBI), ask for the payer’s additional authentication, the UPI PIN, to register, change or revoke a mandate and for its first debit, and for a notice at least 24 hours before each later debit, naming the merchant, the amount, the date and a reference (RBI).

The prompt, the rules and the questions it must answer

The prompt: “Design the classes that a subscription business uses to collect money through a real-time bank payment network: one-off collect requests, and mandates that debit every month.” The rules that come out of the clarifying questions:

  • U1 A mandate debits nothing until the payer approves it, and that approval also authorises the first debit.
  • U2 Every later debit is notified at least 24 hours before it runs. A notice sent late moves the debit, never the other way round.
  • U3 A debit above the automatic limit for the mandate’s category waits for the payer to approve that debit.
  • U4 The payer can pause the mandate, opt out of one notified debit, or revoke the mandate. A pause skips the due dates inside it; a revoke cancels every debit not yet sent.
  • U5 A debit that fails for lack of money gets a set number of retries, each with a new notice.
  • U6 Each notice and each debit request goes out once per execution and attempt, however often the scheduler runs.
  • U7 Every bank code maps through an adapter; a code it does not know sends the execution to review.
  • U8 A collect request expires at its deadline, which the clock decides on every read; no timer fires.
  • U9 Limits and timings are configuration, and each value says which rule it comes from.
Two state machines: a mandate from created to active, paused and its final states, and each execution from scheduled to debited.a mandateeach execution of an active mandate:one debit on one due datecreatedpending_approvalactivepauseddeclined | revoked |expired | completed(final)schedulednotified24 h or more before the debitdebit_requesteddebited(final)skipped | cancelled |failed | needs_review(final)request sentto the payer's appapprovedwith the PINdeclinedpayer pausespause endsrevoked, validity over,or every debit donenotice, sent oncedebit daysuccessno funds,a retry leftpaused, ornot approvedopted outno retry left,unknown code

A mandate and its executions

Text description of the diagram

The diagram has two boxes, one above the other.

The upper box is the mandate. 1. It starts created, and sending the request to the payer's app makes it pending_approval. 2. Approval with the PIN makes it active; a decline ends it. 3. An active mandate can be paused by the payer and becomes active again when the pause ends. 4. An active mandate ends when it is revoked, when its validity is over, or when every planned debit is done. The final states are declined, revoked, expired and completed.

The lower box is one execution of an active mandate: the one debit of one due date. 1. It starts scheduled. Sending the notice, once, makes it notified, 24 hours or more before the debit. 2. On the debit day it becomes debit_requested. 3. Success makes it debited, which is final. "No funds" with a retry left sends it back to scheduled, for a new notice and a new debit day. 4. It can also end as skipped, cancelled, failed or needs_review: from scheduled, when the mandate is paused on its due day or an amount above the automatic limit is not approved; from notified, when the payer opts out; and from debit_requested, when no retry is left or the bank sends a code nobody knows.

The volumes are small for a computer and large for a mistake. Work out the first two answers before you check them.

Check yourself

4 questions about this lesson. Every answer and why it is right is on the page, behind “Show the answer”. Your score stays in this browser.

  1. Question 1 of 4 A subscription service has 400,000 mandates that all debit on the first day of the month. Its scheduler sends the notices between 06:00 and 12:00 on the day before. How many notices a second must it send on average?

    Type a number.

    Show the answer to question 1

    Answer: 18.5 notices a second (anything from 16.65 to 20.35 counts)

    Six hours are 21,600 seconds, and 400,000 ÷ 21,600 ≈ 18.5 notices a second. That is easy for one process, but the window matters: a scheduler that starts the run late, or stops halfway, must still leave 24 hours between each notice and its debit, so a late notice moves its debit to the next day.

  2. Question 2 of 4 Of those 400,000 debits, 8 % fail on the first try for lack of money. The design allows one retry, two days later, and half of the retries succeed. How many debits fail for good?

    Type a number.

    Show the answer to question 2

    Answer: 16000 debits (anything from 14400 to 17600 counts)

    8 % of 400,000 is 32,000 first-try failures. Each gets one retry, with its own notice, and half succeed, so 16,000 fail for good. The retries also add 32,000 notices, which the scheduler's capacity must allow for.

  3. Question 3 of 4 A payer pauses a monthly mandate for three weeks, and one due date falls inside the pause. What should happen to that execution?

    Choose one answer.

    Show the answer to question 3

    Answer: It is skipped, with no notice and no debit, and the mandate carries on after the pause.

    A pause is the payer's choice, not a failure, so nothing is retried and nothing is caught up later. The execution ends as skipped, and the next due date after the pause is notified and debited as usual.

  4. Question 4 of 4 The bank answers a debit with a code that the adapter has never seen. What should the execution become?

    Choose one answer.

    Show the answer to question 4

    Answer: needs_review, so that nobody treats it as paid or debits it again until the code is understood

    An unknown code could mean success, failure or still pending. Treating it as success could give a service that was never paid for; retrying could debit twice; ignoring it loses the bank's only answer. needs_review stops both mistakes until someone, or a status check, settles it.

The in-depth parts answer these questions in order:

  1. Which classes hold the two state machines, and where does each rule live?
  2. What happens, line by line, across 180 days of four mandates? The same scenario runs in Python and JavaScript.
  3. How do limits and timings stay in configuration that cites its rules?
  4. How does a collect request expire without a timer, and what changes once the payer has approved it?
  5. How does the adapter turn bank codes into events? An unknown code becomes a review, never a success.
  6. What separates an early-career answer from a staff-level one here, and how do you rehearse it against the clock?

The classes, and where each rule lives Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • 180 days of four mandates, replayed in Python and JavaScript
  • Limits and timings as configuration, each with its source
  • Collect requests that expire on an injected clock
  • Pay requests: the payer starts, the merchant waits for the outcome
  • The adapter: bank codes in, domain events out, unknown codes to review
  • Practise: changing a mandate’s maximum
    • Change a mandate's maximum only with the payer's approval
  • What each level is expected to cover
  • A 45-minute self-mock
  • Interview questions
    • What is the difference between a collect request and a mandate, and which would you use for a monthly subscription?
    • Your mandate scheduler was down for 30 hours, across the day on which notices for 200,000 debits should have gone out. What happens to those debits when it comes back, and how do you design the scheduler so that an outage like this is safe?
    • The bank starts answering 2 % of mandate debits with a result code your adapter has never seen. What should happen to those executions, and how do you find out what the code means without debiting anyone twice?
    • A payer pauses a mandate at 09:00:00, and at 09:00:01 your scheduler sends that mandate's debit request, whose notice went out the day before. Which wins, and how does your design make the outcome predictable?
  • Key takeaways

2 runnable examples (Python, mandate.mjs, mandate.py, rules.mjs, scenario.mjs) · 1 exercise with sample tests · 3 interview answers · about 23 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; nothing renews unless you choose to. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Read a complete sample first: Low-level design: parking lot (the model)

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.