Getting Started with Flask
Start accepting x402 payments in your Flask server in 2 minutes.
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
BlockEden.xyz supports multiple networks:
sui(recommended for fastest settlement)ethereumbasepolygonavalanche
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 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.
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:
- Switch to production network (e.g.,
suiinstead ofsui-testnet) - Use environment variables for all sensitive data
- Disable debug mode (
debug=False) - Use a production WSGI server (Gunicorn, uWSGI)
- Enable HTTPS (use a reverse proxy like nginx)
- Set up proper logging and monitoring
- 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_KEYis 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
x402package - Verify your Python version is 3.8 or higher
Decorator order matters
@require_paymentshould 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
| Feature | Flask | FastAPI |
|---|---|---|
| Performance | Good | Excellent |
| Async Support | Via extensions | Built-in |
| Type Safety | Optional | Built-in |
| Auto Docs | Via extensions | Built-in |
| Learning Curve | Easy | Moderate |
| Maturity | Very mature | Modern |
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?