Wallet
Panel Guide
Reports

Panel — Reports

Who calls these endpoints?Merchant panel
Base path
/api/panel/v1/wallet
Identity
Panel session (JWT) — Authorization: Bearer <panel access token>. The token comes from panel login; an s2s signing key does NOT open these endpoints.
Authorization
RBAC permission: wallet:report:read · wallet:fee:manage · wallet:terminal:read · wallet:bulk:create
Cross-surface
The endpoints on this page have NO equivalent in the s2s API; you cannot call them from your own panel. These capabilities exist only in the merchant panel, behind a panel session.
GET reports/overview        # overview (programId, date range)
GET reports/operations      # operation volume and breakdown
GET reports/fees            # fee and tax revenue
GET reports/campaigns       # campaign impact and budget consumption
GET reports/terminals       # per-terminal activity
GET reports/custody         # custody — total customer money held

You can also export from listing endpoints: operations/export, bulk-payout-statements/period.

Custody report

GET reports/custody          # programId, asOf

Shows the total customer money held in the program. It is the most critical report for compliance and reconciliation: this figure must line up with the balance in your backing account.

asOf — the report is a MOMENT, not a period

A custody report is a stock, not a flow. A stock has no period, it has an instant — which is why the endpoint accepts asOf (ISO8601) rather than from/to. For flow within a period use reports/operations.

Leaving asOf empty returns the live/cumulative position (the default behaviour).

⚠️

The blocked columns cannot be carried as-of. Amounts blocked by cash-out codes and card authorizations cannot be rewound to a past instant, and the report does not hide this — it tells you, through blockedBasis:

  • CURRENT — no asOf was given; everything is a snapshot of the same instant.
  • CURRENT_NOT_AS_OF — asOf was given, but the blocked columns are CURRENT values.

When reconciling a past date and you see CURRENT_NOT_AS_OF, do not treat the blocked columns as that date's data; explaining a reconciliation gap with them will give you the wrong answer.

⚠️

Check the gap between custody and the backing balance regularly. Any difference should be explainable by suspense funds, outflows awaiting reconciliation (AWAITING_RECON) or held operations (HELD). An unexplained gap must be investigated.

Fee report

GET reports/fees

Fee and tax breakdown. When a figure surprises you:

  1. Look at the operation's scheduleVersionId.
  2. Check which threshold branch was taken in that version's matrix (appliedThreshold, appliedTimeKey).
  3. Check when that schedule version became active.

Seeing "two different fees for the same operation type" is normal when a schedule version changed; if you are comparing across a version boundary, split by scheduleVersionId.

Campaign report

GET reports/campaigns
GET campaigns/:id/report

How many operations benefited and how much budget was spent. If a campaign is paused (budget protection) the curve flattens — do not mistake that for falling demand.

Operations report

GET reports/operations

Volume by type, status and period. For reconciliation:

WatchWhy
AWAITING_RECON countA rising count means something is wrong on the bank side
FAILED rateA sudden jump points to a limit/gate misconfiguration
HELD countRisk rules may be too tight
EXPIRED rateUsers are not completing the confirmation step — likely a UI problem

Track these four regularly. Most wallet problems show up in these curves before any user complains.

Terminal report

GET reports/terminals

Filterable by store code, terminal status and date range. It is only useful if terminal fields were filled in consistently — see Panel — QR & Terminals.

Reconciliation discipline

  1. Compare custody daily. The gap must be explainable.
  2. Keep the AWAITING_RECON queue empty. A growing queue means an unresolved problem on the bank side.
  3. Match fee revenue to schedule versions. Comparisons across version boundaries mislead.
  4. Watch campaign budgets. A paused campaign is silent but visible in reports.
  5. Export with narrow date ranges. Wide ranges are slow and hard to analyse.