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.

payroll.csv
# 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

  • address

    Validated 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.

  • amount

    A 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.

  • reference

    Optional, 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.

1

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.

2

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.

3

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.

Pending Waiting for the batch to be approved
Queued Approved and turned into a withdrawal, waiting to be broadcast
Awaiting approval The withdrawal it created needs a second look of its own
Sent On the chain
Failed Refused, with the reason recorded against the row

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.