Product
Payouts that do not surprise you
One address or a thousand, once or on a schedule. Every route ends at the same reviewed withdrawal path, and none of them puts a transaction on a chain without a person deciding to.
Three shapes
Single, bulk, scheduled
Different front doors, one hallway. A batch row and a scheduled run both become an ordinary withdrawal, so they inherit every control on that path rather than reimplementing it badly.
Single send
Choose the asset, paste the address, confirm with your authenticator code. The address is checked against the shape that chain uses — including the EIP-55 checksum on Ethereum and Polygon — before anything is reserved.
Bulk batch
Up to 1,000 recipients pasted or uploaded as CSV. One approval covers the batch; every row carries its own status afterwards.
Scheduled payout
Daily, weekly or monthly to a fixed address, with an optional cap on the number of runs. Each occurrence gets its own idempotency key, so a scheduler that double-fires still pays once.
Checks live in the service, not the screen
Suspended account, inactive asset, amount below the asset minimum, precision the chain cannot represent, an address that is really one of our own deposit addresses — all refused in the code every path calls. A control that only exists in the API middleware is not a control, because a scheduled run does not pass through middleware.
The fee is on top, and estimated live
Network fees are estimated from current conditions with a safety margin, floored at the asset's configured minimum, and added to the amount rather than taken out of it. A batch of 200 recipients pays 200 network fees.
Bulk batches
One line per recipient
Three columns, the third optional. Comments and blank lines are skipped; a malformed line is rejected with its number rather than guessed at.
# one line per recipient: address,amount,reference
bc1q-first-recipient-address,0.0125,invoice-1042
bc1q-second-recipient-address,0.004,march-retainer
bc1q-third-recipient-address,0.25
How a line is read
-
addressValidated for the batch's chain before the batch is accepted. The same address twice in one file is rejected, with both line numbers — a duplicated row in a payroll is far more often a copy-paste than an intention.
-
amountA dot for the decimal point and no thousands separators. "1,000.5" is refused, never repaired: split across fields it could mean 1000.5 or two columns, and guessing pays somebody a thousand times wrong.
-
referenceOptional, and carried onto that payout row so you can reconcile it against your own records afterwards.
A line starting with # is a comment.
A spreadsheet header row is skipped if it is the first line. Up to
1,000 rows per batch.
The whole total is checked before the batch is accepted — against your available balance, minus anything already committed to batches that have not yet been paid. Discovering on row 400 that the balance had run out would leave 399 payments on chain and the rest stranded, and two batches of 9.9 against a balance of 10 would each look affordable on their own.
Approval
Created, approved, broadcast
Three distinct steps performed by more than one party. Collapsing them into one button is how a payroll goes out twice.
Created
pending_approval
The rows are validated, the total is checked, and the batch is written down. Nothing has moved and nothing has been sent. An idempotency key is required, and reusing one with a different set of rows is refused rather than silently returning the earlier batch — being told "created" while your actual payroll was discarded is the worst outcome available.
Approved
approved
Someone with the approval permission signs off on the batch as a unit. Rows are never re-judged individually afterwards: that loophole let a large total be split into many small rows that each slipped under an auto-approval threshold.
Broadcast
processing
Each row becomes a withdrawal, takes its own hold against your balance, and waits to be put on the chain by a person. Whoever approved it may not be that person.
Per-row status
A batch is one decision, but it is not one outcome. Each row reports for itself, and a row that fails does not stop the rest.
A batch where some rows failed is reported as
partially_failed rather than completed.
A half-paid payroll should be loud.
Nothing broadcasts automatically
This is the load-bearing sentence on the page. Processing a batch creates withdrawals and reserves the money; it does not send anything. Broadcasting is reached only from a human action.
-
Maker is not checker
The person who approved a specific withdrawal is refused when they try to broadcast it. A super-admin is deliberately not exempted, so the control cannot be shrugged off by escalating a role.
-
At most once on the wire
The attempt is claimed under a row lock before the provider is called, and that flag is never cleared. A crash mid-send cannot become a second send.
-
An ambiguous failure keeps the hold
If we cannot tell whether a transaction went out, the money stays reserved and a human is asked. A stuck payout needs a person; a double send cannot be undone by one.
Where approval happens today
Approval is a permission held by an operator, and there is not yet a self-serve screen in the merchant dashboard for approving your own batches — you create the batch, and our operations team releases it. If your account needs the approver to be someone on your side, that is a conversation to have with us before you rely on batches for payroll.
Scheduled payouts
A standing instruction, bounded
For the payments you already know about: a monthly retainer, a weekly settlement to a treasury address.
- Cadence
- Daily, weekly or monthly
- Run limit
- A fixed number of runs, or open until you stop it
- Destination
- One address, fixed at creation
- Amount
- Fixed per run, validated as positive
An unrecognised cadence is refused outright rather than defaulted. A typo'd "yearly" quietly treated as daily would pay 365 times the intended rate.
What happens when things go wrong
-
A missed window is skipped, not replayed
After an outage the schedule advances past the periods it missed. A daily schedule that was down for a month fires once when it comes back, not thirty times.
-
A failed run is recorded and moves on
The error is stored against the schedule and shown to you. Leaving the next run in the past would turn a failing schedule into a hot loop retrying every minute.
-
Only successes count against the limit
A run that failed does not consume one of your remaining runs.
-
A suspended account stops paying out
The account and allowance checks are inside the withdrawal service, which is exactly why a frozen account's schedule cannot keep paying.
Paying a lot of people?
Tell us the shape of it — how many recipients, how often, which assets — and we will tell you honestly whether this fits.