Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Handle redemption / deliver · Boson Protocol
Skip to content

Handle redemption / deliver

After a buyer commits, they redeem the voucher when they're ready to receive the goods. This emits VoucherRedeemed on-chain and transitions the exchange from COMMITTED to REDEEMED. This event is what you wire to your fulfillment system.

For the conceptual model, see Fulfillment channels and Eventing & indexing.

Listen for the event

Direct RPC
import { ethers } from "ethers"
import exchangeAbi from "@bosonprotocol/common/dist/cjs/abis/IBosonExchangeHandler.json"
 
const diamond = new ethers.Contract(DIAMOND_ADDRESS, exchangeAbi, provider)
 
diamond.on("VoucherRedeemed", async (offerId, exchangeId, executedBy, event) => {
  if (await alreadyDelivered(exchangeId)) return
  await deliver(exchangeId)
  await markDelivered(exchangeId)
})

After delivery: complete the exchange

Once delivered, you (or anyone) can complete the exchange after the dispute window closes. This releases the seller's earnings into the treasury.

SDK
await (await sdk.completeExchange(exchangeId)).wait()
// or batch:
await (await sdk.completeExchangeBatch([eId1, eId2, eId3])).wait()

Common patterns

Pattern: Synchronous delivery

For digital goods that can be delivered instantly, use atomic commit-and-redeem. The buyer commits and redeems in one transaction, and your server returns the goods in the HTTP response. See Buyers → Atomic commit-and-redeem and Quickstart → x402 server.

Pattern: Asynchronous delivery (physical goods)

Listen to VoucherRedeemed, kick off your shipping flow, mark delivered = true keyed by exchangeId. Schedule completeExchange to run after the dispute window closes.

Pattern: Buyer initiates fulfillment via webhook

At commit time, your widget/SDK captures a delivery address or contact. Post it to your backend keyed on exchangeId. On redemption, you have all the info you need to deliver.

Common gotchas

  • Make delivery idempotent. Reorgs and re-fired webhooks happen. Key on exchangeId or (txHash, logIndex).
  • Subgraph polling can miss redemptions during indexer downtime. Prefer RPC events for low-latency triggers; use the subgraph for catch-up.
  • Don't auto-complete inside the dispute window. You can call completeExchange, but doing so before the window closes is a no-op and wastes gas.

Next