Skip to main content
This tutorial takes you from a fresh clone to a real, on-chain settled x402 payment on a testnet. You run three pieces: the facilitator (verifies and settles), an example merchant (gates a paid endpoint), and a test client (pays for it). By the end, a request to a paid endpoint settles a USDC transfer through your Fireblocks vault and returns the resource. Set aside about 30 minutes. Everything here uses testnet funds with no real value.

Before you start

Complete Prerequisites and Testnet Funds first. You need:
  • Node.js 20 or later, and Git.
  • A Fireblocks API key and PEM secret from a scoped API user, plus a vault account ID.
  • Testnet USDC for the payer, and testnet ETH for gas in both the payer (for non-eip-3009 runs) and the facilitator’s vault.
The example merchant and test client live in the x402-facilitator repo under examples/, so a single clone covers all three pieces.

Step 1: Start the facilitator

Open config/facilitator.json and fill in your Fireblocks credentials:
Start the facilitator:
Confirm it is up:
Never commit config/facilitator.json with real credentials or the PEM secret. The repository’s .gitignore excludes both by default. In any non-development deployment, keep them in a secrets manager and inject at runtime.

Step 2: Install the CLI and mint an admin token

In a second terminal, build the x402 CLI and put it on your PATH:
Mint a local admin token and export it so the CLI is authenticated:

Step 3: Activate the vault and import USDC

Activate the vault wallets the facilitator needs and cache the receiver addresses:
Import testnet USDC as a payable asset:

Step 4: Declare a product and mint a merchant key

Declare the paid endpoint as a product, priced at one US cent:
Copy the product_id it prints (prod_…). Then mint an API key the merchant server will use to call the facilitator:
The merchant API key plaintext is shown only once; only a hash is stored. Copy it now, treat it as a secret, and never commit or expose it. If you lose it, revoke it and mint a new one.

Step 5: Allow the facilitator to settle

The facilitator settles by submitting a CONTRACT_CALL transaction from your vault. For that transaction to go through without a manual approval each time, add a Fireblocks Policy rule that auto-approves a CONTRACT_CALL from your receiver vault using the network’s gas asset (for example, ETH_TEST5 on Sepolia). See Set Policies. Without an auto-approving Policy rule, settlement transactions wait for manual approval in the Fireblocks Console, and the quickstart will appear to hang at settlement.

Step 6: Run the example merchant

In a third terminal, configure and start the example merchant with the key and product ID from step 4:
Set these in examples/merchant/.env:
The merchant gates /premium and leaves /hello free. A request to /premium without payment now returns a 402. SETTLEMENT_MODE controls whether the merchant settles synchronously before serving the response (settle-first) or serves first and settles in the background (optimistic). It is an important production choice with a latency-versus-risk tradeoff; see When to settle.

Step 7: Pay for the resource

In a fourth terminal, set up the test client. It signs payments with a local development wallet, so you do not need a second Fireblocks vault for the payer.
Fund the printed address with testnet USDC from faucet.circle.com. Then make the payment:
The client requests /premium, receives the 402, signs an EIP-3009 authorization, retries with a payment-signature header, and prints the merchant’s response plus the settlement transaction hash from the PAYMENT-RESPONSE header.

Step 8: Confirm settlement

Check the payment landed, from the CLI terminal:
A completed status with a transaction hash means the USDC moved on-chain into your vault’s receiver address. You have run a full x402 payment.

Run every mechanism at once

The repo ships an end-to-end harness that exercises eip-3009, permit2, and erc7710 in sequence, polling until each payment reaches completed:
It assumes the facilitator and merchant are running, the auto-approving Policy rule from step 5 is in place, and the payer EOA is funded with testnet USDC and a little ETH (Permit2 and ERC-7710 each need a one-time on-chain setup transaction). The harness prints a pass/fail summary with block-explorer links and is safe to re-run.

Troubleshooting

  • Settlement hangs. You are likely missing the auto-approving Policy rule from step 5, so the CONTRACT_CALL is waiting for manual approval in the Console.
  • insufficient_funds or a fund-me block. The payer address is short on USDC, or short on gas ETH for a Permit2 or ERC-7710 first run. Top it up from a faucet.
  • Server refuses to boot citing mainnet. You imported a mainnet asset. The facilitator is testnet-only by default. Use a testnet asset, or see Network policy.
For more, see x402 Troubleshooting and FAQ.