etzee

What happens to money inside Metzee

Holds, claims, and why a refund can only happen once. Including the bug that taught us to do it this way.

The Metzee team20 Oct 20263 min read

Money is the one part of a marketplace where being nearly right is the same as being wrong. This is how it is arranged, and one thing we got wrong.

The shape of it

A buyer pays. The money is held rather than passed on. The seller sends the item. The money becomes the seller's 24 hours after it arrives, and is paid out to their bank from there.

The hold is the whole structure. It is what makes a buyer safe to buy from somebody they have never heard of, and it is the thing a private transfer cannot offer either side.

Every step that moves money claims it first

This is the rule the rest of it hangs on: before anything sends, refunds or pays out, it writes down in the database that it is doing so — and if something else already claimed that work, it stops.

It sounds like bookkeeping. It is the difference between a system that is safe and one that merely looks safe when you test it by hand.

The bug, specifically

Refunding used to read how much had already gone back, work out what was still owed, and then send it. Written down like that it looks fine, and the comment in the code said nothing could send money twice.

It was true of one process running twice in a row. That is not the situation. The scheduled job fires every minute without waiting for the last run to finish, so two sweeps overlap the moment a run takes more than a minute. A buyer cancelling a paid order starts a refund immediately, while the sweep is picking up exactly the orders that have just been cancelled. And a staff refund is an ordinary button.

Two of those reading before either wrote, and both believe the whole amount is still owed. Both send it.

Measured, in a test written to provoke it: ₹3,000 refunded against a ₹1,500 payment, and ₹1,000 against a ₹2,000 one in two ₹500 halves. A full refund has a backstop, because the payment provider refuses more than the payment. A partial one has none.

What fixed it

The decision moved into the database. It takes a lock on the order, adds up everything that has already gone back, and inserts the new refund only if it still fits. Two overlapping attempts no longer both pass, because the second one is answered after the first is already recorded.

The ceiling itself is still worked out in one place in the application and handed down. The database enforces a number it is given and never learns what the number means, so the rule cannot quietly come to exist in two places and disagree with itself.

The quieter failure

A payment can succeed and the work after it can be cut off part way — committing the stock, issuing the invoice, telling the seller. The money is not at risk there; the order is paid. What is at risk is a shop that oversells, an invoice that was never issued, and a seller who was never told.

So the finishing of that work is marked when it completes, and anything unfinished is reported to staff. It tells somebody; it does not retry. The one step that must never run twice is committing the stock, and a retry is exactly how that happens twice.

Questions people ask

Can I be refunded twice by accident?

No. A refund is accepted only if it still fits inside what you paid.

Why is the seller's money held after delivery?

24 hours, so that a problem found on arrival is still a problem with money behind it.

Who can move money by hand?

Staff, and the larger actions need a second person to approve them.

More: how we handle your money, why we hold the money, how refunds work, what the balance is.

← All posts

There is a show on right now.

Nothing to install — it runs in this browser.

Find a showCreate an account