Buyer-initiated offers
In normal Boson, the seller writes an offer first; the buyer commits. Buyer-initiated offers invert that — a buyer drafts an offer (price, terms, validity window) and deposits the price into their protocol treasury. A seller who likes the terms calls commitToBuyerOffer, encumbering their sellerDeposit. From there the protocol flow is identical to a seller-created offer: voucher is minted, redemption clock starts, dispute window opens, etc.
Use cases:
- Request for quote (RFQ) — buyer specifies what they want; sellers respond.
- Bespoke services — the spec is the offer.
- Procurement — purchase orders with on-chain enforcement.
- Agent-driven demand — autonomous buyer agents publish offers; seller agents discover and fulfil. Expected to be the most common usage in the agentic-commerce era.
What changes vs a seller-initiated offer
| Aspect | Seller-initiated | Buyer-initiated |
|---|---|---|
Who calls createOffer | Seller assistant | Buyer |
creator field on offer | SELLER | BUYER |
sellerId set at create time? | Yes | No — fixed when seller commits |
collectionIndex, royalty info, mutualizer set at create? | Yes | No — set when seller commits via commitToBuyerOffer |
| Conditional / token-gated commits | Allowed | Disallowed — buyers don't get to gate sellers |
| Price-discovery offers | Allowed | Disallowed — only static prices |
| Funds encumbered up front | Seller deposit | Buyer's price — funds the buyer pre-deposited |
| Funds encumbered at commit | Buyer's price | Seller's deposit |
| Voucher recipient | Buyer | Buyer (unchanged) |
| Emitted event on commit | BuyerCommitted | SellerCommitted |
After commit, redemption / dispute / completion flows are identical to a normal exchange.
Buyer side: draft the offer
The buyer:
- Deposits funds to their buyer treasury (the price they'll pay if a seller commits).
- Creates the offer, with
creator = BUYER,sellerId = 0, and no royalty / collection / mutualizer. - Publishes off-chain (XMTP, RFQ board, partner site, agent network) so sellers can find it.
- Withdraws any unmatched funds after the validity window if no seller commits.
// 1. Deposit price into buyer treasury
await (await sdk.depositFunds(buyerId, /* amount */ price, exchangeToken)).wait()
// 2. Create the buyer-initiated offer
// The SDK detects creator=BUYER and uses commitToBuyerOffer machinery on commit.
await (await sdk.createOffer({
price,
sellerDeposit: 0, // buyer doesn't set seller's stake — seller commits whatever they want covered
buyerCancelPenalty: 0, // typically 0 for buyer-initiated
quantityAvailable: 1,
exchangeToken,
metadataUri,
metadataHash,
validFromDateInMS: Date.now(),
validUntilDateInMS: Date.now() + 7 * 24 * 60 * 60 * 1000,
voucherRedeemableFromDateInMS: Date.now(),
voucherRedeemableUntilDateInMS: 0,
voucherValidDurationInMS: 14 * 24 * 60 * 60 * 1000,
disputeResolverId,
agentId: 0,
feeLimit: 0,
creator: 1, // 1 = BUYER (0 = SELLER)
})).wait()Seller side: accept and commit
The seller calls commitToBuyerOffer with the offer ID plus the parameters the buyer couldn't set: which collection to mint into, royalty info, mutualizer (if any). The seller's deposit is encumbered at this step; the buyer's price (already in their treasury) is encumbered too.
await (await sdk.commitToBuyerOffer(offerId, {
collectionIndex: 0,
royaltyInfo: {
recipients: ["0x0000000000000000000000000000000000000000"], // seller treasury (default)
bps: [250],
},
mutualizerAddress: "0x0000000000000000000000000000000000000000", // self-mutualised
})).wait()This emits SellerCommitted, sets the offer's sellerId, and mints the voucher to the buyer. From the buyer's wallet it looks the same as a normal commit.
Cancelling unmatched offers
If the validity window closes without any seller committing, the buyer can withdraw the deposit back from their treasury via withdrawFunds. No void step is needed — buyer-initiated offers go stale automatically.
For non-listed (private) buyer-initiated offers signed off-chain via FullOffer, use voidNonListedOffer (and the batch variant) to mark the hash as voided so it can't subsequently be matched.
Discovery patterns
The protocol doesn't run the offer board. Common discovery channels:
- XMTP — buyer posts offer metadata + offer ID to a known topic; seller agents subscribe.
- Custom RFQ board — your own server indexes buyer offers; sellers poll.
- Discord / forum — humans hand-shake; one of them creates the offer.
- Agent registry — buyer agents announce demand, seller agents respond. See Build for AI agents → Agent registry.
The protocol only enforces "first seller to call commitToBuyerOffer wins" — it's a closed auction by default, plus whatever you layer on top.
Common gotchas
- Buyer must pre-fund. Unlike seller-initiated offers, the buyer's price has to sit in their treasury before any seller can commit. Forgetting to deposit means sellers' commit attempts revert.
- Royalties belong to the seller. The buyer can't pre-set royalty recipients — that's a seller-side configuration. Buyers who care should ask sellers to commit with specific terms off-chain before submitting.
commitToConditionalOfferis not supported for buyer-initiated offers — gating doesn't make sense in the inverted direction.- Price-discovery is not supported. Buyer-initiated means static-priced. For dynamic pricing run a normal seller-side auction.
- Quantity > 1 lets multiple sellers commit against the same buyer offer; each gets their own exchange. Useful for "I want 10 of these"; less common.
Related
- Build for AI agents — buyer-initiated is the dominant flow for agent-to-agent commerce.
- Concepts → Funds, escrow & payouts — money flow under inversion.
- Reference → Contracts → Diamond facets →
ExchangeCommitFacet.commitToBuyerOffer.