PFlux
DOCS
GitHub Integration enquiries
PAYMENTS/STATEMENT

Accounting statement

Everything paid to your wallet in a month, from the chain itself, ready for your books. No API call, no key, nothing sent to P2Flux.

SOURCEThe chain
API CALLSNone (EUR/GBP: one for rates)
FORMATSCSV · Xero · QuickBooks · JSON
KEYNone
NUMBERS THAT DO NOT DEPEND ON P2FLUX

A statement lists everything paid to one wallet between two dates, read straight from Base over public JSON-RPC. P2Flux keeps no ledger of your payments, and it is not asked: the same rows come back whether P2Flux is up or not.

Overview

One row per settlement to the wallet — one-time payments (through the splitter and the sponsored splitter) and subscription charges — and one per probable refund. Amounts are decimal USDC; a refund is negative. Times are UTC.

Your own invoice numbers appear only if you hand over your intents: the merchant_ref is read from each intent on your side and matched to its reference. See Your order number.

On the checkout

No code needed: open pay.p2flux.com/#/statement (Base Mainnet) or pay-test.p2flux.com/#/statement for the test network. Enter the receiving wallet (or connect it), the first and last day, and optionally paste or upload your intents — a list, a CSV export or JSON; the page picks out the p2f1. tokens. It shows the table and downloads CSV (all columns, Xero, QuickBooks) or JSON.

The page reads the chain through the network’s public endpoints only, the same ones the checkout already uses. The intents never leave the page. A self-hosted copy from this release has the same screen.

From code

@p2flux/sdk/statement in JavaScript and P2Flux\Statement in PHP give the same rows and the same CSV bytes. Both have no dependencies and take your own RPC endpoints if you have them (rpcUrls / 'rpc_urls'; default the network’s public ones) and network (base or base-sepolia).

import { statement, toCsv } from '@p2flux/sdk/statement'

const rows = await statement({
  wallet: '0x8fA4bE1a0F2d3C4b5A6978Ee0d1C2b3A4F5e6C21',
  from: new Date('2026-10-01T00:00:00Z'),
  to: new Date('2026-10-31T23:59:59Z'),
  intents,            // optional: your intents, to fill merchant_ref (read locally, never sent)
})
writeFileSync('october.csv', toCsv(rows, 'xero'))   // 'generic' | 'xero' | 'quickbooks'
use P2Flux\Statement;

$rows = Statement::statement([
    'wallet'  => '0x8fA4bE1a0F2d3C4b5A6978Ee0d1C2b3A4F5e6C21',
    'from'    => strtotime('2026-10-01 00:00:00 UTC'),
    'to'      => strtotime('2026-10-31 23:59:59 UTC'),
    'intents' => $intents,   // optional: fill merchant_ref (read locally, never sent)
]);
file_put_contents('october.csv', Statement::toCsv($rows, 'xero'));   // 'generic' | 'xero' | 'quickbooks'

The rows

row
{
  "date": "2026-10-14T09:12:44.000Z",
  "tx_hash": "0x5e7a…0c19",
  "kind": "payment",
  "payer": "0x2b41…9e07",
  "reference": "0x9d2c…41be",
  "merchant_ref": "INV-1042",
  "gross": "12.500000",
  "p2flux_fee": "0.125000",
  "network_fee": "0.000000",
  "net": "12.375000"
}
FIELDMEANING
kindpayment, subscription (a charge) or refund?.
payerThe wallet that paid; for a refund, the wallet it went to.
referenceThe payment’s on-chain reference, or the subscription id; for a refund, the payment it matched.
merchant_refFrom your intents; empty when unknown.
grossWhat the buyer was charged for. A sponsored payment’s buyer-paid network fee, and a charge’s gas reimbursement, are on top and not in it.
p2flux_feeThe P2Flux fee, split out on chain in the same transaction.
network_feeNetwork fees the merchant funded out of gross (the fixed fee of a sponsored payment, a charge’s network fee).
netWhat reached the wallet: gross minus both fees.

Refunds

A refund is an ordinary USDC transfer from your wallet, so the chain cannot say why it was sent. The statement marks a transfer refund? when it went to a wallet that paid you, after that payment and for no more than it; the row names the payment it matched. A transfer to anyone else is not listed — it is not income.

The original payment may be older than the statement: payments up to 90 days before the first day are looked up (lookbackDays / 'lookback_days', 0 to turn it off). A September payment refunded in October appears on the October statement as the refund only; the September payment stays on September’s. The extra lookup runs only when the wallet sent USDC in the period.

YOUR RECORDS DECIDE

If you refunded through the checkout, its refund receipt (original transaction, refund transaction, amount, both wallets) is the record to keep; /v1/refunds/verify confirms it at any time. See Refunds.

CSV for your books

FORMATCOLUMNS
genericEvery field above, as in the rows.
xeroA bank-statement import: Date (dd/mm/yyyy), Amount, Payee, Description, Reference (the merchant_ref, else the on-chain reference).
quickbooksThe 3-column bank upload: Date (mm/dd/yyyy), Description, Amount.

The amount booked is net, what reached the wallet; gross and fees are in the description. Lines end in CRLF, and a text cell a spreadsheet would run as a formula gets a leading '. The generic CSV also imports as a bank CSV into FreshBooks and Wave (map Date and net).

USD, EUR and GBP

USDC is booked as US dollars, 1:1. Ask for currencies: ['EUR', 'GBP'] (PHP 'currencies' => ['EUR', 'GBP']; on the checkout, tick “Also in EUR” / “Also in GBP”) and every row also carries the value of net in each currency:

FIELDMEANING
value_usdnet in USD, rounded to cents (USDC = USD 1:1).
value_eurnet in EUR at the ECB euro reference rate: net / USD.
value_gbpnet in GBP through the euro cross rate: net / USD × GBP.
rate_dateThe ECB publication day the rate is from: the row’s own day (UTC), or the last day published before it — a weekend or a TARGET holiday takes the previous working day’s rate. Days are UTC days while the ECB publishes for CET days, so a payment late in the evening UTC takes that UTC day’s rate.

The rates are the European Central Bank’s daily euro foreign exchange reference rates (published around 16:00 CET). They come from the P2Flux API’s /v1/rates — P2Flux downloads them from the ECB once a day and serves its copy, so the checkout talks to no new host. Only the first and last day are sent; your wallet and rows are not. Values are rounded half away from zero, in integers, so the JavaScript and PHP SDKs write the same bytes. Today’s and yesterday’s rows can still change: until the ECB publishes a day, it takes the previous working day’s rate, so export a closed period once it is two days old. Rates are fetched from apiUrl / 'api_url' (default production; the rates are the same everywhere).

The generic CSV gets the extra columns after net. Xero and QuickBooks keep their import layout — the amount stays in USD — and name the EUR and GBP values and the ECB day in the description. Without currencies nothing changes and no rates are read.

Fee statement

What P2Flux took in fees from your wallet’s payments in one month: open pay.p2flux.com/#/fees (or pay-test.p2flux.com/#/fees), enter the receiving wallet and the month. The page reads the chain like the statement — the p2flux_fee of every one-time payment, sponsored payment and subscription charge — and lists them with the total.

  • Number FS-first 12 hex characters of the wallet-YYYYMM, e.g. FS-8fa4be1a9c03-202610: the same wallet and month always give the same number.
  • “Print / save as PDF” prints the statement alone (the browser’s own Save as PDF).
  • CSV: statement, date, tx_hash, kind, reference, merchant_ref, gross, p2flux_fee, one line per fee and a total line.
  • Fees are in USDC (= USD). Every fee was taken on chain in the transaction named, so each line can be checked on a block explorer.
A STATEMENT, NOT AN INVOICE

Modulout LLC is not registered for VAT. This is a statement of fees, not a tax invoice. Receipts and invoices to your buyers are yours to issue; P2Flux does not issue them.

Limits

  • Public endpoints answer a limited number of requests: a long range on a busy wallet can take a minute, and an endpoint that keeps failing is an error, never a short statement. Pass your own endpoints for large ranges.
  • Payments to AI-agent (x402) settlement are not in the statement yet.
  • Base and Base Sepolia only.
Something more than a standard integration?
Marketplace flows, platform billing and custom settlement logic.
Discuss an integration