Feb 15, 2026
Ever wanted to monetize an API with crypto — no subscriptions, no API keys, no payment forms? The x402 protocol makes it possible by turning the HTTP 402 Payment Required status code into an actual payment flow, and thirdweb's hosted facilitator handles the on-chain settlement.
In this guide, you'll build a working demo that accepts SBC (Stable Coin) payments on Base for API access. By the end, you'll have a server that charges 0.01 SBC per request, a CLI client that pays automatically, and a web UI where users can connect their wallet and pay in the browser.
What You'll Build
The demo has three parts:
An Express server with a paid
/paidendpoint that charges 0.01 SBC per requestA CLI client that automatically detects the 402 response, signs an ERC-2612 permit, and retries with payment
A React web app where users connect their wallet and pay through the browser
Here's the payment flow at a glance:
Prerequisites
Before you begin, make sure you have:
Node.js 18+ installed
A GitHub account to clone the repo
A MetaMask or other browser wallet (for the web demo)
Some SBC tokens on Base for testing payments (the payer wallet needs them)
Step 1: Set Up Your Thirdweb Account and API Keys
Everything in this demo authenticates through thirdweb, so you'll need to create an account and generate your keys first.
1.1 Login or Create a Thirdweb Account
Go to thirdweb.com and click Login.
Connect your wallet (MetaMask, Coinbase Wallet, etc.) — you'll be prompted to sign a message to verify ownership.
Once signed in, you'll land on the thirdweb team overview dashboard.
1.2 Create a Project and API Key (Client ID + Secret Key)
The API key gives your app access to thirdweb's infrastructure — RPCs, the x402 facilitator, and more.
Click Create Project.
Give your key a descriptive name (e.g.,
x402-sbc-demo).For development, you can leave domain restrictions empty. In production, restrict to your domain.
Click Create to generate the key.
You'll see two values — save both immediately:
Client ID — used in frontend code (safe to expose publicly)
Secret Key — used in backend code (keep this private)
Check the confirmation box and click Complete.
Important: The Secret Key is only shown once. If you lose it, you'll need to create a new API key.
Step 2: Server Wallet Details
To configure the environment varitibles in Step 4, we'll need the server wallet's address, private key, and vault access token.
The server wallet is what thirdweb uses to sign and settle payments on-chain on your behalf. It's secured through thirdweb's Vault — their non-custodial key management system.
Navigate to the Server Wallets view to locate the information.
2.1 Get the server wallet address
Locate the wallet address.

2.2 Get the Vault Access Token
The Vault Access Token allows your backend to sign transactions using the server wallet.
Navigate to the Configuration tab.
Click Rotate Admin Key. This will generate new vault keys. Securely save the new vault admin key and new vault acccess token.
The vault access token will start with
vt_act_...— save this immediately.

Step 3: Clone the Repository and Install Dependencies
Now that your thirdweb credentials are ready, let's set up the code.
For the web demo, install its dependencies separately:
Step 4: Configure Your Environment Variables
Copy the example environment file and fill in your values:
Open .env in your editor and fill in each field:
Security note: The CLIENT_PRIVATE_KEY is only for the CLI demo. In production, users sign transactions with their own wallets. Never share or commit private keys.
Step 5: Verify SBC Support with the Probe
Before running anything, check that thirdweb's facilitator actually supports SBC on Base:
You should see output confirming that SBC is recognized, with details like:
primaryType: "Permit"— confirms ERC-2612 supportdecimals: 18— matches SBC's configurationChain: Base (8453)
If the probe returns an error, double-check that your THIRDWEB_SECRET_KEY is set correctly in .env.
Screenshot: Successful probe output in the terminal
Step 6: Run the Server
Start the Express server:
The server starts on port 3002 with two endpoints:
Endpoint | Cost | Description |
|---|---|---|
| Free | Health check — always returns 200 |
| 0.01 SBC | Premium content — returns 402 if no payment |
Under the hood, the server uses settlePayment() from the thirdweb SDK. When a request hits /paid:
No payment header? Returns
402with payment requirements (token address, amount, chain)Has payment header? Forwards the signed permit to the thirdweb facilitator
Settlement confirmed? Returns the premium content
The price is configured as a custom ERC-20 token amount in src/constants.ts:
Step 7: Make a Paid Request with the CLI Client
Open a second terminal and run the client:
The client demonstrates the full payment flow:
Hits the free endpoint (
GET /) — works normally, returns 200Hits the paid endpoint (
GET /paid) — receives a402responseParses the payment requirements from the 402 response
Signs an ERC-2612 permit using the
CLIENT_PRIVATE_KEYRetries the request with the signed payment in the header
Receives the premium content with a 200 response
This is powered by wrapFetchWithPayment() from the thirdweb SDK, which wraps the standard fetch API to automatically handle the 402 flow.
Step 8: Run the Web Demo
For a visual, browser-based experience:
Terminal 1 (if the server isn't already running):
Terminal 2:
Open http://localhost:5173 in your browser.
Using the Web Demo
Click Connect Wallet — choose MetaMask, Coinbase Wallet, or any supported wallet on Base.
Make sure your wallet is connected to the Base network.
Click Get Premium Content.
Your wallet will prompt you to sign an ERC-2612 permit (this is not a transaction — it's a gasless signature).
The app retries the request with the signed permit, and you'll see the premium content along with the settlement receipt.
The web app uses thirdweb's useFetchWithPayment() React hook, which handles the entire 402 detection, signing, and retry flow in the browser.
SBC Token Reference
Property | Value |
|---|---|
Name | Stable Coin |
Symbol | SBC |
Contract Address |
|
Chain | Base (Chain ID: 8453) |
Decimals | 18 |
Permit Standard | ERC-2612 (EIP-712 domain version "1") |
Backing | 1:1 USD, full reserve |
Basescan |
Adapting This for Your Own Token
Any ERC-20 token that supports ERC-2612 permit() will work with x402. To swap in your own token, update the values in src/constants.ts:
To find your token's EIP-712 domain name, query the contract directly:
Troubleshooting
Probe fails with authentication error: Double-check your THIRDWEB_SECRET_KEY in .env. Make sure you're using the Secret Key, not the Client ID.
Client gets a 402 but doesn't retry: Ensure CLIENT_PRIVATE_KEY is set and the wallet has SBC tokens on Base.
Web app can't connect wallet: Make sure VITE_THIRDWEB_CLIENT_ID is set in your .env file (note the VITE_ prefix — Vite requires this to expose the variable to the frontend).
Settlement fails: Check that your server wallet has been properly created in the thirdweb dashboard and the VAULT_ACCESS_TOKEN is valid.
What's Next
Now that you have a working x402 payment flow, you can:
Set custom prices by adjusting the amount in
src/constants.tsProtect multiple endpoints by applying the payment middleware to any route
Build a production API using the same pattern with your own Express/Next.js/Hono backend
Deploy the web app with
cd web && npm run build— the built files are served automatically by the Express server
Resources
x402 Protocol — the standard behind HTTP-native payments
thirdweb x402 Documentation — thirdweb's x402 integration docs
thirdweb x402 Facilitator — facilitator setup and API reference
thirdweb API Keys — managing your API keys
thirdweb Server Wallets — server wallet documentation
SBC Documentation — Stable Coin developer docs
SBC on Basescan — token contract on Base
Coinbase x402 Repo — the original x402 reference implementation

