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