Skip to main content
Accept crypto payments in your Bun HTTP server with a single function call.

Installation

# npm
npm install @armory-sh/middleware-bun

# yarn
yarn add @armory-sh/middleware-bun

# pnpm
pnpm add @armory-sh/middleware-bun

# bun
bun add @armory-sh/middleware-bun

Quick Start

import { createBunMiddleware } from '@armory-sh/middleware-bun';

const middleware = createBunMiddleware({
  payTo: '0xYourWalletAddress...',
  amount: '1.0'
});

Bun.serve({
  port: 3000,
  fetch: async (req) => {
    const result = await middleware(req);

    // If middleware returns a response, payment failed/required
    if (result) return result;

    // Payment verified — handle your request
    return new Response(JSON.stringify({ data: 'protected content' }));
  }
});

How It Works

The middleware intercepts incoming requests and:
  1. Checks for payment headers (X-Payment or X402-PAYMENT)
  2. Verifies the payment signature and amount
  3. Returns null if valid (allowing your handler to proceed)
  4. Returns a Response with 402 status if payment is missing or invalid

Configuration

Required Options

{
  payTo: string,     // Your wallet address
  amount: string | bigint  // Amount to charge
}

Settlement Modes

Control how payments are settled after verification:
const middleware = createBunMiddleware({
  payTo: '0x...',
  amount: '1.0',
  settlementMode: 'verify'  // | 'settle' | 'async'
});
ModeDescription
verifyVerify only, don’t settle (good for testing)
settleVerify and settle on-chain before responding
asyncReturn immediately, settle in background

Verification Backend

Use your deployed verification backend in production.

Response Format

On successful payment verification, the middleware returns a Response with: Headers:
  • X-Payment-Verified: true
  • X-Payer-Address: 0x...
Body:
{
  "verified": true,
  "payerAddress": "0x...",
  "version": 2
}

Error Responses

402 Payment Required

No payment header was provided.
{
  "error": "Payment required"
}

402 Verification Failed

Payment signature or amount was invalid.
{
  "error": "Payment verification failed: ..."
}

400 Settlement Failed

Settlement mode was settle but on-chain transaction failed.
{
  "error": "Settlement failed"
}

Tips

For development and testing, use settlementMode: 'verify' to skip on-chain settlement while still verifying payment signatures.
The amount can be specified as a human-readable string like "1.0" for 1 token, or as a bigint for precise control over decimals.
Always validate the payTo address matches your wallet. The middleware does not check if the address is valid or belongs to you.

Advanced Mix-and-Match Config (Current API)

Use paymentMiddleware for per-token/per-network facilitator routing and extension-aware challenge headers:
import { paymentMiddleware } from "@armory-sh/middleware-bun";

const middleware = paymentMiddleware({
  payTo: "0x1234567890123456789012345678901234567890",
  chains: ["base", "skale-base"],
  tokens: ["usdc", "usdt", "weth", "wbtc"],
  amount: "1.0",
  facilitatorUrl: "https://fallback-facilitator.example",
  facilitatorUrlByChain: {
    base: "https://payai.example",
  },
  facilitatorUrlByToken: {
    base: { usdc: "https://payai.example" },
    "skale-base": {
      usdc: "https://payai.example",
      usdt: "https://kobaru.example",
      weth: "https://kobaru.example",
      wbtc: "https://kobaru.example",
    },
  },
  extensions: {
    bazaar: { info: { input: { sku: "pro-plan" } }, schema: { type: "object" } },
    "sign-in-with-x": { info: { domain: "api.example.com" }, schema: { type: "object" } },
  },
});
For fully custom amount-per-combination behavior, pass explicit requirements:
paymentMiddleware({
  requirements: [
    {
      scheme: "exact",
      network: "eip155:8453",
      amount: "1000000",
      asset: "0x833589fCD6eDb6E08f4c7C32D4f71B54bdA02913",
      payTo: "0x1234567890123456789012345678901234567890",
      maxTimeoutSeconds: 300,
    },
    {
      scheme: "exact",
      network: "eip155:1187947933",
      amount: "2500000",
      asset: "0x5f9beea3f6f22be1f4f8efc120f5095f58dbb8a2",
      payTo: "0x1234567890123456789012345678901234567890",
      maxTimeoutSeconds: 300,
    },
  ],
  facilitatorUrlByToken: {
    base: { usdc: "https://payai.example" },
    "skale-base": { usdt: "https://kobaru.example" },
  },
});
Unsupported extension keys are auto-ignored (fail-open) per facilitator /supported capability response.