Track Settlement
A Tab reserves an authorized amount before delivery and transfers it at settlement. Track the reservation, recorded usage, any crystallized claim, and the payment transaction separately.
Payment States
| State | Evidence | Meaning |
|---|---|---|
| Voucher accepted | Valid session signature and scope checks | The buyer authorized a cumulative amount for the channel. |
| Reserved | Independently verified reservation transaction and matching account state | The exact V2 voucher has a confirmed obligation. |
| Delivery accounted | Seller's persisted delivery counter | The seller committed this amount before sending service; its response log confirms delivery. |
| Crystallized | Confirmed LockedClaim account | An accrued amount has been reserved on-chain for its holder. |
| Settled | Successful transaction and recipient transfer | Funds have moved to the recipient. |
A voucher can settle directly. Crystallization provides a claim for settlement later. Neither an accepted voucher nor an increased delivery counter confirms a transfer.
Confirm the Reservation
The buyer's reserveFinalVoucherV2 provider returns a receipt for the exact signed voucher. The client verifies that evidence before releasing the voucher, and the seller verifies it again before admitting the request. Both require a confirmed transaction, its voucher-binding Memo, and coherent Vault/session state. Preserve that receipt with the voucher.
If confirmation is uncertain, recover the same operation using its existing identity. A timeout is insufficient evidence to authorize another payment.
Crystallize Accrued Usage
Crystallization posts a signed voucher through the facilitator's /tab/lock path. A successful lock creates a claim and increases the Vault's reserved obligations. Other available funds remain usable under the Vault's rules.
In @dexterai/x402@6.0.0, the seller SDK's default lock threshold is 0.10 USDC and it attempts a lock when a metered request records delivery. The onClose setting enables the terminal lock attempt. A failed lock is best effort: it does not turn a delivered response into an error.
A facilitator can apply its own cadence and return below_lock_cadence. The SDK records the refused cumulative amount to avoid retrying the same range. Confirm the resulting claim state before marking that amount crystallized; the V2 reservation verified at admission is a separate record.
Finish and Settle
await meter.charge() records each charge before its chunk is sent. meter.end() ends the SSE response without settling the Tab. The buyer's tab.close() requests settlement and returns the result to the buyer.
The seller's settle: 'on-close' | 'periodic' option is accepted by the published API, but the streaming middleware does not implement a periodic settlement worker. Operate settlement and reconciliation explicitly.
If a buyer disconnects, preserve the latest signed voucher, delivery counter, and claim references. Check whether a lock or settlement completed before retrying. Recovery depends on that saved state, current session validity, and the facilitator's available settlement path.
Reconcile Payments
For each channel, retain the following in durable storage:
- The latest voucher, its reservation receipt, and the cumulative amount accounted across requests.
- Lock attempts and confirmed claim addresses.
- Settlement transaction signatures, network, recipient, asset, and settled amount.
Read the recipient's token transfers at your required commitment and match them to the channel or claim. A wallet balance change alone does not identify which purchase settled.
The seller streaming handle exposes cumulative() and deliveredCumulative(). It provides no settlement callback. These counters help reconcile service usage; obtain transfer confirmation from chain state or the facilitator's settlement result.
Configure persistent channel state before serving concurrent requests or resuming after a restart. For settlement before delivery, use Accept a Payment.
Last Updated: