ChainUnfold
A VISUAL GUIDE3 min read

What happens inside a crypto checkout?

An invoice, a payment observation, and an order are related records—not the same thing.

By chainunfold Reviewed 23 September 2026Revision 1

What you’ll be able to explain

  • Trace invoice creation, payment detection, reconciliation and fulfillment without trusting the browser as payment evidence.

01 / Understand

A checkout is a conversation between systems

A customer buys an illustrated guide from a fictional shop. The shop creates an order for one copy, asks its payment service for an invoice, and shows the resulting payment request. The customer’s wallet then attempts the payment.

That visible screen hides several responsibilities. The shop knows what is being sold and to whom. The payment system tracks an expected payment and its state. The wallet arranges the payment. A fulfillment process grants access after the shop’s rules are satisfied.

An invoice identifier connects those responsibilities. It should be mapped to the intended order on the server, alongside expected currency, amount and relevant payment method. A client-supplied “paid” flag is not a substitute for this record.

A fictional successful sequence

  1. The shop creates order demo-order-42, awaiting payment.
  2. The server creates an invoice and stores the order/invoice mapping.
  3. The customer receives a payment request with its applicable terms.
  4. The provider observes payment and sends a notification.
  5. The server authenticates and reconciles the notification with current invoice state.
  6. The shop records eligibility for fulfillment, then grants access once.

The browser may return to a success page, but that redirect is a user-interface event. It is not the authoritative evidence that the payment completed. A customer can close a tab before the redirect, and an attacker can visit a success URL without paying.

The idea, at a glance

Request

Store a server-side order/invoice mapping.

Observe

Authenticate and reconcile payment evidence.

Fulfill

Apply business rules and deliver once.

A browser return, provider notification and fulfillment record are different kinds of evidence.

02 / Explore

Expiration is a decision boundary, not an eraser

Consider an invoice that expires after a fictional ten-minute window. At minute eleven, an on-chain payment to its destination is detected. The business cannot make that transfer disappear by changing an invoice label.

Instead, it needs a late-payment policy and a reconciliation path. The order might need manual review, updated terms, fulfillment, or a refund process. Similarly, an underpayment is not equivalent to no payment, and an overpayment is not necessarily a second order.

BTCPay’s documented invoice states illustrate these distinctions, including payment exceptions and settlement settings. The exact names and event behavior belong to that provider and version. Our flow is an application design example, not a protocol-wide state machine.

Network and application failures complicate the happy path. An invoice-creation response can be lost after the provider creates the invoice. A webhook can arrive twice. A fulfillment call can time out after granting access. Each boundary needs a stable identity and a way to ask what actually happened.

03 / Build

Draw the failure paths

Add two branches to the successful sequence:

  • The browser closes after paying. Expected behavior: the server’s provider reconciliation can still update the order; fulfillment does not depend on the customer’s tab remaining open.
  • The payment arrives after expiry. Expected behavior: preserve the payment evidence, flag the applicable exception, and apply the business policy. Do not silently discard the money or immediately create a duplicate purchase.

For a developer, write the minimal mapping record:

order_id, provider, provider_store_id, invoice_id,
expected_amount, expected_currency, payment_method

These are conceptual fields. A production schema must define units, uniqueness constraints, versioning and which values come from trusted server state. Use provider documentation for authentication and verification; this publication does not implement a merchant checkout.

Pause & explain

If the customer closes the browser after paying, should the order be permanently stuck?

Try explaining it in your own words before opening the answer.

Compare your explanation

No. Server-side notification or reconciliation should discover the provider’s authoritative state independently of the browser. The application can then apply its fulfillment policy.

Sources & scope

Primary references behind this explanation. Worked examples and diagrams are original teaching material.

  1. 01
    BTCPay Server — Greenfield API example ↗

    Creating invoices and registering and processing webhook notifications.

  2. 02
    BTCPay Server — Greenfield PHP example ↗

    Provider integration example, including webhook validation. The lesson’s pseudocode is not a drop-in handler.

  3. 03
    BTCPay Server — Invoices ↗

    Provider-specific invoice lifecycle and exception statuses. Business fulfillment is a separate application decision.

  4. 04
    BOLT 11 — Invoice protocol ↗

    Payment-request encoding, amount and expiry fields. BOLT 11 is one Lightning request format, not every possible payment flow.

Where this explanation stops

  • Fictional merchant example only; provider-specific API authentication and production checkout are not implemented.

Keep unfolding

Why a webhook can arrive more than once Payment received versus order fulfilled: designing clear statuses