Live on BNB Testnet

Build with the Facora

Add gasless, per-request payments to any API endpoint on BNB in minutes.

Caller Gas
0 (no BNB)
Settlement
USDx on-chain
Unlock
200 OK
0Context

Why this matters

Today, most x402-style payment flows depend on a single facilitator. If that server rate-limits you, censors you, or goes offline, your monetization stops.

We're removing that choke point on BNB.

The Fac exposes multiple independent facilitators. Alpha is live now. Beta and Gamma are coming online next. Facilitators will compete on fees, stake FAC to register, and can be slashed if they cheat.

Your endpoint can start charging per request — with no Stripe, no API keys, and no gas needed from the caller.

1Protect an endpoint with HTTP 402

Step 1. Protect an endpoint with HTTP 402

Your API doesn't return data for free. If the request isn't paid, you respond with 402 Payment Required and include:

  • • the price (in USDx),
  • • the settlement asset,
  • • and a list of available facilitators the client can use to pay.
/api/alpha-feed402 flow
// /api/alpha-feed
import { NextResponse } from "next/server";

export async function GET(req: Request) {
  const paidProof = req.headers.get("x-paid-proof");

  // Not paid yet → return a 402 invoice
  if (!paidProof) {
    return NextResponse.json({
      price: "1 USDx",
      asset: process.env.NEXT_PUBLIC_USDX_TOKEN_ADDRESS,
      facilitators: [
        {
          name: "Alpha",
          endpoint: "/api/facilitators/alpha",
          fee: "0.5%",
          address: "0x1437fE0f155b910dda7A80c64b57C1460793641F"
        },
        {
          name: "Beta",
          endpoint: "/api/facilitators/beta",
          fee: "1.0%",
          address: "0xBETA...TODO"
        }
      ]
    }, { status: 402 });
  }

  // Paid → return the protected data
  return NextResponse.json({
    alpha: "your private model output / feed / data product here"
  }, { status: 200 });
}

How to read this:

402 is the invoice. You're telling the client: "This endpoint costs 1 USDx. Here are facilitators who can settle it for you."

The client picks a facilitator (Alpha, Beta, …), gets it to pay, then retries with proof.

x-paid-proof is the receipt from the facilitator: settlement tx hash, block number, etc. That's what you check to decide if they're allowed in.

This is how you meter your API per request.

2Pay and unlock from the client

Step 2. Pay and unlock from the client

The client (or AI agent) calls your endpoint. If it gets 402, it will:

  1. 1. Read the invoice (price + facilitators).
  2. 2. Choose a facilitator (e.g. Alpha, 0.5% fee).
  3. 3. Ask that facilitator to settle on-chain.
  4. 4. Get a receipt.
  5. 5. Retry your endpoint with x-paid-proof.
  6. 6. Get 200 OK and the real data.

You don't have to write that flow manually. Use the SDK helper:

client / agentpayAndRequest()
import { payAndRequest } from "@facora/sdk";

const result = await payAndRequest({
  resourceUrl: "http://localhost:3000/api/alpha-feed"
});

console.log(result.data.alpha);
console.log("Settled tx:", result.settlement.txHash);

Note: The @facora/sdk package is included in this repo under /sdk. You can vendor it into your own agent/client code, or treat it as a local package until we publish it to npm.

What payAndRequest() does under the hood:

  1. 1. Calls your /api/alpha-feed.
  2. 2. Sees 402 Payment Required.
  3. 3. Generates (or uses) an EIP-2612 permit for USDx.
    – User only signs a permit, not a transaction.
    – The caller doesn't need BNB for gas.
  4. 4. Sends that permit to the chosen facilitator (e.g. /api/facilitators/alpha).
  5. 5. The facilitator pays gas on BNB testnet, pulls USDx via that permit, sends it to your merchant wallet, and returns settlement proof (tx hash, block number, amount).
  6. 6. The helper retries /api/alpha-feed with x-paid-proof.
  7. 7. You return 200 OK with the protected data.

The caller never broadcasts a transaction and never needs BNB.

Return value shape:

// result:
{
  data: {
    alpha: string; // your protected response body
  };
  settlement: {
    txHash: string;
    blockNumber: number;
    facilitator: string;   // e.g. "Alpha"
    amount: string;        // e.g. "1.00 USDx"
    proofHeader: string;   // what went into x-paid-proof
  };
}

This is designed so you can log the tx, show it back to the user, or store it for audit.

3You get paid. You don't build billing.

Step 3. You get paid. You don't build billing.

• No Stripe.

• No API keys / account provisioning.

• No subscription tiers.

• You get paid per request in USDx on BNB.

• Every payment has an on-chain receipt (tx hash + block number).

• You can show "here's the tx that paid for this response," which is impossible to fake.

This is on-chain metering, not Web2 billing.

4Trust model: strict vs fast unlock

Trust model: strict vs fast unlock

You get to decide when you unlock your data.

Strict mode (safer)

You wait until the facilitator actually settles on-chain and returns a real tx hash. You only serve 200 OK once funds are on-chain in your merchant wallet.

Fast mode (low latency)

You verify the permit signature off-chain and trust a good facilitator to settle a few seconds later. You unlock instantly. This is useful for high-frequency AI agent workflows.

Both modes are supported. It's your call per endpoint.

5Environment variables you need

Environment variables you need

These are required for the demo / testnet flow:

.env.localrequired
NEXT_PUBLIC_USDX_TOKEN_ADDRESS=0xcfFA309a5Fb3ac7419eBC8Ba4a6063Ff2a7585F5
MERCHANT_WALLET_ADDRESS=0x...your_merchant_address
BNB_TESTNET_RPC=https://data-seed-prebsc-1-s1.bnbchain.org:8545
FACILITATOR_ALPHA_PRIVATE_KEY=0x...your_facilitator_private_key

NEXT_PUBLIC_USDX_TOKEN_ADDRESS

Safe to expose. This is the USDx contract on BNB testnet. USDx is our permit-enabled settlement token (ERC20Permit, 6 decimals).

FACILITATOR_ALPHA_PRIVATE_KEY

This MUST only live in server-side code (like /api/facilitators/alpha). Never load it in client components.

MERCHANT_WALLET_ADDRESS

This is where the facilitator (Alpha, Beta, etc.) sends funds when it settles.

6Recap for devs integrating this today

Recap for devs integrating this today

  1. 1. Wrap any route with the 402 pattern above.
  2. 2. Drop in payAndRequest() on the client/agent side.
  3. 3. Configure env vars.
  4. 4. Run it:
    • • Client hits your route
    • • Facilitator pays gas and settles USDx on-chain to you
    • • Your route unlocks and returns 200 OK
    • • You can prove it with the tx hash

And critically: Facilitators are not hardcoded forever. The server returns a list of possible facilitators (Alpha now, Beta/Gamma next). They'll compete on fee, stake FAC as a bond, and can be slashed if they lie about settlement.

That's how we remove the single point of failure in x402.