Developers › After the payment
Reports and exports
Verified 6 November 2026Explain this to your team →
The balance summary
One call gives you a period: what you opened with, everything that moved, what you closed with — and the same closing figures recomputed independently from the ledger, so you can see that the two agree.
const month = await sp.reports.balanceSummary({ start: "2026-09-01", end: "2026-10-01" });
if (!month.reconciled) {
// Your statement and your balance disagree. Do not reconcile around it — get in touch.
throw new Error("balance summary did not reconcile");
}
month.starting_balance; // { available: 0, pending: 0 }
month.activity.charges; // { count: 2, gross: 20000, fees: 1000, net: 19000 }
month.activity.refunds; // { count: 1, amount: -2000, fees_returned: -100 }
month.activity.payouts; // { count: 1, amount: -17100 }
month.ending_balance; // { available: 0, pending: 0 }
month.ledger; // { available: 0, pending: 0 } — recomputed from the entriesreconciled: false is an incident, not a display quirk. ending_balance is derived from the period’s movements on top of the opening balance. ledger is the same two figures recomputed from the ledger’s own entries at the moment of your request, by the same function a real payout is cut against. Two paths, no shared query. If they disagree, your statement and your balance are telling you different things, and that is a support call rather than a number to work around.Every figure is an integer in minor units of your settlement currency, and it is signed the way the ledger signs it: a charge is positive, a refund and a payout are negative, and fees_returned is negative because it is a fee coming back to you. That is what makes the lines add up — they total exactly ending_balance − starting_balance, with nothing to reinterpret.
| Field | What it is |
|---|---|
| starting_balance | available and pending, at the instant the period opened. |
| activity.charges | count, gross, fees, net. `net` is what reached your balance. |
| activity.refunds | count, amount (negative), fees_returned (negative). |
| activity.payouts | count and amount (negative): money that left for your bank. |
| activity.payout_reversals | A payout cancelled or returned. Positive. |
| activity.application_fees | count and amount: fees a platform took on payments through your account, negative, or that a platform received, positive. Zero unless you are on Connect. |
| activity.adjustments | A correction, with a reason recorded against it. |
| activity.disputes | count, amount, fees. amount is the chargebacks as one signed figure: the amounts held, plus the ones given back when you won. Negative means money is held or gone; zero means it all came back. fees is our handling fee on a lost chargeback, positive, and is not in amount — amount − fees is what disputes moved. |
| ending_balance | starting_balance plus the period's movements. |
| ledger | The same two figures recomputed from ledger.account_balance() right now. |
| reconciled | Whether the two agreed. See above. |
Reconciling against your own books
The check that matters is one line of arithmetic, and it holds for any period:
const opened = month.starting_balance.available + month.starting_balance.pending;
const closed = month.ending_balance.available + month.ending_balance.pending;
const moved =
month.activity.charges.net +
(month.activity.refunds.amount - month.activity.refunds.fees_returned) +
month.activity.payouts.amount +
month.activity.payout_reversals.amount +
month.activity.application_fees.amount +
month.activity.adjustments.amount +
(month.activity.disputes.amount - month.activity.disputes.fees);
closed - opened === moved; // always true, and `reconciled` is us asserting it tooTwelve monthly summaries tile a year exactly, because start is inclusive and end is exclusive. Ask for the 1st to the 1st and you get a whole month; the payment taken at the stroke of midnight belongs to exactly one of two adjacent reports, never both and never neither.
When your period ends in the past, ending_balance and ledger will differ by everything that has happened since. That is expected and is not a disagreement — reconciled accounts for it. When the period runs to now, the two are identical.
Dates
start and end take a unix timestamp in seconds, or an ISO date such as 2026-09-01, which is read as midnight in Belize — 06:00 UTC, because Belize is UTC−6 all year, so an evening payment belongs to that day, not the next. A unix timestamp or a full ISO instant is taken exactly as given. Left out, they default to the current Belize calendar month up to now.
CSV exports
Four downloads, each covering the same date window and each a CSV streamed as it is read out of the database rather than assembled in memory first. They are the rows behind the summary.
| Export | Filters beyond the dates |
|---|---|
| payments.csv | status |
| refunds.csv | status |
| payouts.csv | status |
| balance_transactions.csv | type, payout |
payments.csv also takes customer, payment_link and invoice. balance_transactions.csv with a payout gives exactly what that payout paid for.
curl -H "Authorization: Bearer sk_test_..." \
-H "Accept: text/csv" \
"https://api.secureprocessing.app/v1/reports/exports/payments.csv?start=2026-09-01&end=2026-10-01" \
-o payments-september.csv
curl -H "Authorization: Bearer sk_test_..." \
-H "Accept: text/csv" \
"https://api.secureprocessing.app/v1/reports/exports/balance_transactions.csv?start=2026-09-01&end=2026-10-01" \
-o transactions-september.csvFrom the SDK, you are handed the response so you can pipe it straight to a file:
import { createWriteStream } from "node:fs";
import { Readable } from "node:stream";
import { pipeline } from "node:stream/promises";
const response = await sp.reports.export("payments", { start: "2026-09-01", end: "2026-10-01" });
await pipeline(Readable.fromWeb(response.body!), createWriteStream("payments-september.csv"));What a row looks like
Every money column appears twice. amount_minor is the integer this API speaks in, and amount beside it is the same figure formatted for a person. A file with only the formatted column is a lossy copy of your ledger; a file with only minor units makes whoever opens it divide by a hundred four hundred times.
id,created,type,source,status,currency,amount_minor,amount,fee_minor,fee,net_minor,net,available_on
btxn_9f4c1e2a...,2026-09-14T15:02:11.884Z,charge,pi_3KqL8x...,available,bzd,12000,120.00,600,6.00,11400,114.00,2026-09-16T15:02:11.884Z
btxn_1a7b3c9d...,2026-09-19T09:41:03.210Z,refund,re_7mN4pQ...,available,bzd,-2000,-20.00,-100,-1.00,-1900,-19.00,2026-09-19T09:41:03.210Z| Convention | Detail |
|---|---|
| Money | Twice per figure: an integer in minor units, and a plain decimal with no symbol and no thousands separator. |
| Dates | ISO 8601 in UTC, so the file means the same thing on every machine that opens it. |
| Ids | Exactly as the API returns them. |
| metadata | One cell, holding your metadata as a JSON string. |
| Escaping | RFC 4180. A field containing a comma, a quote or a newline is quoted and its quotes doubled. |
| Order | Newest first, the same order and the same filters as the matching list endpoint. |
A note on spreadsheets
Text fields in these files can contain anything your customers typed. A cell beginning =, +, - or @ is treated as a formula by Excel, Numbers and Google Sheets — so a description of =HYPERLINK("https://example.com","Click") would become a live link in your own spreadsheet. We prefix any such field with an apostrophe, which every spreadsheet reads as “this is text” and strips on display.
-19.00 also begins with a minus sign, and prefixing it would turn every refund and payout in the file into text — where SUM() silently returns zero. Those columns stay numbers so they add up. If you parse these files with a script, strip a single leading ' from text fields.A payout’s reconciliation
Separately from the four exports, every payout has a report of its own: the movements it paid for, ending in a total, with the payout’s own amount printed in the header. The two are derived independently, so if they ever disagreed the document would say so rather than quietly agreeing with itself.
curl -H "Authorization: Bearer sk_test_..." \
-H "Accept: text/csv" \
"https://api.secureprocessing.app/v1/reports/payout_reconciliation/po_7Kq2LxR9sT4vW8yZ1aB3cD5e" \
-o payout.csvIt is also the “Download CSV” button on a payout’s page in the dashboard. The email you get when a payout is paid summarises the same figures and links to that page.