What a mass payout is
A mass payout — also called a bulk or batch payout — disburses funds to many destinations as one logical job rather than as a sequence of individually triggered transfers. The sender provides a list where each entry names a recipient and an amount, and the platform turns each entry into a real payout. The grouping is for the sender's control; each recipient still gets a distinct, independent transfer.
Because the recipients are independent, the hard problem in any mass payout is partial failure. Some lines can go through while others do not — a destination address is malformed, a balance check fails, a network call times out. A well-behaved mass payout is not all-or-nothing at the transfer level: it lets the good lines settle and reports the bad ones precisely, so the sender re-runs only what is left rather than risking duplicates.
Why it matters for crypto payments
Crypto disbursements raise the stakes on partial failure, because an on-chain transfer that has settled cannot be clawed back. If a retry of a half-finished batch pays a recipient who was already paid, that money is gone. So the question is not just whether the platform can send many transfers, but whether the batch can be safely resent after a failure without paying anyone twice — retry-safety at the level of the individual recipient.
Recipients can also span chains and assets. One list might pay some recipients in USDT on Tron, others in USDC on Solana, others in native ETH — each line settles on its own rail with its own confirmation behaviour and fee characteristics. The batch is just an envelope; the real unit of truth is the single line, both for settlement and for retry.
Mass payouts on halfin
On halfin a mass payout is a fan-out over the single-payout API rather than a distinct batch endpoint. The sender posts to the payouts endpoint with multiple lines, and each line is treated as its own payout — its own destination, amount, asset, and chain. The key design point is that every line carries its own idempotency_key, supplied as a field in the request body, not as a header. Because the key is per line, resubmitting the whole list after a timeout does not pay any destination twice: lines that already succeeded are recognised by their keys and skipped, and only those that never landed are created.
Each line then follows halfin's normal payout lifecycle: a submitted payout enters a pending-approval state rather than releasing funds immediately, keeping a human or a policy in the loop before money leaves. As lines settle or fail, halfin emits HMAC-signed webhooks — payout.completed and payout.failed — so the integration learns each outcome without polling. The discipline is the same as for a single payout: reuse one stable idempotency_key per line on every retry, and verify the HMAC signature on each webhook before acting.
- Many recipients paid as one job; each recipient gets an independent transfer.
- The hard part is partial failure — good lines settle while bad ones are reported precisely, so only failures need re-running.
- On halfin it is a fan-out over the single-payout API, not a separate batch endpoint; each line is its own payout.
- Each line carries its own idempotency_key (a body field, not a header), so resubmitting the batch skips lines that already succeeded.
- Submitted payouts enter pending-approval; outcomes arrive as HMAC-signed payout.completed and payout.failed webhooks — verify the signature first.