Skip to main content
You are a merchant if you have an HTTP API and want to charge Canton Coin (CC), or any CIP-56 registry token (e.g. USDCx), per request. Your callers (agents, wallets, or any x402-compatible client) pay before your handler runs. You do not need a token balance. You are receiving, not sending. Settlement uses the transfer-factory method: the payer signs a TransferFactory_Transfer naming you as receiver, the facilitator relays it, and because you hold a standing TransferPreapproval it settles directly to your party in a single transaction. Canton Coin and registry tokens work identically — you pick the instrument via extra.instrumentId in your PaymentRequirements.

Before You Start

You need:
  • A Canton party ID (your receiver identity on Canton mainnet)
  • A live TransferPreapproval for Canton Coin with you as receiver (see Step 1) — this is what lets an incoming transfer settle in one transaction
  • A facilitator URL, party ID, and synchronizer ID (Step 2)

Step 1: Provision a TransferPreapproval

Before any agent can pay you, your party MUST hold a live TransferPreapproval for the Canton Coin instrument (receiver = you). It is what lets an incoming TransferFactory_Transfer resolve direct — accepted automatically and settled in one transaction. Without it the transfer resolves to a two-step pending TransferInstruction, the facilitator cannot settle in one round-trip, and /settle is rejected with invalid_exact_canton_preapproval_missing (your callers get a 402 instead of the resource). A TransferPreapproval is time-bounded — renew it before expiry to keep the one-transaction path available. Pick the path that matches how your party is hosted.

External-party merchant (relay-managed wallet)

Your party is an Ed25519 self-custody wallet managed through the relay. Provision the preapproval with the CLI — it self-provisions, no operator token needed:
For Canton Coin, --admin is the DSO party id (get it from your Canton Scan API) and --days sets the validity before renewal. For a registry token, --admin is the registrar and --id the instrument id; the registrar must be trusted (CANTON_AGENT_REGISTRY_TRUSTED_PARTIES, with USDCx built in). One preapproval per instrument you want to receive.

Hosted-node merchant

If your party lives on your OWN Canton node/wallet, create the TransferPreapproval through that wallet/validator directly (receiver = your party) — no relay or CLI needed. There is no custom DAR to install: transfer-factory runs through the standard CIP-56 :TransferInstruction interface.

Step 2: Get Facilitator Parameters

Call GET /supported on your facilitator to get the values you need:
From this response: signers["canton:*"][0] is your feePayer, and extra.synchronizerId is your synchronizer. Get the DSO party id (for instrumentId.admin) from your Canton Scan API.

Step 3: Install

Step 4: Define PaymentRequirements

Amount format: an integer string of atomic units (1 CC = 10^10 units). The facilitator compares by value (BigInt atomic units), so "10000000000" = 1 CC and "100000000" = 0.01 CC; a mismatch returns invalid_exact_canton_amount_mismatch. Field notes:
  • feePayer: the facilitator party — the relayer that submits the payer-signed transfer and pays its traffic fee. Clients MUST NOT alter it.
  • instrumentId: the token to charge. Canton Coin is { admin: "<DSO-party>", id: "Amulet" }; a CIP-56 registry token (e.g. USDCx) is { admin: "<registrar-party>", id: "<instrument-id>" }. To charge a registry token, set this and the matching asset symbol, and hold that token’s TransferPreapproval (Step 1).
  • executeBeforeSeconds: relative deadline (seconds from request time) the client uses to compute the transfer’s absolute executeBefore; after it, the signed transfer is no longer executable.
  • memo (optional): a string the client stamps into the transfer’s metadata; the facilitator does not validate it.
These field names follow the x402-ENVELOPE convention. synchronizerId may be omitted; clients fall back to the value advertised by GET /supported.

Step 5: Add Middleware

Express

Route keys use "METHOD /path" format, matched exactly against ${req.method} ${req.path}. Unregistered routes pass through ungated.

Next.js App Router

Step 6: Verify It Works

Call your gated endpoint without payment:
Expected:
Decode to confirm your requirements are correct:
You should see your amount, payTo, and feePayer values.

Security Notes

  • Your accepts[] is authoritative. The middleware ignores any amount the client claims. A client cannot request a 1 CC resource for 0.01 CC by tampering with the payment payload.
  • The proven payer is on-ledger. The facilitator binds the proven payer to the sender of the signed TransferFactory_Transfer, not to anything the client puts in the payload, so a spoofed payer field cannot impersonate.
  • Settlement happens before your handler. If your handler throws after a successful /settle, the payer already paid. Handle errors gracefully; do not retry settlement.
  • Keep payTo correct. CC goes to whatever payTo says. If your party ID changes, update paymentReq AND provision a TransferPreapproval (Step 1) for the new party.