BotPay Facilitator

Welcome to the BotPay Facilitator! This Cloudflare Worker provides a secure API for facilitating payments through the x402 protocol on Ethereum. To start, get API key and secret through our account management portal.

API Key Management

Manage API keys and quotas via the Portal UI — register your Botpay facilitator account at /register and visit the Login page at /login to access the API key management dashboard.

The Portal supports adding quota or get new API keys via x402 payments. Users can replenish API key quota by making payments.

Facilitator API

POST /verify

Verify a payment transaction. The facilitator accepts requests using the canonical x402 shapes (PaymentPayload and PaymentRequirements) via the x402 Node package implementation — see the x402 package documentation.

Response (Verify):

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

POST /settle

Settle a verified payment using the x402 payment payload and requirements.

Request Body:

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

(Use the same shapes as the /verify request — see the EVM/SVM examples above.)

Response (Settle):

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

Notes:

  • On failure success will be false and errorReason may indicate the cause (e.g., insufficient_funds, invalid_payment, etc.).
  • Both verify and settle operations decrement your API quota by 1.

Authentication

All facilitator API requests require authentication using HMAC signing. You'll need:

  1. An API Key ID (provided in X-API-Key header)
  2. The corresponding secret key (used for signing, never sent in requests)

HMAC Signing

Requests are signed using HMAC-SHA256. The facilitator implements a header-only signing scheme that uses a timestamp to protect against replay and tampering.

Required headers:

  • X-API-Key: Your API key ID
  • X-Timestamp: Unix epoch seconds (integer)
  • X-Signature: Hex-encoded HMAC-SHA256 signature

String to sign:

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

Where:

  • timestamp is the value of X-Timestamp (seconds)
  • method is the HTTP method in UPPERCASE (e.g., POST)
  • path is the request path and query (e.g., /facilitator/verify or /facilitator/verify?foo=1)

HMAC key: The server stores hashed_secret as hex(SHA-256(secret)). To compute the signature you should:

  1. Compute key = SHA256(secret) and use the raw bytes of key as the HMAC key
  2. Compute signature = hex(HMAC-SHA256(key, stringToSign))

Timestamp window: The server allows a +/- window controlled by SIGNATURE_WINDOW_SECONDS (default 300 seconds).

Example (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 Client

// 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

  • Each API key has a quota limit
  • Verify and settle operations consume 1 quota each
  • Monitor your remaining quota via the /api-keys endpoint
  • Add more quota using the /add-quota endpoint

Error Handling

The API returns standard HTTP status codes:

  • 200: Success
  • 400: Bad Request
  • 401: Unauthorized (invalid signature)
  • 403: Forbidden (quota exceeded)
  • 500: Internal Server Error

Error responses include a JSON body with success: false and an error message.

Security Best Practices

  1. Never share your secret key
  2. Use HTTPS for all requests
  3. Validate signatures on your end if needed
  4. Monitor your quota usage
  5. Rotate API keys regularly

References