BotPay 商户接入
外部商户的 Bot 可以自己注册、拿到 API key,然后在 Base Sepolia 上用 USDC 报价和付款。默认演示金额是 1 USDC。没有主网。
线上地址:https://botpay.polyos.ai
机器可读说明:
GET /v1/onboardingGET /.well-known/botpay.jsonGET /onboarding.md
先记住这几条
- API key 和 webhook secret 只在注册或轮换时出现一次。立刻放进密钥管理器,不要写进仓库、日志或对话。
- 服务端只存 API key 的 SHA-256。丢了就轮换,没有找回接口。
- 收款地址由收款商户自己设置。付款请求里不要传
pay_to或to_address。 - 会动钱的 POST 必须带
Idempotency-Key(用 UUID)。相同 key 和相同请求体会重放;请求体不同会返回IDEMPOTENCY_KEY_CONFLICT。 - 单笔超过 50 USDC 要管理员审批,超过 100 USDC 直接拒绝。
- 付款从平台共享的测试网钱包转出。自助注册的商户默认每天最多花 5 USDC(UTC 日切),全体自助商户每天合计默认 50 USDC。演示商户
mer_a/mer_b不走这本账。管理员可以把单个商户的上限调到 0–100 USDC/日。 - 注册接口不强制 Turnstile,方便 Bot 直接调用,但按 IP 和全局限流。配了 Turnstile 时,带上无效 token 会被拒绝;不带 token 仍然可以注册。
1. 注册
付款方和收款方各注册一次。scope_preset 省略时是 full,同一把 key 既能付也能收。只要付款用 payer,只要收款用 payee。
curl -sS https://botpay.polyos.ai/v1/merchants \
-H 'content-type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Acme Bot","scope_preset":"full"}'
响应里把下面三个值存成 secret,不要打印到对话里:
data.api_key(形如bp_live_...)data.webhook_secret(形如whsec_...)data.merchant_id
15 分钟内用同一个 Idempotency-Key 重试,会拿回同一次注册结果(含密钥)。这个重放缓存在 KV,过期后数据库里只剩哈希。
2. 接上 MCP
服务是无状态的 Streamable HTTP,只接受 POST /mcp。用 Bearer token。register_merchant 不需要 token,其余工具需要。
只支持 stdio 的客户端可以用 mcp-remote:
{
"mcpServers": {
"botpay": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://botpay.polyos.ai/mcp",
"--header",
"Authorization: Bearer ${BOTPAY_API_KEY}"
],
"env": {
"BOTPAY_API_KEY": "把密钥放在环境变量里,不要写进这个文件"
}
}
}
}
Cursor 也可以直接配远程 MCP:
{
"mcpServers": {
"botpay": {
"url": "https://botpay.polyos.ai/mcp",
"headers": {
"Authorization": "Bearer ${BOTPAY_API_KEY}"
}
}
}
}
协议版本 2025-03-26 或 2025-06-18。先 initialize,再 notifications/initialized,然后 tools/list / tools/call。服务器不提供 GET SSE 会话。
还没有 key 时,可以不带 Authorization 调用工具 register_merchant(参数 name、idempotency_key)。拿到 key 之后重新连接。
3. 收款方设置地址
地址必须是 EIP-55 校验和形式。全零、0x1111… 这类占位地址、以及平台出款钱包会被拒绝。
下面只是格式示例,请换成你自己的 Base Sepolia 地址:
curl -sS -X PUT https://botpay.polyos.ai/v1/merchants/me/wallet \
-H "authorization: Bearer $BOTPAY_API_KEY" \
-H 'content-type: application/json' \
-d '{"address":"0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"}'
MCP 工具:set_payee_wallet。
4. 跑一笔 1 USDC
假设收款方商户 id 是 $PAYEE,付款方是 $PAYER,两边都用自己的 key。
收款方报价:
curl -sS https://botpay.polyos.ai/v1/quotes \
-H "authorization: Bearer $PAYEE_KEY" \
-H 'content-type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"payer_merchant_id\":\"$PAYER\",\"service_ref\":\"demo.1usdc\",\"amount\":{\"value\":\"1.00\",\"currency\":\"USDC\"},\"network\":\"eip155:84532\"}"
付款方接受并执行(不要加 pay_to):
curl -sS https://botpay.polyos.ai/v1/payment-intents \
-H "authorization: Bearer $PAYER_KEY" \
-H 'content-type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"quote_id\":\"$QUOTE_ID\"}"
curl -sS -X POST "https://botpay.polyos.ai/v1/payment-intents/$PAYMENT_ID/execute" \
-H "authorization: Bearer $PAYER_KEY" \
-H 'content-type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{}'
然后 GET /v1/payment-intents/$PAYMENT_ID,等到 SETTLED。MCP 上对应的工具是 create_quote、create_payment_intent、execute_payment、get_payment。create_quote 的金额字段是 amount_value,演示填 "1.00"。
没有白名单记录的付款商户可以向任意有效收款商户付款。预置的 mer_a 仍然只能付给白名单里的 mer_b。
5. Webhook 和密钥
curl -sS https://botpay.polyos.ai/v1/webhooks/subscriptions \
-H "authorization: Bearer $PAYEE_KEY" \
-H 'content-type: application/json' \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"url":"https://example.com/botpay","event_types":["payment.settled"]}'
验签用注册时拿到的 webhook_secret。头是 X-Webhook-Timestamp 和 X-Webhook-Signature(v1= + HMAC-SHA256,消息是 {timestamp}.{body})。
轮换 API key:POST /v1/api-keys/{id}/rotate(需要 Idempotency-Key)。旧 key 立即失效,新 key 只出现一次。POST /v1/api-keys/{id}/revoke 可以吊销其中一把,但不能吊销最后一把。GET /v1/api-keys 只返回前缀。
轮换 webhook secret:POST /v1/webhooks/secret/rotate。
看自己是谁:GET /v1/merchants/me。这里有今日剩余额度,没有密钥。
排障
| 现象 | 原因 |
|---|---|
401 | key 不存在。已吊销的 key 是 403。演示 key 在 ALLOW_DEMO_KEYS=false 时也是 401。bp_live_ 不受演示开关影响 |
403 缺少权限 | scope 不够。payer 不能报价,payee 不能执行付款,read 不能轮换 key |
400 不允许由客户端指定收款地址 | 请求里带了 pay_to 或 to_address |
400 收款地址必须是 EIP-55 | 用了全小写,或校验和错了 |
422 PAYEE_WALLET_MISSING | 收款方还没设置地址 |
422 SPEND_ALLOWANCE_EXCEEDED | 超过该商户或全平台的当日额度。换新的 Idempotency-Key,或等 UTC 日切,或请管理员调整 |
409 APPROVAL_REQUIRED | 金额大于 50 USDC,要管理员批准后才能 execute |
422 AMOUNT_OVER_LIMIT | 单笔超过 100 USDC |
429 RATE_LIMITED | 这个 IP 每小时注册太多。默认 5 次,全平台默认 120 次 |
409 不能吊销最后一把密钥 | 改用 rotate |