Agents: fetch this page as plain markdown at
https://docs.usecleff.com/concepts/payouts.md.Fund the payouts
Payouts draw from your Cleff Account, and a shortfall surfaces when a payout is sent, not when it is created. Read the account’s balance and the deposit instructions to fund it withGET /v1/funding/account. A 404 means
your Business has no Cleff Account yet: in sandbox, submit your business
profile in the dashboard; in production, finish going live.
Follow a payout through its states
A payout is a single instruction: pay this Beneficiary (the payee), at this destination, this amount. It moves through an explicit state machine:
Each state means one thing, and says what you do about it:
Name where the payout goes
A payout is paid to one of the Beneficiary’s destinations: a bank account or a debit card. Itsdestination_id names which one, and destination_kind says
whether it is a bank or a card.
destination_id is optional when you create the payout. Leave it out and the
payout goes to the Beneficiary’s declared destination, the one they chose
through a collection link. If they have declared none, it goes to the only
destination they hold, and a Beneficiary who holds several needs you to name
one. Beneficiaries & compliance
has the full table of what you send and what happens.
The destination is fixed when the payout is created. If the Beneficiary
declares a different destination afterwards, their next payout goes there; this
one does not move.
Creation checks the payout up front: the Beneficiary must be compliant and
the destination payout_usable. In production, your Business must not be
blocked (BUSINESS_BLOCKED). A payout that fails a check is refused and nothing
is created, so it is safe to correct and resend. The idempotency key you send makes creation safe to retry for 24
hours; see Idempotency.
Know which rail carries the money
The destination decides the Payout Rail, the network that carries the money:
The dashboard’s Settings → Plan & Billing page lists your payout rails,
which of them are active, and how to request the others.
A card payout your Business is not approved for is created and approved without complaint, then
fails when it is sent. Check that card payouts are active on Plan & Billing before you pay a
Beneficiary whose destination is a card.
Pass the approval gate
Nothing is sent without a Decision. A Decision is an approve or reject verdict recorded by a validator: a person on your team, or your own risk system calling the API.approve and reject are conveniences over decisions and share its
guarantees. Every Decision carries a decision_id you mint, a ULID, which makes
it safe to retry: resending it unchanged returns the original Decision with HTTP
200, and resending it with a different verdict is refused with
IDEMPOTENCY_CONFLICT. Approving or rejecting a payout that is no longer
pending_approval is refused with INVALID_STATE_TRANSITION.
A Decision with status: "pending_review" is recorded without moving the
payout: it stays in its current state until an approve or reject follows.
In production, a Business Cleff has blocked can’t create or approve payouts
(BUSINESS_BLOCKED), but can still reject them, so nothing waiting for approval
is stranded.
Know what happens after approval
Approval queues the payout to be sent, and sending happens asynchronously, so the payout staysapproved while the payment is in flight. In production your
balance is checked at this point, not before: a payout your Cleff Account can’t cover
fails with failure_code: insufficient_funds.
On the way, the provider may acknowledge the payout, give an expected delivery
date, and assign rail_ref, the payment’s reference on the rail. The
acknowledgment and the expected date arrive only as webhook events; rail_ref
appears on the payout and in each event’s data. When the provider confirms the
money has left, the payout reaches disbursed.
disbursed is not the end. The receiving bank can still return the money, so
the payout stays provisional until the return window closes and it becomes
settled. The money arriving in the Beneficiary’s account is reported by
payout.delivered, not by a state: a delivered payout is still disbursed
until it settles.
In sandbox, every payout that is approved reaches disbursed and stops there.
Replace a payout that did not arrive
A payout that isfailed or returned can be answered with a replacement: a
new payout, created with replaces_payout_id set to the original’s ID. Check
replaceable on the original first. It is false when:
- a replacement already exists, so creating another is refused with
PREDECESSOR_ALREADY_REPLACED; - the failure is
indeterminate, because the money may already have moved. Contact Cleff support instead.
failure_code names before you replace the payout, or the
replacement fails the same way. A replacement goes through the approval gate
like any other payout.
Track payouts without polling
Webhooks report each step as it happens. There are tenpayout.*
events:
No event is sent for creating or approving a payout, including one approved by
a teammate in the dashboard;
payout.disbursement_submitted is the first event
after approval. To catch up on changes you did not see, list payouts with
updatedSince. Payout events describes what
each one carries.
Read amounts in minor and major units
The API speaks minor units: whole numbers of the currency’s smallest unit, in fields that end in_minor. For USD that is cents, so
amount_minor: 50000 is $500.00. Integers keep amounts exact; there is no
rounding on the way in or out.
Webhooks speak major units. The amount field on every payout.* event is
a decimal string in the currency’s own unit, carrying exactly as many decimal
places as the currency uses. Jane Doe’s payout arrives as:
payout_id rather than on the amount. If you do compare
amounts, convert the string to minor units with a decimal parser, or by
dropping the decimal point, and compare integers. Parsing it as a
floating-point number can round it.