Skip to main content
GET /v2/merchant/billing/invoices returns the authenticated merchant’s billing history for the trailing 365 days: per-invoice rows plus a totals envelope (paid amount, platform fees retained, invoice count). This endpoint is the data source for the merchant Billing History page in the dashboard.
This endpoint requires:
  • Merchant JWT — any authenticated merchant role (OWNER, MEMBER, PRODUCER)
The merchant scope is derived from the JWT sub claim. There is no merchantId query parameter. If a client passes one anyway it is silently ignored — the response is always scoped to the JWT-bound merchant.

GET /v2/merchant/billing/invoices

Authentication

Obtain a merchant JWT via POST /merchant/admin/login — see Authentication. SUPER_ADMIN tokens work too (they are merchant JWTs with an extra role); the response is scoped to the SUPER_ADMIN’s own merchant record, not to the platform.

Query parameters

None. The window is fixed at trailing 365 days.

Example

Response — 200 OK

Fields

Errors

Notes

  • Trailing 365-day window. windowStart is computed as now − 365d on every call. The window is rolling, not anchored — two calls a day apart return slightly different windowStart / windowEnd values, and an invoice issued exactly 365d ago may drop out of one call’s window and back into the next.
  • Auth scope. The endpoint reads merchantId from the JWT sub claim only. Any ?merchantId= (or body merchantId) is silently ignored. A merchant cannot read another merchant’s invoices through this endpoint — even with a syntactically valid query parameter pointing at the target.
  • Fail-open semantics. If the underlying invoice store throws, the endpoint returns the empty-state envelope (invoices: [], totals.*: 0) with 200 OK rather than propagating the error. Inspect server logs / Sentry for the underlying failure. Merchants never see a partial billing-history page error in the dashboard.
  • Currency. All monetary fields are USD major units (dollars), not cents. Renders straight into Intl.NumberFormat({ style: 'currency', currency: 'USD' }) without dividing by 100. This contract diverges from the admin x402-earnings rollup (USD cents, integer) intentionally — merchant-facing endpoints serve pre-formatted human values; admin rollups serve aggregation-safe integer cents.
  • Only PAID invoices. Today the endpoint returns rows where status === 'PAID'. Pending / void / refunded invoices are out of scope for v1 and tracked for a future revision.