Running payouts
Top up your balance and pay partners via Stripe Connect from the dashboard or on a schedule.
Running payouts moves money from your pre-funded payout balance to each partner's Stripe Connect account. As the workspace owner, you fund the balance once via Stripe Checkout, then either trigger a run manually or let the monthly cron do it. Partli never fronts money — every transfer draws from the balance you've already topped up.
In the dashboard
- ●
Top up your payout balance
Go to
/account/billingand top up via Stripe Checkout. The minimum is $1 and the cap is $1,000,000 per top-up. Once the payment succeeds, the amount lands in your account-level balance (users.payout_balance_cents) and every transfer draws from it. - ●
Open the Payouts page
Visit
/<workspace>/payouts. The stat cards show Ready to pay, Eligible partners, Total paid out, and your Payout balance. If a partner has earnings but hasn't connected Stripe, or your balance is short, a warning banner appears here before you run anything. - ●
Click Run payouts now
The
Run payouts nowbutton opens a confirmation dialog showing eligible partner count, the total partners will receive (100% of approved commissions — no fee), and your current balance. The button is disabled when there are no eligible partners or nothing is ready to pay. - ●
Confirm the transfer
Click
Send $X to N partnersto fire the run. Each eligible partner receives a Stripe Connect transfer, and a toast reports how many payouts were sent. The Recent payouts table then lists each payout with its status and Stripe transfer ID.
Who counts as eligible
active, their approved-commission total is at or above the program's minPayoutCents (default $10), and your balance can cover it. Otherwise they're skipped and their commissions stay approved to retry on the next run.Via the API / for agents
Two endpoints back this flow: one to top up the balance and one to trigger a run.
Top up the payout balance
POST /api/account/billing/topupAuthenticated as the workspace owner. Returns a Stripe Checkout URL to complete payment.
{
"amountCents": 50000 // required, $1 min (100), $1M cap (100000000)
}{
"url": "https://checkout.stripe.com/c/pay/...", // redirect the owner here
"topupId": "uuid-of-topup"
}The balance is credited only after Stripe confirms the payment (the Checkout session carries metadata.kind = "payout_topup"). On success Stripe redirects to /account/billing?topup=success.
Trigger a payout run
POST /api/workspaces/<workspace>/payouts/runThis is what the Run payouts now button calls. It runs runPayoutsForWorkspace and returns a per-partner result array — each entry has either a payoutId (paid) or a skipped reason.
{
"results": [
{ "partnerId": "…", "payoutId": "…" }, // paid
{ "partnerId": "…", "skipped": "connect_not_active" },
{ "partnerId": "…", "skipped": "below_minimum" },
{ "partnerId": "…", "skipped": "insufficient_balance" },
{ "partnerId": "…", "skipped": "stripe_error" }
]
}Automatic monthly run
A cron endpoint runs payouts for every workspace on the 1st of each month. It's protected by verifyCron and is not a public endpoint.
POST /api/cron/run-payouts // cron-authenticated onlyWebhook events
Each run emits webhooks you can subscribe to for an external agent to react:
payout.sent // { payoutId, partnerId, amountCents, currency, stripeTransferId }
payout.failed // { payoutId, partnerId, amountCents, currency, reason }
commission.paid // { commissionId, partnerId, payoutId }Gotchas
Balance is debited atomically, and refunded on failure
For each partner, Partli debits the owner's balance in a single conditional update that only succeeds when the balance is high enough — so concurrent runs can't overdraw. If the subsequent stripe.transfers.create throws, the debit is refunded, the payout is marked failed with a failureReason, and a payout.failed webhook fires. Those commissions stay approved and retry on the next run.
Partners are processed one at a time in balance order of discovery, so if your balance is partially short, some partners pay and later ones are skipped with insufficient_balance — top up and re-run to clear them. The action can't be undone, but nothing over-transfers.