Fulfillment channels (x402)
After the facilitator confirms on-chain settlement, the seller's server delivers the asset. The x402 challenge advertised which channels are available; the buyer picked one.
For the canonical reference (channels and trade-offs), see Concepts → Fulfillment channels.
Built-in channels
| Channel | Delivery |
|---|---|
| Inline | Seller's HTTP response carries the asset directly |
| Server sends an email to a buyer-supplied address | |
| XMTP | Server posts to the buyer's XMTP identity |
| Webhook | Server POSTs to a buyer-supplied URL |
| IPFS pointer | Server returns an IPFS CID; buyer fetches separately |
Implementing a channel
import type { FulfillmentChannel } from "@bosonprotocol/x402-fulfillment"
const inline: FulfillmentChannel = {
id: "inline",
async fulfill({ asset, request, response }) {
response.json(asset)
},
}Register the channel with the server:
import { ChannelRegistry } from "@bosonprotocol/x402-fulfillment"
const registry = new ChannelRegistry([inline, email, xmtp])
const x402 = createX402bServerExpress({ /* …, */ channelRegistry: registry })Buyer-chosen, seller-bound
The buyer's client picks the channel; the seller's server must support it. Negotiation happens at the 402 step — the server advertises only channels it implements.
Custom channels
The FulfillmentChannel interface is open. Add your own (Slack DM, on-chain log, in-game inventory) by implementing fulfill().
Common gotchas
- The buyer's contact info comes in the X-PAYMENT envelope (for email/XMTP). Validate / sanitize before using.
- Inline channel can't deliver large assets. Use IPFS pointer for >1 MB payloads.
- Webhook handlers must be authenticated — HMAC-sign the payload.