BotPay Facilitator(撮合器)

欢迎使用 BotPay Facilitator!该 Cloudflare Worker 提供一个安全的 API,用于在以太坊上通过 x402 协议撮合与处理支付。开始使用前,请先通过我们的账户管理门户获取 API key 与 secret。

API Key 管理

通过 Portal UI 管理 API key 与配额 —— 在 /register 注册你的 Botpay facilitator 账户,并访问 /login 登录页面进入 API key 管理控制台。

Portal 支持通过 x402 支付来增加配额或获取新的 API key。用户可以通过支付为 API key 充值补充配额。

Facilitator API(接口)

POST /verify

验证一笔支付交易。Facilitator 通过 x402 Node 包的实现,接受使用标准 x402 结构(PaymentPayloadPaymentRequirements)的请求 —— 详见 x402 包文档。

响应(Verify):

{
  "isValid": true,
  "invalidReason": null,
  "payer": "0xPayerAddress"
}

POST /settle

使用 x402 的 payment payload 与 requirements 对已验证的支付进行结算。

请求体:

{
  "paymentPayload": { ... },
  "paymentRequirements": { ... }
}

(使用与 /verify 请求相同的结构 —— 参考上面的 EVM/SVM 示例。)

响应(Settle):

{
  "success": true,
  "transaction": "0xTransactionHash",
  "network": "base",
  "payer": "0xPayerAddress"
}

备注:

  • 失败时 success 将为 false,并且 errorReason 可能提示原因(例如 insufficient_fundsinvalid_payment 等)。
  • verify 与 settle 两个操作每次调用都会消耗 1 点 API 配额。

认证(Authentication)

所有 facilitator API 请求都需要使用 HMAC 签名进行认证。你需要:

  1. API Key ID(通过 X-API-Key 请求头传递)
  2. 对应的 secret key(用于签名,绝不会在请求中发送)

HMAC 签名(HMAC Signing)

请求使用 HMAC-SHA256 签名。Facilitator 采用“仅签名 Header”的方案,并使用时间戳来防止重放与篡改。

必需请求头:

  • X-API-Key: 你的 API key ID
  • X-Timestamp: Unix epoch 秒(整数)
  • X-Signature: Hex 编码的 HMAC-SHA256 签名

待签名字符串:

{timestamp}\n{method}\n{path}

其中:

  • timestampX-Timestamp 的值(秒)
  • method 为大写 HTTP 方法(例如 POST
  • path 为请求路径与 query(例如 /facilitator/verify/facilitator/verify?foo=1

HMAC key: 服务端将 hashed_secret 存为 hex(SHA-256(secret))。要计算签名,你应:

  1. 计算 key = SHA256(secret),并使用 key 的原始字节作为 HMAC key
  2. 计算 signature = hex(HMAC-SHA256(key, stringToSign))

时间窗口(Timestamp window): 服务端允许的时间偏移窗口由 SIGNATURE_WINDOW_SECONDS 控制(默认 300 秒)。

示例(Node.js):

const crypto = require('crypto');

function buildSignedHeaders(apiKeyId, secret, method, path = '') {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const stringToSign = `${timestamp}\n${method.toUpperCase()}\n${path}`;
  const key = crypto.createHash('sha256').update(secret).digest(); // raw bytes
  const signature = crypto.createHmac('sha256', key).update(stringToSign).digest('hex');

  const headers = {
    'Content-Type': 'application/json',
    'X-API-Key': apiKeyId,
    'X-Timestamp': timestamp,
    'X-Signature': signature,
  };
  return headers;
}

// Usage example
const headers = buildSignedHeaders('your-api-key-id', 'your-secret', 'POST', '/facilitator/verify');
const body = JSON.stringify({ paymentPayload: {...}, paymentRequirements: {...} });
fetch('https://your-facilitator.com/facilitator/verify', { method: 'POST', headers, body });

客户端示例(Client Examples)

JavaScript 客户端

// Node client: create an x402 payment (using `x402`), sign it with your EVM signer, then POST to the facilitator
const crypto = require('crypto');
const { createAndSignPayment } = require('x402'); // builds canonical paymentPayloads

// Example helper to build HMAC headers matching the facilitator
function buildSignedHeaders(apiKeyId, secret, method, path = '') {
  const timestamp = Math.floor(Date.now() / 1000).toString();
  const stringToSign = `${timestamp}\n${method.toUpperCase()}\n${path}`;
  const key = crypto.createHash('sha256').update(secret).digest(); // raw bytes
  const signature = crypto.createHmac('sha256', key).update(stringToSign).digest('hex');

  const headers = {
    'Content-Type': 'application/json',
    'X-API-Key': apiKeyId,
    'X-Timestamp': timestamp,
    'X-Signature': signature,
  };
  return headers;
}

// Usage example (pseudo-code — replace signer with your viem wallet client or other signer)
async function verifyPayment(apiKeyId, secret, signer, paymentRequirements) {
  // Build and sign a canonical x402 paymentPayload using your signer
  const paymentPayload = await createAndSignPayment(signer, {
    x402Version: 1,
    scheme: 'exact',
    network: paymentRequirements.network,
    payload: {
      // For exact EVM payments, create authorization; createAndSignPayment will sign it
      authorization: {
        from: '0xSenderAddress',
        to: paymentRequirements.payTo,
        value: paymentRequirements.maxAmountRequired,
        validAfter: '0',
        validBefore: `${Math.floor(Date.now() / 1000) + 3600}`,
        nonce: '0x...'
      }
    }
  }, paymentRequirements);

  const body = JSON.stringify({ paymentPayload, paymentRequirements });
  const headers = buildSignedHeaders(apiKeyId, secret, 'POST', '/facilitator/verify', body);

  const res = await fetch('https://botpay-facilitator.alexwlex143.workers.dev/facilitator/verify', { method: 'POST', headers, body });
  return res.json();
}

配额管理(Quota Management)

  • 每个 API key 都有配额上限
  • verify 与 settle 操作每次各消耗 1 点配额
  • 通过 /api-keys 端点查看剩余配额
  • 通过 /add-quota 端点增加配额

错误处理(Error Handling)

API 返回标准 HTTP 状态码:

  • 200: 成功
  • 400: 请求错误(Bad Request)
  • 401: 未授权(签名无效)
  • 403: 禁止(配额超限)
  • 500: 服务端内部错误(Internal Server Error)

错误响应会返回 JSON,包含 success: false 与错误信息。

安全最佳实践(Security Best Practices)

  1. 永远不要分享你的 secret key
  2. 所有请求都使用 HTTPS
  3. 如有需要,可在你侧校验签名
  4. 监控配额使用情况
  5. 定期轮换 API key

参考(References)