Developers › After the payment
Balance and payouts
Verified 6 November 2026Explain this to your team →
How funds move
A payment goes through three states after the card is charged, and each is a real balance you can read rather than a label on a screen.
| State | What it means |
|---|---|
| pending | Captured. Still inside your settlement delay, so it cannot be paid out yet. |
| available | The delay has passed. This is what the next payout draws on. |
| paid out | Included in a payout. It has left your balance for your bank account. |
The settlement delay is yours to choose — two days by default — and it exists so that a card taken this morning and refunded this afternoon costs nothing to unwind. Money crosses from pending to available on the hour, once its delay has passed.
const balance = await sp.balance.retrieve();
balance.available; // [{ amount: 114000, currency: "bzd" }] — the next payout draws on this
balance.pending; // [{ amount: 47500, currency: "bzd" }] — still inside the delay
balance.payouts_in_transit; // [{ amount: 80000, currency: "bzd" }] — already sent, not yet confirmedBalance transactions
A balance_transaction is one movement of your balance. Payments, refunds, payouts and adjustments are four different resources with four different lifecycles; what they have in common is that each moved the balance by some amount, and this list is that. Its net column sums, across the whole list, to pending + available. That is the property to reconcile against.
const page = await sp.balanceTransactions.list({ limit: 25 });
page.data[0];
// {
// id: "btxn_9f4c1e2a7b8d4f0aa1c3e5d7b9f0a2c4",
// type: "charge",
// amount: 12000, // the gross, signed in your favour
// fee: 600, // what we charged, signed
// net: 11400, // amount - fee, and the column that sums to your balance
// status: "available",
// source: "pi_3KqL8xQpR2sT7vW9yZ1aB4cD",
// }status changes from pending to available — the release is not a second transaction, and totalling the list never double-counts anything.| type | What it is | source |
|---|---|---|
| charge | A card payment. Positive. | The payment intent, pi_… |
| refund | Money returned to a cardholder, including a refund made directly at the bank. Negative. | The refund, re_… — its payment_intent leads back to the payment |
| payout | A payout leaving for your bank account. Negative. | The payout, po_… |
| payout_reversal | A payout that was cancelled or returned. Positive: the money came back. | The payout, po_… |
| adjustment | A correction we made, with a reason recorded against it. Also the fee a bank kept for returning a payout. | The adjustment, or the payout for a bank’s return fee |
| dispute / dispute_reversal | A chargeback held against you, or given back. | The dispute |
| application_fee / application_fee_refund | Only when a platform acts for you: the fee it took from a payment, or that fee given back. | The fee, or the fee refund |
| connect_collection_transfer | Only when a platform acts for you: the platform covering a negative balance that could not be recovered. | The platform’s cover |
currency is always bzd — because that is what your balance is held in. A charge’s amount is what the card was charged, the payment’s settlement_amount, not the amount it was priced at: a US$25.00 payment is a charge of 5000. A refund of it is likewise the BZD that went back, at the payment’s own rate, and its fee is negative when our fee was returned with it.Payouts
A payout takes your whole available balance and sends it to your bank account. It is never an amount you choose: there is no POST /v1/payouts, and there will not be one, because an amount a caller supplies is an amount that can be asked for twice.
You choose the schedule in the dashboard under Settings → Payouts: daily, weekly on a day you pick, monthly on a date you pick, or only when you ask. A scheduled payout is cut at 09:00 Belize time on the day it is due, and skipped if your balance is below the minimum you set — the money is not lost, it rides into the next one.
const payouts = await sp.payouts.list({ status: "paid" });
payouts.data[0];
// {
// id: "po_7Kq2LxR9sT4vW8yZ1aB3cD5e",
// amount: 114000,
// currency: "bzd",
// status: "paid",
// destination: { bank_name: "Example Bank", account_last4: "4321" },
// bank_reference: "2022835577",
// }| status | What it means |
|---|---|
| pending | Cut. The transfer has not been made yet. |
| in_transit | The transfer has been initiated at the bank. |
| paid | The bank confirmed it. bank_reference is the bank's own reference for it. |
| canceled | Called off before the transfer. The money is back in your available balance. |
| failed | The bank refused it before it left. The money is back in your available balance. |
| returned | It was paid, and then the bank sent it back. The money is back in your available balance, less any fee the bank kept. |
status is what it is actually doing, and bank_reference is what you can search for at your own bank once it says paid. The email we send your team when it is paid labels it as an estimate, never a promise. Estimated arrival: the same day for some banks, and the next business day for others.In test mode, a payout goes to a simulated destination and needs no bank details. It moves to paid by itself within about 20 minutes, with a bank_reference starting SIMULATED-, and payout.paid fires as it would in live. No money moves.
To rehearse what happens when a payout doesn't arrive, make a test payout fail or come back with a test key:
curl -X POST https://api.secureprocessing.app/v1/test_helpers/payouts/po_.../fail \
-H "Authorization: Bearer sk_test_..."fail: the bank refuses the transfer before it leaves. The payout becomesfailed, its money is back in your available balance, and you getpayout.failed. Only apendingorin_transitpayout can fail.return: the transfer left and came back. The payout becomesreturned, its money is back in your available balance, and you getpayout.failedand thenpayout.returned. A payout that hasn't been paid yet is paid first, so you getpayout.paidbefore them.
Both take an optional failure_code, such as account_closed or invalid_account_number. A live key is refused.
You give us your bank details in your activation application, and can edit them there until you submit it — or again if we ask you for more information. After that you ask for a change in the dashboard under Settings → Payouts, and it is never made by itself: our staff call you back on the number already on file before they approve it, and the first payout to the new account waits for a person to check it. The account number is encrypted and only its last four digits appear on any screen or document of yours; the full number is decrypted only when our staff need it to make the transfer, and each time is recorded.
Reconciling a payout
Every payout can name exactly what it paid for, and the report is a CSV with every money column twice — in minor units for a script, and formatted for a person checking a bank statement.
curl https://api.secureprocessing.app/v1/reports/payout_reconciliation/po_7Kq2LxR9sT4vW8yZ1aB3cD5e \
-H "Authorization: Bearer sk_live_..." -o payout.csvThe same movements are available as objects, so you can reconcile in code rather than in a spreadsheet:
import { autoPaginate } from "@secureprocessing/node";
// Every page, not just the first: a payout can cover more movements than one page holds.
let total = 0;
for await (const line of autoPaginate((page) =>
sp.payouts.listTransactions("po_7Kq2LxR9sT4vW8yZ1aB3cD5e", page),
)) {
total += line.net;
}
const payout = await sp.payouts.retrieve("po_7Kq2LxR9sT4vW8yZ1aB3cD5e");
total === payout.amount; // trueOver HTTP that is the balance transactions list filtered to one payout — there is no separate path. Like every list it returns ten rows unless you ask for up to 100, so follow has_more before you total it:
curl "https://api.secureprocessing.app/v1/balance_transactions?payout=po_7Kq2LxR9sT4vW8yZ1aB3cD5e&limit=100" \
-H "Authorization: Bearer sk_live_..."A payout that was cancelled keeps its own report, naming what it would have covered, and the reversal that put the money back appears on the next payout’s report. Each movement belongs to exactly one payout, so the reports never double-count and never lose a line between them.
Events
Subscribe to these rather than polling. They are documented in full on the webhooks page.
| Event | When |
|---|---|
| balance.available | Money finished its settlement delay. One event per release, not one per payment. |
| balance.adjusted | We moved your balance by hand — a correction, a write-off, or a debt. The reason is on the event. |
| payout.created | A payout was cut. Its amount has left your available balance. |
| payout.updated | The transfer has been initiated. |
| payout.paid | The transfer left our account. bank_reference names it. |
| payout.canceled | Called off. The money is back in your available balance. |
| payout.failed | The bank refused or returned it. The money is back in your available balance. |
| payout.returned | It left and the bank sent it back. The money is back in your available balance, less any fee the bank kept. Sent with payout.failed. |