Every sale you take adds to your store's balance at Fluveo, kept in your store's currency. A new sale sits in pending for a while. Once it settles it moves to available, and only available money can leave for your bank. This page reads the balance, sends a payout and follows it until the money lands.
Read your balance#
GET /v1/balance returns two lists, each with one entry per currency, in the smallest unit of the currency:
available: what you can send to your bank right now.pending: sales that have not settled yet.
available can go below zero. It is what your account holds less any amount your store owes Fluveo. A dispute takes its amount and its fee as soon as it opens, and a refund the balance did not cover counts while it waits. A refund or a dispute can take out more than the balance held, and the balance then shows the real, negative number, never zero. While available is below a payout's amount, the payout is refused with balance_insufficient, or with payouts_not_allowed when the account cannot pay out now for another reason.
curl https://api.fluveo.com/v1/balance \
-H "Authorization: Bearer sk_test_..."const response = await fetch("https://api.fluveo.com/v1/balance", {
headers: { Authorization: "Bearer sk_test_..." },
});
const balance = await response.json();
console.log(balance.available, balance.pending);import requests
response = requests.get(
"https://api.fluveo.com/v1/balance",
headers={"Authorization": "Bearer sk_test_..."},
)
balance = response.json()
print(balance["available"], balance["pending"])<?php
$ch = curl_init("https://api.fluveo.com/v1/balance");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer sk_test_..."],
]);
$balance = json_decode(curl_exec($ch), true);
print_r($balance["available"]);The answer, trimmed:
{
"object": "balance",
"available": [{ "amount": 12500, "currency": "usd" }],
"pending": [{ "amount": 4000, "currency": "usd" }],
"livemode": false
}When pending money becomes available, Fluveo sends one balance.available event, whose data.object is your balance as GET /v1/balance shows it at that moment. Listen for it if you pay out automatically.
Refunds and disputes also draw on your balance. See Refund a payment.
What a payout may take#
Available money is not always free to leave. A payout already on its way, a hold on your account, or an amount your store still owes lowers what a new payout may take. So does a refund of a sale whose own money has not arrived yet, until that money arrives. A payout that asks for more is refused, and the error message names the reason (see Errors you may see).
When your store has a reserve, the part of each sale it holds stays out of available until it is released. Reserves shows how much is held and when it comes back.
Create a payout#
Check your bank account#
Payouts go to the bank account your store registered for payouts. A store without one cannot pay out.
Every payout names the bank account it pays in
destination, as aba_...id. You may leavedestinationout of the request to pay your payout bank account, or send the id of one of your store's bank accounts to pay that one. Any other id is refused, so money never goes to an account your store did not register.GET /v1/accounts/{account}/external_accountslists your store's bank accounts, and a payout read withexpand[]=destinationshows the one it pays. Each shows the last four digits of the account number inlast4and the bank's name inbank_name, ornullwhen Fluveo has no name for it. The test bank of routing number110000000is namedFLUVEO TEST BANK.Send the payout#
Give the amount in the currency's smallest unit, plus your store's currency. Add an
Idempotency-Keymade for this one payout. If the call is sent again with the same key and body, you get the firstpo_back and nothing is paid a second time.Pay out $95.00curl https://api.fluveo.com/v1/payouts \ -H "Authorization: Bearer sk_test_..." \ -H "Idempotency-Key: payout-2026-11-07" \ -d amount=9500 \ -d currency=usd \ -d "description=Weekly payout"const response = await fetch("https://api.fluveo.com/v1/payouts", { method: "POST", headers: { Authorization: "Bearer sk_test_...", "Idempotency-Key": "payout-2026-11-07", }, body: new URLSearchParams({ amount: "9500", currency: "usd", description: "Weekly payout" }), }); const payout = await response.json(); console.log(payout.id, payout.status);import requests response = requests.post( "https://api.fluveo.com/v1/payouts", headers={ "Authorization": "Bearer sk_test_...", "Idempotency-Key": "payout-2026-11-07", }, data={"amount": 9500, "currency": "usd", "description": "Weekly payout"}, ) payout = response.json() print(payout["id"], payout["status"])<?php $ch = curl_init("https://api.fluveo.com/v1/payouts"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer sk_test_...", "Idempotency-Key: payout-2026-11-07", ], CURLOPT_POSTFIELDS => http_build_query([ "amount" => 9500, "currency" => "usd", "description" => "Weekly payout", ]), ]); $payout = json_decode(curl_exec($ch), true); echo $payout["id"] . " " . $payout["status"];Follow it to the end#
A new payout is
pending. Fluveo first sets the whole amount aside in your balance, and only then sends it. While the bank is receiving it, it can readin_transit.paidmeans your bank has it. A bank that refuses it turns itfailed, and the amount returns to your balance. A payout can also turnfailedafterpaid, when the bank sends the money back later; that amount returns to your balance too.
In the smallest unit of the currency, at least 1.
Your store's currency, as a three-letter code in lowercase. Any other currency is refused.
Your own text, up to 5,000 characters.
Text that may show on your bank statement. It cannot hold
<,>,'or".Only
standard, the default.instantis refused with 400instant_payouts_unsupported.The id (
ba_...) of one of your store's bank accounts, asGET /v1/accounts/{account}/external_accountslists them. Leave it out to use your payout bank account for the currency.Your own key-value pairs, sent as
metadata[key]=value.
Payout statuses#
| Status | Meaning |
|---|---|
pending | Accepted and not sent yet. You can still cancel it while none of it has left. |
in_transit | Sent; your bank has not confirmed it yet. |
paid | Your bank has the money. |
failed | The bank refused it, or returned it after it was paid. The amount is back in your balance, and failure_code and failure_message explain. |
canceled | You canceled it before it was sent. The amount is back in your balance. |
A payout keeps the destination it was created with. If your store removes or replaces that bank account before the money leaves, the payout fails with failure_code account_closed (no_account when no account is left on file), and the amount returns to your balance. Fluveo never redirects it to the new account.
Events#
| Event | When |
|---|---|
payout.created | The payout was created. |
payout.updated | The payout's status changed (sent beside each of the events below), the bank trace it shows (trace_id) changed, or you changed its metadata. |
payout.paid | All of its money reached your bank. |
payout.failed | The payout failed, or a paid payout had a bank return. The money is back in your balance. |
payout.canceled | The payout was canceled before it was sent. |
Payout schedule#
Your store starts on manual: money leaves only when you create a payout. To be paid out on a schedule instead, set it with POST /v1/balance_settings, and read it back with GET /v1/balance_settings.
curl https://api.fluveo.com/v1/balance_settings \
-H "Authorization: Bearer sk_test_..." \
-d "payments[payouts][schedule][interval]=weekly" \
-d "payments[payouts][schedule][weekly_payout_days][0]=monday"payments[payouts][schedule][interval]ismanual(the default),daily,weeklyormonthly.dailypays out each weekday, Monday to Friday.- With
weekly, send the days inpayments[payouts][schedule][weekly_payout_days][], frommondaytofriday. - With
monthly, send the days of the month inpayments[payouts][schedule][monthly_payout_days][], from1to31. A day the month lacks pays on its last day.
On each scheduled day, Fluveo creates a payout of what your store may pay out then (see What a payout may take). It is an ordinary po_ with automatic: true, and it sends the same events as any payout. You can still create a manual payout beside the schedule. Set interval=manual to stop the schedule.
Cancel, read and list payouts#
POST /v1/payouts/{id}/cancelstops a payout that is stillpending, before any of it was sent. After that the cancel is refused, so treat a payout as final once you create it.POST /v1/payouts/{id}changes onlymetadata.GET /v1/payouts/{id}reads one payout.GET /v1/payoutslists payouts, newest first. Filter withstatus,created,arrival_dateordestination, and page withlimit(1 to 100),starting_afterorending_before.
curl -X POST https://api.fluveo.com/v1/payouts/po_.../cancel \
-H "Authorization: Bearer sk_test_..." \
-H "Idempotency-Key: payout-2026-11-07-cancel"Your statement: balance transactions#
Each charge, refund and payout leaves a balance transaction (txn_) with its amount, fee, net, type and source (the object that caused it).
curl -G https://api.fluveo.com/v1/balance_transactions \
-H "Authorization: Bearer sk_test_..." \
-d source=ch_... \
-d limit=20GET /v1/balance_transactionslists lines, newest first. Filter withtype,source,currencyorcreated; page withlimit,starting_afterorending_before(see Pagination). Addexpand[]=data.sourceto get each source object in the same answer.GET /v1/balance_transactions/{id}reads one line.payout=po_...with an automatic payout (one your payout schedule made,automatic: true) lists the lines that payout paid out, its ownpayoutline included. Another payout'spayoutline, manual or automatic, is never in it: that payout paid its money out. Thereserved_fundsline that moved part of a sale into your reserve is in the list of the payout it made smaller; the reserve's own side (reserve_holdandreserve_release, balancerisk_reserved) never is. Other payouts, open disputes or debts can keep the listed lines'netfrom adding to 0. A manual payout is refused with 400 onpayout: "Balance transaction history can only be filtered on automatic transfers, not manual." A value that is not one of your store's payouts answers 400resource_missingonpayout. To find the line any payout left, filter withsource=po_....
Errors you may see#
| Error | Why |
|---|---|
400 balance_insufficient | The payout asks for more than you can pay out now, as when what your store owes takes the available balance below it. Read GET /v1/balance and ask for less. |
400 payouts_not_allowed | Your account cannot pay out right now: payouts are not enabled yet, identity verification is not approved, there is a hold or an amount owed, or an earlier payout is not settled. The message says which. |
| 400 "Sorry, you don't have any external accounts in that currency" | No payout bank account is on file for the store. |
400 amount_too_large on amount | The amount is above your account's limit for one payout. |
400 parameter_invalid_integer on amount | The amount is above 9999999999, the most any payout can be. |
400 instant_payouts_unsupported | You sent method=instant. |
400 on currency | The currency is not your store's. |
400 resource_missing on destination | The destination is not one of your store's bank accounts. It is checked after the form of the request (an unknown parameter, a missing or invalid amount or currency, metadata, a description over 5,000 characters), and before method, a statement_descriptor with a forbidden character, the amount's maximum, a currency that is not your store's and your balance. |
A refused payout reserves and sends nothing.
See Errors for the shape of every error.
Test it#
- Take a few test payments with
pm_card_visa(see Accept a payment). GET /v1/balance: the payments show inpendingoravailable.- If
availableis more than0, create a small payout, such asamount=100: you get apo_inpendingandpayout.created. If it is refused instead, the message names the reason. - Ask for more than your available balance:
400 balance_insufficient(orpayouts_not_allowed), and no payout is made. - Send
method=instant:400 instant_payouts_unsupported. - Send step 3 again with the same
Idempotency-Key: you get the samepo_back.
A test payout needs available test money. A test Pix or Boleto paid with the payer email succeed_immediately@example.com adds it once its money is available. See Pix.
Test a failed payout#
In test mode, set your payout bank account (in the dashboard's payout settings) to one of these test bank accounts, with the routing number 110000000. The next payout goes to it and fails with that code: you get payout.failed, the payout's failure_code, and the amount back in your balance.
| Test account number | failure_code |
|---|---|
000111111116 | no_account |
000111111113 | account_closed |
After a failure the bank account shows as errored, and payouts stay off until you set a working bank account, such as 000123456789. These numbers work only in test mode.