Use case

Marketplace settlements: collect from buyers, pay out to sellers

A marketplace sits between two sides of a trade. A buyer pays for an order, the platform holds the money for a beat, and then a seller has to be paid their share — minus the marketplace's cut, on the schedule the platform sets, to whatever chain that seller actually uses. halfin covers all three legs from one account: hosted checkout takes the buyer's payment, a signed webhook tells your platform which order settled, and idempotent mass payouts release sellers their earnings without ever paying anyone twice.

01

Why a marketplace is harder than a store

A single-merchant store has one money flow: a customer pays, the store keeps the money. A marketplace has three parties and two flows that have to stay reconciled against each other. Money comes in from many buyers, attached to specific orders. Money goes out to many sellers, attached to specific earnings. The platform's own revenue is the gap between the two. If the inbound side and the outbound side ever drift apart, you are paying sellers for orders that were refunded, or holding funds you should have released, and the discrepancy compounds every settlement cycle.

The hard part is not taking the payment. It is keeping a clean ledger where every incoming payment maps to an order, every order maps to a seller's earnings, and every outgoing payout maps back to those earnings — through retries, refunds, and the inevitable run that crashes halfway. A naive integration that fires a transfer per seller in a loop loses that mapping the first time the script dies mid-run and someone re-runs the file.

halfin gives you the two primitives that make the marketplace ledger keep its shape: an invoice per order whose paid state arrives as a signed webhook (so the inbound side is auditable), and a payout per seller line whose idempotency key is derived from your own records (so the outbound side is safe to retry). Your platform owns the ledger that ties them together; halfin owns the on-chain mechanics underneath both.

02

The settlement cycle, leg by leg

Walk the lifecycle of one order through the platform. The buyer pays, your ledger records the order as funded, the order is fulfilled or the hold period elapses, and the seller's share is queued for the next payout run. Each leg has a halfin primitive behind it and a clear point where your platform takes a decision.

The redirect the buyer sees at the end of checkout is for their eyes. The signed webhook is what your server acts on — verify the HMAC signature, then mark the order funded and credit the seller's pending balance in your own ledger. Hold and release timing is your platform's policy, not halfin's; halfin just makes the inbound payment final and the outbound payment idempotent.

Leghalfin primitiveWhat your platform does
Buyer pays for an orderInvoice + hosted checkoutCreate an invoice for the order total in your catalogue currency; redirect the buyer to the returned checkout URL.
Payment settles on-chainSigned invoice webhookVerify the signature on invoice.paid; mark the order funded and credit the seller's pending earnings in your ledger.
Order is held or fulfilledYour ledger (platform policy)Apply your hold window, dispute window, and commission split. halfin holds the balance; the timing is yours.
Seller is paid their shareMass payoutsSubmit one payout line per seller with a deterministic idempotency_key; approve the run; reconcile against per-line status.
Buyer is refundedRefunds against the invoiceRefund the original invoice and reverse the seller's pending credit before it is paid out.
03

Collecting from buyers: one invoice per order

At checkout you create an invoice anchored to the order total in the fiat currency your prices already live in — USD, EUR, whatever your catalogue uses. The rate locks when the invoice activates, so a buyer who pays ten minutes later owes the exact crypto amount they were quoted, and a moving market does not turn a fully-priced order into an underpayment that strands the seller's earnings.

Redirect the buyer to the hosted checkout page. They pick a network they already hold funds on, see the amount, the QR code, and the deposit address; halfin watches the chain, applies that chain's confirmation threshold, and credits the payment in a reorg-aware way. When the invoice resolves, your server receives a signed webhook. That webhook is the moment the order becomes funded in your ledger — not the redirect, which the buyer can interrupt by closing the tab.

Because a confirmed on-chain payment is final, the marketplace is not exposed to card-style chargebacks reversing an order weeks after a seller has already been paid. Returns and goodwill become deliberate refunds your platform chooses to issue against the original invoice, which you reconcile by reversing the seller's pending credit — a decision you control, rather than a forced reversal you react to.

  • One invoice per order, anchored to the order total in your catalogue currency.
  • Rate locks at activation and the invoice expires if unpaid — no silent re-pricing.
  • invoice.paid arrives as an HMAC-signed webhook; verify it before crediting the seller's earnings.
  • Reorg-aware crediting with per-chain confirmation thresholds before an order counts as funded.
04

Reconciling at the order level, not the wallet level

The mistake that breaks marketplace accounting is reconciling on raw deposits — watching addresses and trying to guess which arriving payment belongs to which order. halfin's model is order-first: the invoice you created carries your order reference, and the webhook that fires when it settles carries the same invoice. Your platform matches the webhook to the order, not a stray deposit to a wallet.

Treat the canonical invoice events as the spine of your inbound ledger. invoice.confirming tells you a buyer's payment window has opened; invoice.paid tells you the order is funded and the seller's share can be credited; invoice.underpaid and invoice.overpaid surface a buyer who sent the wrong amount, so your platform can decide whether to hold, request a top-up, or refund the difference before any seller is paid; invoice.expired tells you the window closed unpaid and the order should be released. Every one of these is HMAC-signed — verify the signature before you act on it, because acting on an unverified webhook is how a forged event credits a seller for an order that never settled.

Underpaid and overpaid are where marketplaces get burned if they ignore them. A buyer who sends slightly too little has not funded the order, and crediting the seller off a bare deposit notification would leave the platform short. Because halfin records expected-versus-received against the invoice and surfaces the gap as a typed event, your reconciliation can hold the seller's credit until the order is genuinely whole.

05

Paying sellers: one idempotent run, mixed chains

On settlement day your platform has a list: each seller, their net earnings for the period, and the address and asset they want to be paid in. That is a mass payout — a fan-out over the single-payout API where each line carries currency, amount as a string, destination, and its own idempotency_key. There is no separate batch endpoint; the run is a loop, and the keys are what make the loop safe to interrupt.

Derive each key deterministically from your own ledger — the seller's account id joined with the settlement period is the usual shape — so re-submitting the run reproduces the same keys. If the process dies on seller 240 of 600, you re-run the whole file: the 239 already paid come back as no-ops, and only the missing lines execute. No double-pays, no manual picking-up-from-where-it-crashed, no spreadsheet of who-got-what reconstructed under time pressure.

Sellers don't share a chain preference, and a marketplace spanning regions can't force one on them. One run can pay a seller in USDT on Tron, another in USDC on Base, and a third in native SOL, each line choosing its own currency and network. Payouts enter a pending-approval state and are released from the dashboard, so your integration can stage the entire run unattended and a treasurer still approves once before anything leaves the platform's balance. Settlement is reorg-aware with per-chain confirmation thresholds, so a per-seller status of complete means settled, not merely broadcast.

# Settlement run: one payout per seller, each line idempotent.
# Re-running after a crash is safe — keys collide, nobody is paid twice.
while IFS=, read -r seller_id currency amount destination; do
  curl -sS -X POST https://api.thehalfin.com/api/v1/payouts \
    -H "Content-Type: application/json" \
    -H "X-API-Key: $HALFIN_API_KEY" \
    -d "{
      \"currency\": \"$currency\",
      \"amount\": \"$amount\",
      \"destination\": \"$destination\",
      \"idempotency_key\": \"settle-2026-06-$seller_id\"
    }"
done < sellers.csv
# Each key is derived from your own ledger (seller id + period), so the
# same seller in the same run always maps to one payout. payout.completed
# arrives as a signed webhook. See docs.thehalfin.com for the full schema.
06

Keeping the two sides reconciled

The marketplace ledger only stays honest if the inbound and outbound sides reference the same records. Because invoice.paid carries the invoice tied to your order, and each payout line's idempotency_key is derived from the seller earnings that order produced, you can trace a single dollar from the buyer who paid it to the seller who received it — and prove the platform's cut is the difference. That trace is what an audit, a dispute, or a tax filing needs.

Refunds are the case that ties both sides together. When a buyer is refunded, the refund runs against the original invoice, and your platform reverses the seller's pending credit so it is never included in a payout run. Refund a credit that has already been paid out and you are chasing the seller for clawback; the order-level ledger is what lets you catch it inside the hold window instead. halfin gives you final inbound payments, idempotent outbound payments, and a signed event on each — your platform owns the policy that decides hold periods, commission splits, and when a seller's earnings become payable.

  • Trace every order from the buyer's invoice to the seller's payout via shared references.
  • Reverse a seller's pending credit on refund before it enters a payout run.
  • Hold windows, commission splits, and payout cadence are your platform's policy, not halfin's.
  • Inbound finality + outbound idempotency + signed events on both = a ledger that reconciles.