Skip to content

Receipts

Every confirmed payment yields a document a customer can file — reachable at a stable URL, attached to the confirmation webhook, and true about a payment that crossed currencies.

What it is (and isn't)

It's a receipt, deliberately not a jurisdiction-specific tax invoice: it states what was bought, both sides of the conversion, the rate as struck, and the settlement transaction. A merchant's accounting system turns it into whatever their jurisdiction requires; VAT/sales-tax handling is explicitly the merchant's problem, not 0billing's.

"PDF" is the browser's print dialog — the document is print-first HTML with a Save as PDF button, which keeps a PDF toolchain out of the server and loses nothing: the page is self-contained, styles inline, rendered from a frozen snapshot.

What's on it

  • Receipt number, issue time, and the merchant's receipt identity (legal name, address, tax id — set on the Integrate page or PUT /v1/merchant/identity)
  • Customer billing details, when captured at checkout (collectBillingDetails on the widget, or metadata.billTo)
  • What was bought, the discount code, the USD total
  • Both sides of the conversion: what the customer paid (0.00033 BTC on btc) and what settled (20 USDC on sol), with the rate and when it was struck
  • The platform fee, when the payer carried one — "what did I actually pay" must reconcile
  • The settlement transaction hash — independently verifiable on-chain

Snapshots, not views

A receipt freezes the merchant identity and every amount at issue time. Renaming the company or moving the treasury never rewrites an issued document.

Numbering is gapless

Several jurisdictions require receipt sequences without holes, so numbers are allocated transactionally at confirmation — claimed inside the insert, retried on collision — never derived after the fact. Sequences are per merchant, starting at 1. Issuance is idempotent per payment.

Retrieval

  • GET /v1/receipts/:paymentId — HTML; ?format=json for the raw snapshot. Public by the same capability logic as the payment itself: the unguessable payment id is the credential.
  • The payment.confirmed webhook carries receiptUrl when the deployment knows its public origin (PUBLIC_BASE_URL).
  • The checkout widget links to the receipt on its confirmation screen, and the dashboard links it from every confirmed payment.

Payments confirmed before receipts existed are backfilled on first request — fetching their URL issues the document then.

0billing — crypto billing for your app · pay from any chain, settle in one