Facilitator Path
Lesson 3 of 3
15 min

Building Your Own Facilitator

Learning Objectives

  • Understand the facilitator interface
  • Learn the implementation steps
  • Recognize key security considerations
  • Know how to integrate custom facilitators

Facilitator Interface

A facilitator must implement three core methods:

1.acceptPayment() - Verify and accept payment requests
2.settlePayment() - Submit transaction on-chain
3.getPaymentStatus() - Check payment status
typescript
interface Facilitator {
  // Accept payment request from client
  acceptPayment(payment: SignedPayment): Promise<PaymentAcceptance>;

  // Settle payment on-chain
  settlePayment(paymentId: string): Promise<SettlementProof>;

  // Check payment status
  getPaymentStatus(paymentId: string): Promise<PaymentStatus>;
}

interface SignedPayment {
  from: string;      // Payer address
  to: string;        // Receiver address
  amount: string;    // Amount in USDC
  network: string;   // 'base'
  signature: string; // Signed by payer
}
typescript
class CustomFacilitator implements Facilitator {
  async acceptPayment(payment: SignedPayment): Promise<PaymentAcceptance> {
    // 1. Verify signature
    const isValid = await this.verifySignature(payment);
    if (!isValid) {
      return { accepted: false, reason: 'Invalid signature' };
    }

    // 2. Check payer has sufficient funds (optional)
    const balance = await this.getBalance(payment.from);
    if (balance < parseFloat(payment.amount)) {
      return { accepted: false, reason: 'Insufficient funds' };
    }

    // 3. Store payment request
    const paymentId = await this.storePayment(payment);

    return { accepted: true, paymentId };
  }

  async settlePayment(paymentId: string): Promise<SettlementProof> {
    // 1. Retrieve payment
    const payment = await this.getPayment(paymentId);

    // 2. Submit to blockchain
    const tx = await this.submitTransaction(payment);

    // 3. Wait for confirmation
    await this.waitForConfirmation(tx.hash);

    return {
      success: true,
      transaction: tx.hash,
      network: payment.network,
      payer: payment.from,
    };
  }
}

Key Considerations

When building a custom facilitator:

Security: Verify all signatures, never trust client input
Gas fees: Decide who pays (facilitator, payer, receiver?)
Retries: Handle failed transactions, network issues
Monitoring: Log all payments for debugging
Rate limiting: Prevent spam/abuse
Database: Store payment records for auditing
typescript
// Using your custom facilitator
import { CustomFacilitator } from './facilitator';
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import { paymentMiddleware } from '@x402/express';
import { x402ResourceServer } from '@x402/core/server';
import { registerExactEvmScheme as registerServerScheme } from '@x402/evm/exact/server';
import express from 'express';

const myFacilitator = new CustomFacilitator({
  rpcUrl: process.env.BASE_RPC_URL,
  privateKey: process.env.FACILITATOR_PRIVATE_KEY,
});

// Use in client
const evmSigner = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
registerExactEvmScheme(client, { signer: evmSigner });
const fetchWithPayment = wrapFetchWithPayment(fetch, client);

// Use in server
const server = new x402ResourceServer(myFacilitator);
registerServerScheme(server);
const app = express();

app.use(
  paymentMiddleware(
    {
      'GET /api/data': {
        accepts: [{
          scheme: 'exact',
          price: '$0.001',
          network: 'eip155:8453',
          payTo: '0xYourWallet',
        }],
        description: 'Data endpoint',
        mimeType: 'application/json',
      },
    },
    server
  )
);

Implement the verifySignature() method

Complete the signature verification logic

Requirements:

Verifies valid signatures

Returns true for correctly signed payments

Rejects invalid signatures

Returns false for incorrectly signed payments

Your Solution