How to Implement a Crypto Paywall with x402 Payment Protocol | BlockEden.xyz Guide
Overview
x402 is an open protocol for internet-native payments that leverages the HTTP 402 "Payment Required" status code. With x402, you can implement paywalls behind API requests, webpages, and more without the traditional friction of credit card processing, KYC, and high transaction fees.
In this guide, you'll utilize x402 as a seller and buyer on the Base Sepolia testnet via building a simple HTML/JS web app using Express as the backend to protect content behind a paywall and allow users to pay using cryptocurrency on the testnet.
Let's get started!
What You Will Do
- Learn about x402 and how it works
- Set up a HTML/JS web app with an Express server with x402 integration
- Test the web app in a local environment with Base Sepolia
- Integrate BlockEden.xyz RPC endpoints for blockchain interactions
What You Will Need
- Basic understanding of programming and blockchain concepts
- Node.js installed (v22+)
- An EVM-compatible wallet with ETH and USDC on Base Sepolia blockchain
- A BlockEden.xyz account for RPC access
What is x402?
x402 is a chain-agnostic protocol built around the HTTP 402 Payment Required status code that enables services to charge for access to their APIs and content directly over HTTP. This open payment standard allows clients to programmatically pay for resources without accounts, sessions, or credential management. With x402, any web service can require payment before serving a response, using crypto-native payments for speed and privacy.
Who is x402 for?
- Sellers: Service providers who want to monetize their APIs or content. x402 enables direct, programmatic payments from clients with minimal setup.
- Buyers: Developers and AI agents seeking to access paid services without accounts or manual payment flows.
Both sellers and buyers interact directly through HTTP requests, with payment handled transparently through the protocol.
Core Components of x402
Client/Server Architecture
Client Role (Buyer)
- Initiates requests to access paid resources
- Processes 402 responses and extracts payment details
- Submits payment with the X-PAYMENT header
Server Role (Seller)
- Defines payment requirements with HTTP 402 responses
- Verifies incoming payment payloads
- Provides the requested resource once payment confirms
Facilitators
Facilitators simplify the payment process by:
- Verifying payment payloads
- Settling payments on the blockchain for servers
- Removing the need for servers to implement complex blockchain interactions
Having a Facilitator is optional, but it is recommended to use one. Currently, Coinbase Developer Platform (CDP) hosts the primary facilitator, offering fee-free USDC settlement on Base mainnet.
x402 Payment Flow
The x402 protocol leverages ERC-3009 TransferWithAuthorization standard to enable gasless transfers, a key component for frictionless web3 monetization. Let's cover the flow of using x402 along with specs to comply with the standard.
- Client requests a resource from a server
- Server responds with 402 Payment Required and payment instructions:
{
  "maxAmountRequired": "0.10",
  "resource": "/api/market-data",
  "description": "Access requires payment",
  "payTo": "0xABCDEF1234567890ABCDEF1234567890ABCDEF12",
  "asset": "0xA0b86991C6218b36c1d19D4a2e9Eb0cE3606EB48",
  "network": "ethereum-mainnet"
}
- Client prepares payment based on requirements
- Client retries with X-PAYMENT header containing signed payload
- Server verifies payment via facilitator
- Server settles payment on blockchain
- Server delivers resource once payment confirms
Now that we have a good understanding of what x402 is and how it works under the hood, let's move onto building a simple x402 demo. However, we will first need to fulfill some project prerequisites but if you already have ETH on Base Sepolia and an RPC endpoint, feel free to skip to the Project Set Up section.
Project Prerequisite: Retrieve USDC on Base Sepolia
You will need some USDC on Base Sepolia in order to demonstrate a simple x402 payment.
To retrieve USDC, navigate to the Circle USDC faucet and request some funds. Once you have USDC on Base Sepolia, you can move onto the next step.
Project Prerequisite: BlockEden.xyz Base Endpoint
To interact with Base Sepolia, you'll need an API endpoint to communicate with the network. BlockEden.xyz provides fast, reliable RPC endpoints for Base and other blockchain networks.
Setting Up Your BlockEden.xyz Endpoint
- 
Sign up for BlockEden.xyz: Visit https://blockeden.xyz and create a free account 
- 
Create an API Key: Once logged in, navigate to your dashboard and create a new API key 
- 
Select Base Sepolia: Choose Base Sepolia as your network 
- 
Copy Your Endpoint: Your RPC endpoint will look like: https://api.blockeden.xyz/base_sepolia/YOUR_API_KEY
- 
Configure Your Wallet: Add this endpoint to your Web3 wallet's RPC settings as the Base Sepolia blockchain 
BlockEden.xyz offers:
- Fast response times with global CDN
- High reliability and uptime
- Generous free tier for development
- Support for multiple blockchain networks
- Advanced analytics and monitoring
Project Set Up
With the prerequisites out of the way, let's get into project setup. The demo we will be building in this guide will do the following:
- Allow a user to connect their wallet and sign a message that will be used to verify the payment
- The server will then authenticate the 402 status code was met
- Respond with the paywalled API request or webpage
Let's get started!
Clone the Repository
Clone the qn-guide-examples repository (we'll use the same codebase as it's protocol-agnostic):
git clone git@github.com:quiknode-labs/qn-guide-examples.git
Install Dependencies
Then, navigate inside the project folder and install dependencies:
cd sample-apps/coinbase-x402
npm install
Configure Environment
cp .env.local .env
Next, open up the .env file and ensure you put in the wallet address receiving payments and other environment variables:
# Receiving wallet address (where payments will be sent)
WALLET_ADDRESS=INPUT_WALLET_ADDRESS_HERE
# Environment
NODE_ENV=development
# Server port (default: 4021)
PORT=4021
Save the file.
Now, let's get into the logic of the codebase.
Server Setup
We will be using Express to create a simple server that will handle the payment and the API request.
Open the api/index.js file and let's recap the logic of the file.
import express from "express";
import { paymentMiddleware } from "x402-express";
import dotenv from "dotenv";
import path from "path";
import { log } from "../utils/log.js";
import { videoAccessHandler } from "../handlers/videoAccessHandler.js";
dotenv.config();
// Create and configure the Express app
const app = express();
// Use Base Sepolia (testnet) for development
const network = "base-sepolia";
const facilitatorObj = { url: "https://x402.org/facilitator" };
// Serve static files from the public directory
app.use(express.static(path.join(process.cwd(), "public")));
app.use(express.json());
// x402 payment middleware configuration
app.use(
  paymentMiddleware(
    process.env.WALLET_ADDRESS, // your receiving wallet address
    {
      // Protected endpoint for authentication
      "GET /authenticate": {
        price: "$0.10", // Set your desired price
        network: network,
      },
    },
    facilitatorObj
  )
);
// Add request logging middleware
app.use((req, res, next) => {
  const start = Date.now();
  log(`${req.method} ${req.url}`);
  log(`Request Headers: ${JSON.stringify(req.headers)}`);
  
  res.on("finish", () => {
    const duration = Date.now() - start;
    log(`${req.method} ${req.url} - ${res.statusCode} (${duration}ms)`);
  });
  
  next();
});
// Authentication endpoint - just redirects to the authenticated content
app.get("/authenticate", (req, res) => {
  log("Payment successful, redirecting to video content");
  res.redirect("/video-content");
});
// Video content endpoint - serves the authenticated content
app.get("/video-content", videoAccessHandler);
// Serve the home page
app.get("/", (req, res) => {
  res.sendFile(path.join(process.cwd(), "public", "index.html"));
});
// Handle 404s
app.use((req, res) => {
  res.status(404).json({ error: "Route not found" });
});
// Export the app for Vercel serverless functions
export default app;
// Start the server for local development
const PORT = process.env.PORT || 4021;
app.listen(PORT, () => {
  log(`Server is running on http://localhost:${PORT}`);
});
The key components here are:
- Payment Middleware: The paymentMiddlewarefromx402-expresshandles the payment verification
- Network Configuration: Set to base-sepoliafor testnet development
- Protected Routes: The /authenticateendpoint is protected and requires payment
- Facilitator: Uses the x402 facilitator for payment processing
Client Setup
Now we'll set up the client (our frontend), which we'll need to build three pages in the public directory of our project:
- index.html: Homepage
- authenticate.html: Authenticate and payment
- video-content.html: Page serving the paywalled video content
Let's dig into each. First, let's check out the homepage file (index.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>x402 Video Paywall Demo</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>x402 Video Paywall Demo</h1>
        <p>Ready to access premium content with <a href="https://www.x402.org/" target="_blank">x402 payment</a> protocol.</p>
    </header>
    
    <div class="card">
        <h3>Premium Video Content</h3>
        <p>Access our premium video content for just $0.10 in USDC:</p>
        <a href="/authenticate" class="cta-button">Pay $0.10 to Access Video</a>
    </div>
</body>
</html>
The HTML above is the homepage of the app which users will be first shown.
Then, the payment page (i.e., authenticate.html):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>x402 Video Paywall Demo</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>x402 Video Paywall Demo</h1>
        <p>Processing your payment...</p>
    </header>
    
    <div class="card">
        <h3>Payment in Progress</h3>
        <div class="payment-processing">
            <div class="loader"></div>
            <p>Your payment is being processed. Please do not close this window.</p>
            <p>You will be automatically redirected to the video content once the payment is confirmed.</p>
        </div>
        <a href="/" class="cta-button secondary-button">Cancel Payment</a>
    </div>
</body>
</html>
We'll also need to build the paywall webpage which won't be shown unless the user successfully submits payment and retrieves a successful 402 status code response. This logic will be contained within the video-content.html file as shown below:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>x402 Video Paywall Demo</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <header>
        <h1>x402 Video Paywall Demo</h1>
    </header>
    
    <div class="card">
        <h3>Premium Video Content</h3>
        <div class="video-container">
            <iframe
                width="100%"
                height="450"
                src="https://www.youtube.com/embed/dQw4w9WgXcQ"
                title="YouTube video player"
                frameborder="0"
                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                allowfullscreen>
            </iframe>
        </div>
        <br />
        <p>You have successfully paid $0.10 in cryptocurrency to access this content.</p>
        <a href="/" class="cta-button">Return to Homepage</a>
    </div>
</body>
</html>
Helper Functions
We'll also need to create a helper function that processes the video page. This will be within the handlers/videoAccessHandler.js file:
import { log } from "../utils/log.js";
import path from "path";
export function videoAccessHandler(req, res) {
  const startTime = Date.now();
  
  try {
    log("Processing video access request");
    
    // Send the video content page
    res.sendFile(path.join(process.cwd(), "public", "video-content.html"));
    
    log(`Request completed in ${Date.now() - startTime}ms`);
  } catch (error) {
    log("Error serving video content:", "error", error);
    res.status(500).send({
      error: "Failed to serve video content",
      message: error.message,
    });
  }
}
Note that there is also a vercel.json file that is used for deployment that tells Vercel to route all requests (/(.*)) to your /api directory.
Testing the Paywall
With our backend and frontend setup, let's now try and test it. Start the server by running the command in your terminal window within the project's root folder:
npm run dev
The Express server runs on port 4021 and serves the app. You'll see a page like this:
Homepage View:
- Clean interface with payment button
- Clear pricing displayed ($0.10 USDC)
- Link to x402 protocol documentation
Payment Flow:
- Click the payment button and you'll be forwarded to an authentication page (e.g., localhost:4021/authenticate)
- You'll be prompted to connect your wallet
- Sign the transaction message
You'll be prompted to sign a message similar to signing a TransferWithAuthorization message (implemented in ERC-3009) which allows gasless transfers by delegating to a 3rd-party EOA or smart contract. The signer authorizes fund transfer from themselves to another party.
This signed message contains all the necessary details for the transfer:
- The sender address
- The recipient address
- The transfer amount
- Validity time window
- A unique nonce to prevent replay attacks
Once you sign the message in your wallet and the payment of $0.10 USDC is successful, you'll be redirected to the paywalled video page.
Success State:
- Video content is now accessible
- Confirmation message displayed
- Option to return to homepage
Integration with BlockEden.xyz Analytics
One advantage of using BlockEden.xyz is the built-in analytics and monitoring capabilities. You can track:
- Request patterns for your paywall
- Payment success rates
- Geographic distribution of users
- Performance metrics
To view these analytics:
- Log into your BlockEden.xyz dashboard
- Navigate to the Analytics section
- Select your Base Sepolia endpoint
- Review real-time and historical data
This data can help you optimize pricing, understand user behavior, and improve your paywall implementation.
More Use Cases
The x402 protocol combined with BlockEden.xyz infrastructure enables various monetization strategies:
- Content Monetization: Earn directly for individual articles, videos, or e-book chapters without subscription barriers
- API Monetization: Charge for blockchain data access, analytics endpoints, or specialized services
- Pay-As-You-Go Services: Pay exactly for what you use—whether API calls, cloud storage, or computing power—in precise increments
- Automated Service Payments: Let your software or smart devices handle small payments automatically for services they use
- Micro-transactions: Enable tiny payments for individual API calls or data queries
- AI Agent Services: Allow AI agents to autonomously pay for resources they need without human intervention
Next Steps
To build on top of what you've just learned, try the following:
- Deploy to a live server: Move beyond the local environment to host the demo on a real server accessible to others
- Customize payment amounts: Experiment with different price points or implement dynamic pricing based on content value
- Implement timed access: Create time-limited access where payments unlock content for specific durations
- Connect to Base Mainnet: Move from the Sepolia testnet to Base Mainnet for real-world implementation once you're ready. Update your BlockEden.xyz endpoint accordingly
- Add multiple payment tiers: Offer different pricing for different content types or access levels
- Integrate analytics: Use BlockEden.xyz analytics to track payment patterns and optimize your pricing strategy
- Support multiple chains: Leverage BlockEden.xyz's multi-chain support to accept payments on Ethereum, Polygon, and other networks
Monitoring and Debugging
When running your x402 implementation with BlockEden.xyz:
Server-Side Monitoring
Check your server logs for:
- Payment verification attempts
- Failed transactions
- Response times
- Error messages
BlockEden.xyz Dashboard
Monitor your endpoint usage:
- Request count and rate
- Error rates
- Response times
- Geographic distribution
Common Issues and Solutions
Issue: Payments not being verified
- Solution: Check that your facilitator URL is correct and accessible
- Solution: Verify your wallet address is properly configured in .env
- Solution: Ensure sufficient USDC balance in the payer's wallet
Issue: Slow transaction confirmation
- Solution: Check BlockEden.xyz dashboard for endpoint performance
- Solution: Consider implementing a loading state with better UX
- Solution: Verify network congestion on Base Sepolia
Issue: 402 responses not being handled correctly
- Solution: Verify the x402-expressmiddleware is properly configured
- Solution: Check browser console for client-side errors
- Solution: Ensure payment headers are being sent correctly
Final Thoughts
That's it! You just learned how to use x402 to implement internet-native payments in your web application with BlockEden.xyz as your blockchain infrastructure provider. By leveraging the HTTP 402 "Payment Required" status code and the blockchain, you've created a streamlined payment system that eliminates traditional payment processing friction.
BlockEden.xyz provides the reliable, fast RPC infrastructure you need to build production-ready applications with x402. The combination of x402's payment protocol and BlockEden.xyz's enterprise-grade infrastructure enables you to:
- Build scalable monetization systems
- Reduce infrastructure complexity
- Monitor and optimize performance
- Support global users with low latency
Additional Resources
- x402 Protocol Documentation
- BlockEden.xyz Documentation
- ERC-3009 Specification
- Base Network Documentation
- BlockEden.xyz Dashboard
Need Help?
If you have questions or need assistance:
- Visit the BlockEden.xyz Discord community
- Check out BlockEden.xyz documentation
- Follow @BlockEdenHQ on Twitter for updates
- Contact BlockEden.xyz support through the dashboard
We ❤️ Feedback!
Have feedback or suggestions for this guide? We'd love to hear from you! Reach out through our community channels or submit feedback through the BlockEden.xyz dashboard.
Built with BlockEden.xyz - Enterprise-grade blockchain infrastructure for developers