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:
- Checks for payment headers (
X-Payment or X402-PAYMENT)
- Verifies the payment signature and amount
- Returns
null if valid (allowing your handler to proceed)
- 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'
});
| Mode | Description |
|---|
verify | Verify only, don’t settle (good for testing) |
settle | Verify and settle on-chain before responding |
async | Return immediately, settle in background |
Verification Backend
Use your deployed verification backend in production.
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.