Skip to main content

Getting Started with Flask

Start accepting x402 payments in your Flask server in 2 minutes.

Example Code

You can find the full code for this example on GitHub.

Step 1: Install Dependencies

Install the required packages for your Flask server:

pip install x402 flask python-dotenv

Step 2: Set Your Environment Variables

Create a .env file in your project root:

echo "ADDRESS=0x...\nNETWORK=sui" > .env

Your .env file should look like this:

ADDRESS=0x... # wallet public address you want to receive payments to
NETWORK=sui # recommended for fastest settlement
# Optional: Configure facilitator URL if using custom facilitator
# FACILITATOR_URL=https://x402.blockeden.xyz
Network Options

BlockEden.xyz supports multiple networks:

  • sui (recommended for fastest settlement)
  • ethereum
  • base
  • polygon
  • avalanche

Step 3: Create a New Flask App

Create an app.py file with the following code:

import os
from typing import Any, Dict

from dotenv import load_dotenv
from flask import Flask, jsonify
from x402.flask.middleware import PaymentMiddleware
from x402.types import TokenAmount, TokenAsset, EIP712Domain

# Load environment variables
load_dotenv()

# Get configuration from environment
ADDRESS = os.getenv("ADDRESS")
NETWORK = os.getenv("NETWORK", "sui")

if not ADDRESS:
raise ValueError("Missing required environment variables")

app = Flask(__name__)

# Initialize payment middleware
payment_middleware = PaymentMiddleware(app)

# Apply payment middleware to specific routes
payment_middleware.add(
path="/weather",
price="$0.001",
pay_to_address=ADDRESS,
network=NETWORK,
)

# Apply payment middleware to premium routes
payment_middleware.add(
path="/premium/*",
price=TokenAmount(
amount="10000",
asset=TokenAsset(
address="0x...", # USDC contract address for your network
decimals=6,
eip712=EIP712Domain(name="USDC", version="2"),
),
),
pay_to_address=ADDRESS,
network=NETWORK,
)


@app.route("/")
def index() -> Dict[str, str]:
"""Root endpoint"""
return jsonify({
"message": "x402 Payment Server",
"status": "running",
})


@app.route("/weather")
def get_weather() -> Dict[str, Any]:
"""Get weather data - requires payment"""
return jsonify({
"report": {
"weather": "sunny",
"temperature": 70,
"location": "San Francisco",
}
})


@app.route("/premium/content")
def get_premium_content() -> Dict[str, Any]:
"""Get premium content - requires payment"""
return jsonify({
"content": "This is premium content",
"type": "article",
"timestamp": "2025-01-01T00:00:00Z",
})


@app.route("/premium/analytics")
def get_premium_analytics() -> Dict[str, Any]:
"""Get premium analytics - requires payment"""
return jsonify({
"analytics": {
"users": 1000,
"revenue": 50000,
"growth": 25.5,
}
})


if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=4021,
debug=True,
)

Step 4: Run the Server

Start your Flask server:

python app.py

Or use Flask's built-in development server:

flask --app app run --port 4021
Your Flask server is now accepting x402 payments!

Your server will be available at http://localhost:4021.

Step 5: Test the Server

You can test payments against your server locally using HTTP clients like curl, Postman, or by building a Python client application.

Coming Soon

Client implementation guides for httpx and requests libraries will be available soon.

Manual Testing with curl

# This will return a 402 Payment Required response
curl http://localhost:4021/weather

# The response will include payment details in headers

Payment Configuration Options

The PaymentMiddleware.add() method accepts flexible payment configurations:

Simple Dollar Amount

# Initialize payment middleware
payment_middleware = PaymentMiddleware(app)

payment_middleware.add(
path="/weather",
price="$0.001",
pay_to_address=ADDRESS,
network="sui",
)

@app.route("/weather")
def get_weather():
return jsonify({"weather": "sunny"})

Token Amount with Specific Asset

from x402.types import TokenAmount, TokenAsset, EIP712Domain

payment_middleware.add(
path="/premium/data",
price=TokenAmount(
amount="10000",
asset=TokenAsset(
address="0x...", # Token contract address
decimals=6,
eip712=EIP712Domain(name="USDC", version="2"),
),
),
pay_to_address=ADDRESS,
network="sui",
)

@app.route("/premium/data")
def get_premium_data():
return jsonify({"data": "Premium content"})

Multiple Routes with Same Payment

You can protect multiple routes with wildcard paths:

# Protect all /premium routes with the same payment requirement
payment_middleware.add(
path="/premium/*",
price="$0.05",
pay_to_address=ADDRESS,
network="sui",
)

@app.route("/premium/content")
def premium_content():
return jsonify({"content": "Premium content"})

@app.route("/premium/analytics")
def premium_analytics():
return jsonify({"analytics": {...}})

Advanced Features

Custom Payment Verification Callback

Add custom logic when payments are verified:

# Note: Custom payment verification callbacks may vary based on
# the x402 library version. Check the official documentation for
# the exact callback mechanism supported by your version.

payment_middleware.add(
path="/weather",
price="$0.001",
pay_to_address=ADDRESS,
network="sui",
)

@app.route("/weather")
def get_weather():
# Payment has been verified if this handler is reached
# Add your custom logic here
return jsonify({"weather": "sunny"})

Error Handling

Add custom error handling for payment failures:

from flask import request
from x402.exceptions import X402PaymentError

@app.errorhandler(X402PaymentError)
def handle_payment_error(error):
return jsonify({
"error": "Payment required",
"details": str(error),
"path": request.path,
}), 402

@app.errorhandler(Exception)
def handle_general_error(error):
app.logger.error(f"Unexpected error: {error}")
return jsonify({
"error": "Internal server error",
}), 500

CORS Configuration

Enable CORS for cross-origin requests:

from flask_cors import CORS

# Enable CORS for all routes
CORS(app, resources={
r"/*": {
"origins": ["http://localhost:3000", "https://yourdomain.com"],
"allow_headers": ["Content-Type", "Authorization"],
"methods": ["GET", "POST", "OPTIONS"],
}
})

Install flask-cors:

pip install flask-cors

Request Context Access

Access payment information in your route handlers:

from flask import g

@app.route("/weather")
@require_payment(
price="$0.001",
pay_to_address=ADDRESS,
network="sui",
facilitator_config=facilitator_config,
)
def get_weather():
# Access payment details from Flask's g object
payment_info = getattr(g, "x402_payment", None)

return jsonify({
"report": {"weather": "sunny", "temperature": 70},
"payment": {
"tx_hash": payment_info.tx_hash if payment_info else None,
}
})

Logging Configuration

Set up proper logging for production:

import logging
from logging.handlers import RotatingFileHandler

if not app.debug:
# Create logs directory if it doesn't exist
if not os.path.exists('logs'):
os.mkdir('logs')

# Configure file handler
file_handler = RotatingFileHandler(
'logs/x402_server.log',
maxBytes=10240000,
backupCount=10
)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s '
'[in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)

app.logger.setLevel(logging.INFO)
app.logger.info('x402 payment server startup')

Production Deployment

Before deploying to production:

  1. Switch to production network (e.g., sui instead of sui-testnet)
  2. Use environment variables for all sensitive data
  3. Disable debug mode (debug=False)
  4. Use a production WSGI server (Gunicorn, uWSGI)
  5. Enable HTTPS (use a reverse proxy like nginx)
  6. Set up proper logging and monitoring
  7. Configure CORS for your production domains

Production Example

import os
import logging
from logging.handlers import RotatingFileHandler

from dotenv import load_dotenv
from flask import Flask, jsonify
from flask_cors import CORS
from x402.flask.middleware import PaymentMiddleware

load_dotenv()

app = Flask(__name__)
app.config['DEBUG'] = False

# CORS configuration
CORS(app, resources={
r"/*": {
"origins": os.getenv("ALLOWED_ORIGINS", "").split(","),
"allow_headers": ["Content-Type", "Authorization"],
"methods": ["GET", "POST", "OPTIONS"],
}
})

# Logging configuration
if not app.debug:
if not os.path.exists('logs'):
os.mkdir('logs')
file_handler = RotatingFileHandler(
'logs/x402_server.log',
maxBytes=10240000,
backupCount=10
)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)

# Initialize payment middleware
payment_middleware = PaymentMiddleware(app)

payment_middleware.add(
path="/api/data",
price="$0.01",
pay_to_address=os.getenv("ADDRESS"),
network="sui", # Production Sui network
)

@app.route("/api/data")
def get_data():
app.logger.info("Delivering protected data")
return jsonify({"data": "Protected content"})

if __name__ == "__main__":
app.run(
host="0.0.0.0",
port=int(os.getenv("PORT", "4021")),
debug=False,
)

Deploy with Gunicorn

For production, use Gunicorn:

pip install gunicorn

gunicorn app:app \
--workers 4 \
--bind 0.0.0.0:4021 \
--timeout 120 \
--access-logfile logs/access.log \
--error-logfile logs/error.log

Deploy with uWSGI

Alternatively, use uWSGI:

pip install uwsgi

uwsgi --http 0.0.0.0:4021 \
--wsgi-file app.py \
--callable app \
--processes 4 \
--threads 2

Troubleshooting

Common Issues

Payment verification fails

  • Verify your BLOCKEDEN_API_KEY is correct
  • Check that the wallet address format matches the network
  • Ensure the facilitator URL is accessible

CORS errors

  • Install and configure flask-cors
  • Ensure CORS middleware is configured before routes
  • Check allowed origins configuration

Network mismatch

  • Ensure client and server use the same network
  • Check that the token address is valid for the network

Module import errors

  • Ensure you installed x402 package
  • Verify your Python version is 3.8 or higher

Decorator order matters

  • @require_payment should be the closest decorator to the function
  • Example correct order:
    @app.route("/weather")
    @require_payment(...)
    def get_weather():
    ...

Port already in use

  • Change the port in app.run() configuration
  • Kill any existing processes: lsof -ti:4021 | xargs kill

Why Choose Flask?

Flask is an excellent choice for x402 payment servers:

  • Lightweight: Minimal and unopinionated framework
  • Flexible: Easy to extend with plugins
  • Easy to learn: Simple, intuitive API
  • Large community: Extensive documentation and third-party extensions
  • Production-ready: Battle-tested in thousands of applications

Flask vs FastAPI

FeatureFlaskFastAPI
PerformanceGoodExcellent
Async SupportVia extensionsBuilt-in
Type SafetyOptionalBuilt-in
Auto DocsVia extensionsBuilt-in
Learning CurveEasyModerate
MaturityVery matureModern

Choose Flask if you:

  • Want a simple, familiar framework
  • Don't need async features
  • Prefer flexibility over structure
  • Are building a traditional web app

Choose FastAPI if you:

  • Need high performance
  • Want built-in async support
  • Prefer type safety
  • Want automatic API documentation

Next Steps

Need Help?

Join Our Community

Have questions or want to connect with other developers?

Join Discord