1. Run the testnet example
The seller quickstart is a complete, working seller: a receiving account with a USDC trustline,@x402/express with the Stellar exact scheme, the hosted testnet facilitator, and Bazaar
metadata. Pay it with the buyer quickstart or rail402 pay <url> --max 0.01. The
seller helpers build the same route configuration with discovery metadata the catalog
accepts as is, for HTTP routes and paid MCP tools.
examples/seller-http is the same kind of seller as a standalone project: npm install, PAY_TO=G... npm start, or its Dockerfile; its dependencies are pinned to published versions. The public demo seller
(apps/demo-seller, at https://demo.rail402.dev) is a larger example of the same packages: HTTP routes, a
metered upto route and paid MCP tools.
2. Choose the network
Every payment option names its network by its CAIP-2 id, and the resource server registers its scheme for that network:- The facilitator must serve that network: its
/supportedlists anexactkind for it. The hosted facilitator athttps://testnet.rail402.devservesstellar:testnet; a resource server whose facilitator does not serve the network cannot start its middleware. - On
stellar:pubnetpayments move real funds. Use a facilitator that serves pubnet (see Operate a facilitator) and apayToyou control on pubnet. - The demo seller selects the network with
NETWORK=stellar:pubnet, needsFACILITATOR_URL(https) there, and lists itspayTounder the pubnet passphrase in itsstellar.toml.
3. Choose the asset
price: "$0.01" is Circle’s USDC on the option’s network, 7 decimals: contract
CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA on testnet and
CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75 on pubnet. x402 amounts are always base units of
the asset ("$0.01" is amount: "100000"). Any other SEP-41 token works when the facilitator accepts it:
{ amount, asset: "C…", decimals } with the seller helpers, and see
Accepted assets for what the facilitator checks.
4. Make sure payTo can receive
A G… account needs a trustline for a Stellar Asset Contract such as USDC; a C… contract account does not.
Without one, payments are refused with invalid_exact_stellar_payload_recipient_trustline_missing and nothing
moves. The seller needs no XLM for fees and never signs anything during a payment. A muxed M… payTo is
refused for exact (invalid_exact_stellar_requirements_invalid_pay_to).
5. What the buyer signs
exact: the buyer signs one Soroban authorization entry for the asset contract’stransfer(buyer, payTo, amount). The signature fixes the asset, the recipient and the amount; changing any of them fails signature verification. The entry’ssignatureExpirationLedgeris the latest ledger plusceil(maxTimeoutSeconds / ledger time): with 5-second ledgers,maxTimeoutSeconds: 60gives 12 ledgers. After that ledger the authorization can no longer be used (Expiration).upto: the buyer signs terms for theuptosettlement contract: recipient, token, a cap, the facilitator’s settlement authority and an expiration ledger, with one nestedtoken.approvefor the cap. After serving, the seller settles any amount from zero to the cap, and the contract enforces the cap (upto payments, seller helpers).
6. Fees are sponsored
The facilitator’s/supported advertises extra.areFeesSponsored: true, which the stock resource server
copies into every payment option. The facilitator builds the transaction around the buyer’s signed entry,
wraps it in a fee bump and pays the fee from its sponsor account; it is never the source of the funds. Buyers
refuse options without areFeesSponsored (payment_fees_not_sponsored in the Rail402 buyer tools).
7. Get listed
Declare the Bazaar extension (declareDiscoveryExtension, or the seller helpers) and register
bazaarResourceServerExtension. The first settled payment catalogs the resource, bound to the payTo that
received it; Rail402 then requests the resource without payment and publishes the listing once your 402
confirms it. Only public https hosts are listed. The outcome comes back in EXTENSION-RESPONSES; see
Get listed and Cataloging. For domain_verified
trust, bind your host and payTo both ways with SEP-1 (stellar.toml ACCOUNTS plus the account’s
home_domain).
8. Check it before the first sale
rail402 seller check <url> requests a running resource the way the catalog will and reports what it would
refuse; validateListing does the same in code (Check a running seller).
It exits 0 when the resource would be listed and 3 when not.
The verdict is the hosted catalog’s, which lists public hosts only. A seller on your machine is reached with
--allow-http --allow-private-network, but those flags only let the check connect; the result still says
catalog: would not be listed: bazaar_resource_unsafe: Host "localhost" is not a public host., as the catalog
would answer after a settlement. To judge against your own testnet instance run with
DISCOVERY_ALLOW_LOOPBACK=true (Try the Bazaar locally), add
--discovery-allow-loopback. Private addresses such as 10.0.0.5 are never listed.