> For the complete index of the 402pay docs, see [llms.txt](https://developer.402pay.co/llms.txt).

# Reporting and reconciliation

Which amounts to report, how payments match your wallet, and how to export a period.

Every payment carries what you charged, what arrived, what it was worth in US dollars and where it landed, and every deposit is a transaction in your wallet. This page shows which field to use for what, and how to export a period.

## Amounts on a payment

| Field | What it holds |
| --- | --- |
| `amount, currency` | The price you charged, in minor units of your currency. |
| `fee_payer, customer_fee` | Who pays 402pay's fee, `business` or `customer`, and what the customer pays toward it, in the same currency: 0 when you pay it, and until the customer picks how to pay. |
| `amount_received` | What arrived, in the same currency at the quoted rate. 0 until funds arrive, and `amount` plus `customer_fee` once it's paid in full. |
| `reporting` | `amount`, `fee`, `transaction_fee`, `customer_fee` and `net` in US cents, for totals across currencies. `fee` is the rate and `transaction_fee` the flat fee, and `net` is what you keep after them: `amount` plus `customer_fee` less `fee` and `transaction_fee`. `fee` and `net` are final once the payment succeeds. |
| `fee_rate_bps` | The rail's rate in basis points: 0 for crypto (0%) and 300 for cards (3%). |
| `method` | How the customer paid: the coin, network and amount as decimal strings, the sending address and transaction, and `overpaid_amount`. For cards, the payment rail without card details, which the customer enters on the secure payment page. |
| `settlement` | Where the funds went: `destination` is `wallet` for the deposit that reached your wallet, whole, or `fees` when the payment went to 402pay to pay fees you owed. Then the asset, network, amount, address and transaction. |
| `confirmed_at` | When the payment succeeded. |

- An overpayment keeps `reporting.amount` at the price, while `amount_received` and `settlement.amount` include the excess.
- An accepted payment reports what actually arrived: `reporting.amount` is its value less any `customer_fee`, and the fee is taken on that.
- A payment finished by a remainder landed in more than one transfer. `settlement.amount` adds them up, and `settlement.tx_hash` names the latest.

## Fees

`reporting.transaction_fee` and `reporting.net` stay 0 until the payment succeeds.`reporting.fee` is the rate on the payment and `reporting.transaction_fee` the $0.25 flat fee, both on the [pricing page](https://402pay.co/pricing). Neither comes out of the deposit: every payment, by card or crypto, lands in your wallet whole (the price, plus the fee when your customer pays it). What you owe, the rate, the flat fee and your wallet's monthly plan, goes on your fee statement, which 402pay collects by sending some whole payments to its own address. Those payments have `settlement.destination` set to `fees` and no wallet transaction. See [fees and billing](https://developer.402pay.co/guides/fees.md).

## Passing fees on

In the dashboard, under Settings, Payments, you choose who pays 402pay's fees. With your customers paying, the hosted checkout adds a processing fee to each customer's total: the rate for the method they pick, plus the $0.25 flat fee, in the price's currency. It's worked out on the price, never on a total that already includes it, so the payment lands at the price plus the whole fee, and the same fee owed on your fee statement as usual leaves you the whole price. A payment you create with `POST /payments` follows the setting unless its own `fee_payer` says otherwise.

| A $49.00 card payment | Amount |
| --- | --- |
| Price | $49.00 |
| Processing fee (3% plus $0.25) | $1.72 |
| The customer pays | $50.72 |
| Lands in your wallet | $50.72 |
| The rate plus $0.25, on your fee statement | -$1.72 |
| You keep | $49.00 |

A crypto customer sends the price plus the fee in their coin. A card customer reviews the final total, including any additional fees, on the secure payment page. The payment says who paid in `fee_payer` and how much in `customer_fee`, while `amount` stays the price.

Network fees are separate: the customer's wallet pays them in the network's own coin on top of what it sends, so they're never in a payment's amounts. The hosted checkout shows an estimate beside the total.

## Wallet transactions

Every deposit is an `in` wallet transaction whose `payment_id` names the payment, with its `value_usd` at the time. A payment collected as fees has none, since its funds went to 402pay. Sends are `out` transactions with their `network_fee_usd` and a note of up to 280 characters.

> Funds from a payment that's `underpaid` or `needs_review` can already be in your wallet, as `in` transactions with its `payment_id`, before the payment succeeds. Match wallet transactions to payments by `payment_id`, not by status.

Money in during September, cURL:

```bash
curl "https://dash.402pay.co/api/v1/wallet/transactions?direction=in&created_after=2026-09-01T00:00:00Z&created_before=2026-10-01T00:00:00Z&limit=100" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY"
```

Money in during September, Node.js:

```js
const response = await fetch("https://dash.402pay.co/api/v1/wallet/transactions?direction=in&created_after=2026-09-01T00:00:00Z&created_before=2026-10-01T00:00:00Z&limit=100", {
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
  },
});
const { data } = await response.json();
```

Money in during September, Python:

```python
import os

import requests

response = requests.get(
    "https://dash.402pay.co/api/v1/wallet/transactions?direction=in&created_after=2026-09-01T00:00:00Z&created_before=2026-10-01T00:00:00Z&limit=100",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
    },
)
data = response.json()["data"]
```

## Export a period

List payments with `created_after` and `created_before`, follow `next_cursor` until it's `null`, and write a row per payment. The start is included and the end isn't, so back-to-back periods never overlap.

export.mjs, Node.js:

```js
// Every payment created in September 2026, oldest first, as CSV.
const API = "https://dash.402pay.co/api/v1";
const headers = { Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}` };
const csv = (cell) => `"${String(cell ?? "").replaceAll('"', '""')}"`;

const rows = [["id", "status", "reference", "currency", "amount", "usd_amount", "usd_fee", "usd_net", "confirmed_at"]];
let cursor = null;
do {
  const query = new URLSearchParams({
    created_after: "2026-09-01T00:00:00Z",
    created_before: "2026-10-01T00:00:00Z",
    sort: "created_at",
    limit: "100",
  });
  if (cursor) query.set("cursor", cursor);
  const page = await (await fetch(`${API}/payments?${query}`, { headers })).json();
  for (const p of page.data) {
    rows.push([p.id, p.status, p.reference, p.currency, p.amount, p.reporting.amount, p.reporting.fee, p.reporting.net, p.confirmed_at]);
  }
  cursor = page.next_cursor;
} while (cursor);

console.log(rows.map((row) => row.map(csv).join(",")).join("\n"));
```

The dates filter on `created_at`. To book payments by when they succeeded, filter the rows on `confirmed_at`, or list `payment.succeeded` events for the period with [`GET /events`](https://developer.402pay.co/api/events/list.md).

## Match records

| To match | Use |
| --- | --- |
| An order to its payment | `reference`, or your own `metadata`. Both filter `GET /payments`. |
| A payment to the chain | `method.tx_hash` and `method.explorer_url`. |
| A payment to your wallet | `settlement.tx_hash`, and the `payment_id` on each wallet transaction. |
| A payment to a customer | `customer_id`. |
| A send to its purpose | Its `note`. |

## Exchange rates

A crypto checkout locks the coin amount when it opens, and `reporting` converts your currency to US dollars at the rates [`GET /exchange-rates`](https://developer.402pay.co/api/exchange-rates.md) returns. Those rates follow the market, except on a simulated business, where they're fixed.
