使用 FastAPI 集成 x402 支付协议的完整示例,包含:
- 支付验证与结算中间件(Verify / Settle)
- 业务路由(
/mint、/mint1、/mint10、/premium/mint) - 自定义付费页(Paywall 页面中文与品牌化)
- 结算结果持久化到 MySQL、交易哈希发布到 Redis
- 调试与观测接口(
/debug-mint)
适合用作自有 API 与 x402 Facilitator 对接的最小可运行示例,也可作为生产环境集成参考。
- 框架:
FastAPI - 支付协议:
x402(验证与结算均由 Facilitator 提供) - 语言与运行:Python
>=3.10(开发使用 3.11) - 依赖:
cdp-sdk、aiomysql、redis.asyncio、python-dotenv、uvicorn - 端口:
3001(本地运行)
核心路径:
- 请求头:客户端需在请求中携带
X-PAYMENT(Base64(JSON)) - 验证:
middleware/x402_verify_guard.py → facilitator.verify - 路由:
main.py → /mint* 与 /premium/mint - 结算:
middleware/x402_verify_guard.py → facilitator.settle - 数据:
db/mysql_async.py(写入x402_data表)与db/redis_async.py(发布 tx_hash) - 调试:
/debug-mint返回最近结算、错误与环境配置快照
mainnet/
├── main.py # FastAPI 入口与路由注册
├── config/
│ ├── settings.py # 统一集中配置(环境读取/路由/付费页)
│ ├── config.py # 兼容旧接口的适配层
│ ├── config_routes.py # 路由集合与价格策略(MINT、PREMIUM 前缀)
│ └── config_paywall.py # 付费页配置生成与索引
├── middleware/
│ ├── x402_verify_guard.py # 验证与结算中间件(核心)
│ └── payment_capture.py # 捕获响应头与错误快照(外层中间件)
├── db/
│ ├── mysql_async.py # 异步 MySQL 连接池与插入接口
│ └── redis_async.py # 异步 Redis 客户端与发布接口
├── templates/
│ ├── paywall_custom.py # 中文与品牌化的付费页模板
│ └── branding.py # 品牌与文案配置(中文)
├── scripts/
│ ├── redis_subscriber.py # 示例订阅器(打印接收的 tx_hash)
│ └── redis_publish_test.py # 示例发布器(向频道发布模拟 tx_hash)
├── request_flow.svg # 简化版请求流程图
├── request_flow_tx_hash_highlight.svg # 详细流程图(带 tx_hash 流)
├── pyproject.toml # 项目依赖与构建配置
├── .env / .env-local # 环境变量文件(示例/本地覆盖)
└── uv.lock # 开发工具锁文件
集中由 config/settings.py 管理。所有配置可通过 .env 或系统环境变量注入。
必需:
NETWORK:x402 支付网络(如base或base-sepolia)ADDRESS:收款地址(pay_to)CDP_API_KEY_ID、CDP_API_KEY_SECRET:CDP SDK Key(用于构建 Facilitator 配置)
可选:
FACILITATOR_URL:显式指定 Facilitator 服务地址(不设则通过cdp.x402.create_facilitator_config自动生成)ENV:运行环境字符串(prod/production视为生产环境)DEBUG_ERRORS:在非生产环境启用更详尽错误返回(1/true)MYSQL_HOST、MYSQL_PORT(默认3306)、MYSQL_USER、MYSQL_PASSWORD、MYSQL_DATABASEREDIS_URL:Redis 连接串(默认redis://localhost:6379/7)X402_TX_HASH_CHANNEL:发布交易哈希的频道(默认error_x402_txh_hash)- 代理:
HTTP_PROXY、HTTPS_PROXY、NO_PROXY(仅用于调试输出,不影响功能)
付费与路由:
config_routes.py定义MINT_ROUTES(/mint、/mint1、/mint10)与ROUTE_POLICY(价格/币种/模板)config_paywall.py根据路由策略自动生成PAYWALL_ROUTES,包括PREMIUM_PREFIX=/premium/前缀匹配(match: prefix)- 自定义付费页通过
templates/paywall_custom.py注入中文与品牌样式,get_paywall_config提供前端所需cdp_client_key等信息
示例 .env:
ENV=local
NETWORK=base
ADDRESS=0xYourPayToAddress
CDP_API_KEY_ID=your_public_key_id
CDP_API_KEY_SECRET=your_secret_key
# FACILITATOR_URL=https://facilitator.example.com
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=passwd
MYSQL_DATABASE=yourdata
REDIS_URL=redis://localhost:6379/7
X402_TX_HASH_CHANNEL=x402_tx_hash
DEBUG_ERRORS=1
- 安装依赖(使用
uv):uv sync(根据pyproject.toml安装依赖并创建本地.venv,生成/更新uv.lock)- 如需新增依赖:
uv add <package>(同时更新pyproject.toml与uv.lock)
- 运行(使用
uv):uv run uvicorn main:app --reload --port 3001(推荐,热重载开发)- 或
uv run python main.py(使用内置uvicorn.run,默认127.0.0.1:3001)
- CORS:已放开全部来源与头,且暴露
x-payment-response响应头 - 代理头:
proxy_headers=True、forwarded_allow_ips="*"(生产建议限制来源)
GET/POST /mint、/mint1、/mint10- 需携带
X-PAYMENT请求头(Base64(JSON)) - 验证通过后进入业务逻辑,业务返回
2xx将触发结算与哈希获取
- 需携带
GET/POST /premium/mint- 受
PREMIUM_PREFIX前缀策略保护,价格与模板可在ROUTE_POLICY中调整
- 受
GET/POST /debug-mint- 返回统一调试快照:请求、环境、配置与
status(最近支付/错误/结算原始返回)
- 返回统一调试快照:请求、环境、配置与
路由与价格来源:
config_routes.py → ROUTE_POLICY:/mint→$0.1、USD/mint1→$1、USD/mint10→$10、USD(使用自定义付费页模板)PREMIUM_PREFIX=/premium/→$0.01、USD(前缀匹配)
- 客户端需构造
X-PAYMENT请求头,内容为支付凭证 JSON 的 Base64 字符串 - 形如:
X-PAYMENT: Base64(
{
"payload": {
"authorization": { "value": "<atomic-amount>", ... },
"signature": "<eip712-signature>"
},
...
}
)
- 后端在
x402_verify_guard.py中解析:safe_base64_decode → json.loads → PaymentPayload(**dict)- 根据路由价格生成
PaymentRequirements并调用facilitator.verify
middleware/payment_capture.py- 外层中间件;在响应阶段解析
x-payment-response头(Base64(JSON)) - 更新最近一次支付信息
_LAST_PAYMENT_INFO;失败时记录_LAST_PAYMENT_ERROR - 保留签名与原始支付载荷,便于调试“旧签名/截止时间”类问题
- 外层中间件;在响应阶段解析
middleware/x402_verify_guard.py- 内层中间件;对匹配路径执行支付验证与结算
- 验证:
facilitator.verify,失败返回402(浏览器则返回 HTML 付费页) - 业务:
call_next,仅当业务返回2xx才进行结算 - 结算:
facilitator.settle,读取transaction作为tx_hash - 持久化:写入 MySQL(
x402_data表),并发布到 Redis 频道 - 观测:最近一次结算原始返回
_LAST_SETTLE_RAW存档(便于/debug-mint查看)
db/mysql_async.py- 基于
aiomysql的连接池;提供insert_x402_data(record)写入接口
- 基于
db/redis_async.py- 基于
redis.asyncio的发布接口;初始化失败时安全降级并记录日志
- 基于
templates/paywall_custom.py- 注入中文文案与品牌样式,监听异步渲染替换默认英文模板内容
scripts/redis_subscriber.py/scripts/redis_publish_test.py- 订阅/发布示例脚本,辅助验证 Redis 推送
流程图:
摘要:
- 客户端发起请求(携带
X-PAYMENT) - Verify Guard 调用
facilitator.verify验证凭证 - 验证通过进入路由处理;业务返回
2xx才结算 - 调用
facilitator.settle获取tx_hash - 将 Base64(JSON) 的结算结果写入响应头
x-payment-response - 写入 MySQL
x402_data(含txh_hash、from_address、amount等) - 发布
tx_hash到 Redis 频道 - 客户端可解码响应头获取
tx_hash等信息
- 表名:
x402_data - 插入字段(与代码一致):
from_address、amount(BIGINT)、to_address、signature、sign_json(JSON)status、token_status、txh_hash、mint、start_time、end_time(均INT/VARCHAR视情况)
示例建表 SQL(可按需调整类型与索引):
CREATE TABLE IF NOT EXISTS `x402_data` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`from_address` VARCHAR(64),
`amount` BIGINT,
`to_address` VARCHAR(64),
`signature` VARCHAR(512),
`sign_json` JSON,
`status` INT,
`token_status` INT,
`txh_hash` VARCHAR(80),
`mint` VARCHAR(32),
`start_time` INT,
`end_time` INT,
PRIMARY KEY (`id`),
KEY `idx_txh_hash` (`txh_hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
- 频道名:
X402_TX_HASH_CHANNEL(默认error_x402_txh_hash) - 发布内容:
tx_hash文本 - 订阅示例:
python scripts/redis_subscriber.py(会打印收到的哈希)
- 发布示例:
python scripts/redis_publish_test.py 0xdeadbeef...(不传参则生成随机哈希)
- 验证异常:返回
402 Payment Required(浏览器请求返回 HTML 付费页) - 网络或上游故障:捕获异常并返回
500(在DEBUG_ERRORS=1时包含type/correlationId等细节) - 业务非
2xx:跳过结算,直接返回原响应 - 结算失败:记录错误并返回原响应(或按需返回 402),同时保留最近失败信息供调试
- MySQL/Redis:写入/发布失败仅记录日志,不阻塞主流程
GET/POST /debug-mint返回统一调试快照:method/path/query/url/headers/client/json/body_text/body_lengthenv:HTTP_PROXY、HTTPS_PROXY、NO_PROXY、ENV、DEBUG_ERRORSconfig:network、facilitator_urlstatus:last_payment、last_error、last_settle_raw
- 最近一次支付/错误由外层中间件在响应阶段记录;结算原始返回由内层中间件保存
- 前端或客户端用官方 x402 SDK 生成
X-PAYMENT请求头 - 逐步验证:
- 未携带头 → 应返回 402(浏览器看到付费页)
- 携带无效签名/过期凭证 → 返回 402(错误描述)
- 携带有效凭证 →
/mint*返回 2xx,响应头含x-payment-response
- 查数与观测:
- MySQL 表是否有新增记录
- Redis 频道是否收到
tx_hash /debug-mint中status.last_payment.tx_hash与status.last_settle_raw.transaction
- CORS 与代理头在示例中处于较为开放的配置,生产环境请按需收紧(白名单域名、
forwarded_allow_ips) - 付费页模板为前端 HTML 注入,请确保自定义脚本来源可信并避免 XSS
- 建议为
x402_data添加必要的唯一键或业务索引,避免重复写入 - 结合 API 网关/反向代理统一接入层的限流与鉴权策略
- 路由与价格只需修改
config/config_routes.py → ROUTE_POLICY与ROUTE_PATHS - 付费页样式与文案修改
templates/branding.py与templates/paywall_custom.py - 环境与集中配置通过
config/settings.py一处维护,config/config.py保留兼容接口