BotPayBotPay Facilitator

BotPay Facilitator

Welcome to the BotPay Facilitator! This Cloudflare Worker is a self-hosted x402 facilitator that verifies and settles Base mainnet USDC payments directly on-chain. It does not use a third-party facilitator in the verification or settlement path.

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

GET /supported

Returns the supported x402 schemes and the public facilitator signer address. Both GET /supported and the legacy GET /facilitator/supported are available.

POST /verify

Verify a payment transaction. The facilitator accepts requests using the canonical x402 v2 shapes (PaymentPayload and PaymentRequirements) via the current @x402/core SDK.

For backward compatibility, POST /facilitator/verify is also available. The standard /verify path is recommended for new integrations.

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.)

For backward compatibility, POST /facilitator/settle is also available. The standard /settle path is recommended for new integrations.

Response (Settle):

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

Notes:

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:

String to sign:

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

Where:

The existing BotPay client also sends a historical variant with one trailing newline. It remains accepted temporarily so deployed callers continue to work; new clients should use the three-line form above.

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://facilitator.botpay.network/verify', { method: 'POST', headers, body });

Client Examples

JavaScript Client

// Node client: create an x402 v2 payment, sign it with your EVM signer, then POST to the facilitator
const crypto = require('crypto');
// Use the current @x402/core and @x402/evm client packages to build 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 v2 paymentPayload with the @x402 client SDK.
  const paymentPayload = await createPaymentPayloadWithX402V2(signer, paymentRequirements);

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

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

Quota Management

Error Handling

The API returns standard HTTP status codes:

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

Security Best Practices

  1. Never share your API secret or internal facilitator token
  2. Use HTTPS for all requests
  3. Only Base mainnet USDC payments to approved BotPay recipients are accepted
  4. Monitor your quota usage and Base gas balance
  5. Rotate API keys regularly

References