Accept crypto payments in your Hono API with a single middleware function.
Installation
# npm
npm install @armory-sh/middleware-hono
# yarn
yarn add @armory-sh/middleware-hono
# pnpm
pnpm add @armory-sh/middleware-hono
# bun
bun add @armory-sh/middleware-hono
Quick Start
import { Hono } from 'hono';
import { acceptPaymentsViaArmory } from '@armory-sh/middleware-hono';
const app = new Hono();
app.use('/api/*', acceptPaymentsViaArmory({
payTo: '0xYourWalletAddress...',
amount: '1.0'
}));
app.get('/api/protected', (c) => {
const payment = c.get('payment');
return c.json({ message: `Hello ${payment.payerAddress}!` });
});
app.listen(3000);
How It Works
The middleware intercepts requests and:
- Checks for payment headers (
X-Payment or X402-PAYMENT)
- Verifies the payment signature and amount
- Stores payment info in the Hono context
- Calls
next() if valid, or returns 402 if invalid
Configuration
Minimal Setup
acceptPaymentsViaArmory({
payTo: '0xYourWallet...', // Your wallet address
amount: '1.0' // Amount in tokens (e.g., 1 USDC)
});
All Options
{
payTo: string, // Your wallet address
amount: string | bigint, // Amount to charge
token?: string, // Token symbol (default: USDC)
network?: string, // Network name (default: base)
defaultVersion?: 1 | 2 // Payment version (default: 2)
}
Accessing Payment Info
Payment information is stored in the Hono context:
app.get('/api/user', (c) => {
const payment = c.get('payment');
return c.json({
payer: payment.payerAddress,
paid: payment.payload.amount,
token: payment.payload.token
});
});
Available Properties:
| Property | Type | Description |
|---|
payload | PaymentPayload | Decoded payment payload |
payerAddress | string | Wallet address of the payer |
version | 1 | 2 | Payment protocol version |
verified | true | Always true when request reaches your handler |
On successful verification:
X-Payment-Verified: true
X-Payer-Address: 0x...
X-Payment-Response: {"status":"verified","payerAddress":"0x...","version":2}
Error Responses
402 Payment Required
{
"error": "Payment required",
"requirements": { ... }
}
402 Verification Failed
{
"error": "Payment verification failed: ..."
}
Multi-Network Support
Accept payments across multiple networks and tokens:
app.use('/api/*', acceptPaymentsViaArmory({
payTo: '0x...',
amount: '1.0',
accept: {
networks: ['base', 'ethereum', 'polygon'],
tokens: ['usdc', 'usdt']
}
}));
Advanced Mix-and-Match Config (Current API)
import { Hono } from "hono";
import { paymentMiddleware } from "@armory-sh/middleware-hono";
const app = new Hono();
app.use(
"/api/*",
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" } },
},
}),
);
If you need fully custom amount-per-requirement combinations, use 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" },
},
});
Extension keys are fail-open filtered by facilitator capability: unsupported keys are automatically omitted from PAYMENT-REQUIRED.
Tips
The amount parameter accepts human-readable strings like "1.0" for 1 token, or use bigint for precise decimal control.
Hono middleware applies to routes that match the path pattern. Use /api/* to protect all API routes, or specific paths like /premium/* for paid content.
The middleware will return 402 before your handler runs if payment is missing or invalid. Only verified requests reach your route handlers.