Skip to content

Build1 publisher3 min readPublished

The payout trigger is a balance-sheet decision, not a timestamp you happen to have

An engineer's account of a multi-vendor settlement service argues that crediting vendors on payment success converts every ordinary refund into a collections job.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying The payout trigger is a balance-sheet decision, not a timestamp you happen to have
Generated illustration

What happened

  • Crediting a vendor's share to their payout balance the moment the buyer's card is charged looks reasonable, because paid_at is already a timestamp on the order, but in a marketplace with real buyers and returns it is the most expensive line of code you can write.
  • The author states he built the settlement service for a multi-vendor platform around the opposite anchor: bill a vendor only after the order is delivered and the return window has closed.
  • The reason given for the delivery-plus-window anchor is not academic purity about escrow, but that the paid_at alternative turns every post-payment refund into a collections problem; a refund is not just a database correction.
  • In the system described, 'billed' is what makes a bill eligible to be locked into a payout and paid out, so by the time a buyer returns an item three days later the money may already have left the platform and landed in the vendor's bank account.
  • Under a paid_at anchor, a refund cannot just flip a status column; the options become chasing the vendor for money back, netting it against whatever they are owed next cycle, or eating the loss.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A writeup on dev.to makes a narrow but load-bearing claim: the most expensive line of code in a marketplace is the one that credits a vendor's share the instant the buyer's card clears [1]. The author, who says he built the settlement service for a multi-vendor platform on the opposite anchor, frames it as a money question rather than an architectural preference: paid_at as the settlement trigger commits the platform to a promise that a refund is only a database correction, and it isn't [2][3].

The mechanism is worth spelling out because it is boring and therefore easy to ship. In that system, "billed" is the state that makes a bill eligible to be locked into a payout and paid, so by the time a buyer returns an item three days later, the money may already have left the platform and landed in the vendor's bank account [4]. At that point the refund cannot flip a status column. The remaining options are chasing the vendor for the money, netting it against whatever they are owed next cycle, or absorbing the loss [5]. According to the author, none of those are database operations; they are accounts-receivable operations involving a second party who did nothing wrong and may not welcome a clawback request [6].

The instinctive patch is to keep the payment-success anchor and hold payouts for a grace period afterwards. The post's objection is that this re-derives a return-window anchor through the back door and does it badly, because you now run two clocks, billing and payout eligibility, both tracking the same real-world fact, and they can drift apart [7]. One clock is cheaper to reason about [8].

So the anchor is delivered_at plus a configured RETURN_WINDOW: a sub-order becomes billable only once it has been marked delivered and the window has elapsed with nothing excluding it [9]. The sweeper's selection requires three things to hold at once: bill_id IS NULL, excluded = FALSE, and delivered_at set and older than now minus the interval [10]. Batches are claimed with ORDER BY id, LIMIT, and FOR UPDATE SKIP LOCKED, so a second concurrent sweeper splits the batch rather than contending for the same rows, the same posture the platform's inventory timeout scanner uses [11]. Before those conditions hold, the platform is holding the cash, not provisionally crediting it [12].

The payoff is what a refund inside the window costs. It does not reach into a payout to reverse anything; it sets excluded = TRUE on a row that was never going to be billed, guarded by bill_id IS NULL AND excluded = FALSE [13]. If a refund event arrives after the sweep has already generated a bill, from a misconfigured return window or a slow consumer, the update matches nothing and affects zero rows [14]. The author's stated reasoning is that this case belongs to reconciliation to flag, not to the refund consumer to hide [15]. Note that the exclusion guard filters on the same two columns the billable query filters on, which is why one boolean is sufficient rather than a second coordination path [16].

What to watch, if you run something like this: the zero-row return from that exclusion update is your only cheap signal that refunds are outrunning your billing sweep, which means it needs a counter and an alarm rather than a log line. The other thing to watch is delivered_at itself, since moving the anchor onto delivery makes the accuracy of that field, and the configured window value, the things that decide when money becomes irreversible [9][14].

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories