The first interface over a payment system that couldn't be changed
The hard part was not designing the interface. It was understanding a payment system I was not allowed to change.
Overview
A marketplace of 200+ vendors paid out after customers received their orders. Between the delivery and the money landing sat commissions, returns, approvals, TDS and TCS deductions, and bank transfers — separate processes that all moved the same number.
The payment logic already existed in the backend. The interface did not. Around 50 people ran payment eligibility, approval and transfer state in spreadsheets, alongside a system that already knew all of it.
The job was not redesigning a dashboard. It was building the first interface over a financial system that had never had one, without changing a line of how it worked.
- Domain
- Marketplace payment operations
- Users
- 200+ vendors · 50+ internal · four consoles
- Consoles
- Vendor · Marketplace · Logistics · Accounts
- Role
- Designed all four. Research, workflow, information architecture, screens, review cycles.
- Constraint
- The backend already existed and its behaviour was fixed. Every design decision had to fit a data model nobody was going to change.
- Time
- About a week from first look to reviewed screens, then revision passes
- Year
- 2026
- Shipped
- Yes. Nothing was instrumented, so this study describes what changed operationally and claims no percentages.
Project
Marketplace payment operations
Four consoles over a payment system that already worked and had no interface at all.
Role
All four consoles, end to end
Research, workflow, information architecture, screens and review cycles, inside a fixed data model.
Outcome
Two sets of numbers → one record
The calculation happens once, and the vendor and the marketplace read the same record instead of reconciling by hand.
The problem
There was no interface for any of it. That is the actual problem — not an outdated interface, no interface. Payment eligibility, approval, and transfer state all lived in files that were copied, emailed, and edited by hand.
It produced the failure that eventually paid for the work: the balance sheet did not reconcile. Amounts calculated by hand, in files, by different people, did not agree with what the system held.
That is why the project existed — to have the calculation happen once, automatically, and to let vendors and the marketplace look at the same number instead of two versions of it. Transparency here is not a value statement. It means the vendor and the admin are reading the same record, so there is nothing to reconcile between them.
Fig 1Money path
Delivery is the financial trigger. Returns re-enter the ledger as their own negative record rather than editing anything upstream.
Order placed
Delivered
Financial triggerNothing before this pays.
Eligible for payout
Commission, TDS, TCS deducted.
Approved
Marketplace managementTransferred
AccountsVendor balance
↺ Return
Posts as its own negative record against the balance. The original order is never edited.
Who used it
Four consoles, authority deliberately split so no role can move money alone.
- 01
- Marketplace managementVerify which delivered orders are eligible to pay, configure commissions and permissions. Approves; cannot transfer.
- 02
- LogisticsAssign couriers, update delivery status, resolve misroutes. Owns whether an order counts as delivered, which is what makes it payable.
- 03
- AccountsRelease transfers, retry failures, reverse. Cannot change business rules.
- 04
- VendorsSee what they earned, what was deducted, what is coming. Approve nothing.
Logistics is the load-bearing one and the least obvious. Delivery status is the event that makes money owed, so a courier update is a financial trigger. The separation only holds because logistics cannot see or touch payment.
Fig 2Permission matrix
No row holds both Approve and Transfer. That is the whole control.
| Console | Can | Cannot |
|---|---|---|
| Marketplace | Approve a payment. Set commissions. | Transfer money. |
| Logistics | Mark an order delivered — the event that makes money owed. | See or touch payment at all. |
| Accounts | Transfer, retry, reverse. | Approve. Change a business rule. |
| Vendor | Read their own ledger. | Approve anything. |
The real constraint
I did not design the payment system. It existed, it worked, and it was not going to change for me.
So the job was inversion of the usual one: instead of deciding how the system should behave and asking engineering to build it, I had to read how it already behaved and decide what an honest interface for that looks like.
Most of the week went on understanding, not drawing. Commissions, returns, approvals, and transfers appeared to be four processes. They are one number, recalculated. Every return immediately changes what a vendor is owed, which changes the next transfer, which changes the balance after it.
Once that was clear, the screens mostly fell out of it.
A note on vocabulary
Several things I had logged as interface problems turned out to be vocabulary problems. Internal finance language had leaked into screens used by people who did not share it — the same number described in accounting terms to a vendor who only wanted to know what was coming.
The clearest case was the vendor’s headline figure, labelled Pending Payable. Payable and receivable are the same money seen from opposite sides of the ledger: payable is what the marketplace owes, receivable is what the vendor expects. The client asked for Receivable, which was right — the vendor is the one with no other way to check the number.
Worth recording because the fix cost nothing and the problem was invisible until someone said the word out loud. A meaningful share of what looked like confusing design was confusing language.
Decisions
Two that were mine, and what each cost.
Not inventing an object the system does not have
Transfers happen in batches, so I designed a Settlement object to group them — a record you could open, name, and refer to.
Then I took it out. The backend is order-based. Every question a settlement could answer, orders already answered. Introducing it in the interface would have created a thing users could see and talk about that did not exist in the data, and the first time the two disagreed, the interface would be lying.
Cost
The interface does grouping work the data model refuses to do. Transfers display as batches that exist nowhere as records. More view logic, and a permanent risk of drift between what is shown and what is stored.
Why that was the right trade
An auditor follows orders. A vendor disputing an amount follows orders. A concept that exists only on screen has to be maintained by hand forever, and eventually somebody reconciles against it.
Fig 3Rejected, then current
The rejected version looks tidier. That is the trap: it groups cleanly on screen and has nothing behind it.
Rejected
- Settlement #4821
- Order 1194
- Order 1207
- Order 1213
A record you can open, name and refer to. Exists nowhere in the data.
Current
- Transfer batch (a view)
- Order 1194
- Order 1207
- Order 1213
No record. The grouping is drawn from the orders and exists only while displayed.
Showing the negative balance instead of hiding it
The system posts a return as its own negative record and never edits the original order. If that pushes a vendor below zero, no transfer releases until later orders bring the balance back up.
That rule was not my decision. What to do about it on screen was.
I could have shown zero and explained later, or shown the balance only once it turned positive again, or split it into a separate adjustments area away from the main number. All of those make the screen calmer and the vendor’s understanding worse.
The transfer queue shows -₹6,091 in red on a row marked Processed. The vendor’s transaction history shows the return as its own line with its own negative value. Nothing is netted out before the user sees it.
Cost
A vendor with one large return sees a negative number, receives nothing that cycle, and had no say in it. That is a real harm to a real business, and the interface delivers the news.
Why
The alternative is a number that does not match reality, and a vendor who cannot reconcile their own payments has to ask someone every time. A confusing number can be explained in a minute. A wrong one takes weeks to unwind, and costs trust that does not come back.
Fig 4Ledger arithmetic
The same event from the vendor’s side, and the blocked case beside it. A blocked cycle generates no transfer record at all; a ₹0 row would imply a payment happened.
| Vendor transaction history | Paid cycle | Blocked cycle |
|---|---|---|
| Delivered orders | ₹ 18,400 | ₹ 4,100 |
| Commission, TDS, TCS | -₹ 2,209 | -₹ 492 |
| Return posted | — | -₹ 9,699 |
| Balance | ₹ 16,191 | -₹ 6,091 |
| Transfer record | ₹ 16,191 | none generated |
Making the state machine visible
Six payment states — created, pending, processed, partially reversed, reversed, failed — plus transfer states of pending, initiated, completed, failed, and manually processed.
Fig 5Payment states
A spreadsheet column holds exactly one of these at a time, typed by hand.
Resolves itself · 6
Moves on its own. Shown as a status, counted on the dashboard, and otherwise left alone.
- created
- pending
- processed
- initiated
- completed
- transfer pending
Needs a person · 5
Stops until someone acts. Each one gets a filter tab on the transfer queue and a line in Needs Attention.
- failed
- reversed
- partially reversed
- transfer failed
- manually processed
Spreadsheets flatten all of that into a column somebody types into. The consoles surface it: status counts on the dashboard, filter tabs across the transfer queue for ready, sync failed, reversed, manual, processed.
The Needs Attention panel on the vendor dashboard exists for the same reason — reversed payments, failed delivery syncs, misroutes, missing wallet details. The states that need a human, pulled out of the states that do not.
The edges
Most of the design is in what happens when things do not go straight through.
Transfers that fail. Sync failures get their own tab in the transfer queue rather than a flag on a row, because the recovery action is different — retry, or fall back to a manual transfer that is recorded as manual. A payment made outside the automated path still has to appear in the same ledger, marked as what it was.
Reversals after processing. A processed payment can be reversed, and partially reversed is its own state rather than a special case of either. The vendor is told directly — the reversal appears in Needs Attention with the amount and a link to the transaction, instead of the balance quietly changing.
Delivery going wrong. Logistics owns delivery status, and delivery status is what makes an order payable, so a courier problem is a payment problem. A misroute is recorded as a transition with its cause attached — In Transit → Misrouted · Reason: courier reported wrong hub — not as a status that silently flips. Courier data arrives from an external system, so a fetch is itself a logged event; when the sync is stale, the vendor sees how stale.
Bulk actions. Operations approve in bulk — 18 orders in one action — and the audit log keeps every one. The entry expands to list each invoice individually and links back to the orders. A bulk action is one decision and eighteen records; collapsing that into a single line would break the trail exactly where it matters most.
Missing payout details. A vendor with no wallet on file is told before a payment is attempted, not after one fails.
The audit log is read-only and says so on the screen. Filterable by user, event, vendor and date. It is not a debugging tool — it is the answer to “who did this, and what did they see when they did it.”
Two edges were not designed, and both involve an approval that has already happened. A pending approval has no owner if the approver leaves — nothing reassigns it or expires it. And an approved order that is later returned posts the adjustment without touching the approval, so the record says approved for an amount that no longer exists.
Neither breaks the ledger. Both leave a human looking at something that reads as settled and is not.
What changed
The spreadsheets stopped.
Not immediately — there was a period where people ran both, checking the consoles against the files they trusted. That is the normal shape of replacing a tool somebody has relied on for years, and it is the part worth reporting honestly. Once the numbers agreed often enough, the files were abandoned.
Nothing was instrumented, so there are no figures. What can be said is that the calculation now happens in one place, the vendor and the marketplace read the same record, and the reconciliation that used to be done by hand between two sets of numbers no longer has two sets of numbers to reconcile.
What I would do differently
The negative balance is where the design stops short.
Showing a number honestly is not the same as helping someone act on it, and the data needed to do that was already there. A vendor whose balance goes below zero finds out by opening the dashboard. There is no warning before a return posts, and nothing on the screen answers the question they will immediately have: when do payments start again.
Both are answerable from data the system already holds. A return is known before it settles, so the vendor could be told it is coming. The balance and the pipeline of eligible orders are both known, so a projected recovery point could be estimated and shown with appropriate hedging.
The design served the marketplace’s need to be correct and stopped one step short of the vendor’s need to plan. Those are not in conflict — the second one just did not get built.
The two undesigned edges have the same shape. An abandoned approval and an approval that outlives its own amount both leave someone reading a record that looks settled and is not. In a week I got the money right and did not get to what happens when a person steps out of the middle of it. That is the next thing I would build.
What the work rests on
Six rules, each of which cost something earlier in this study.
- 01Never hide a financial truth. A negative balance is shown negative. No netting before display, no ₹0 transfer standing in for a payment that did not happen.
- 02Match the word to the reader, not to the ledger. Payable and receivable are the same money. The vendor gets the one they can act on.
- 03The interface may not invent objects the data does not have. Grouping can be a view. It cannot be a record users can name and refer to.
- 04Every financial event is traceable to an order. A bulk approval is one decision and eighteen records, and the log keeps eighteen.
- 05Authority is split so no role can move money alone. Approve and transfer never sit in the same seat.
- 06Exceptional states get their own surface. Failures, reversals and misroutes are tabs and panels, not flags on a row.