@rma-dev/http-proxy-util
v0.3.0
Published
HTTP proxy utility for API gating.
Readme
@rma-dev/http-proxy-util
TypeScript library that wraps any HTTP API behind machine payments.
npm install @rma-dev/http-proxy-util mppx stripeThe minimum
Seven lines. Any unpaid request gets a 402 with a Stripe payment challenge; paid requests are forwarded to your origin.
import { createProxy } from '@rma-dev/http-proxy-util'
const proxy = createProxy({
stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
origin: 'https://api.yourservice.com',
routes: [{ method: 'POST', path: '/v1/infer', amount: '0.05' }],
})
Bun.serve({ fetch: proxy.fetch })Multiple routes
Wildcard * matches one path segment. Unlisted routes are forwarded free.
const proxy = createProxy({
stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
origin: 'https://api.yourservice.com',
routes: [
{ method: 'POST', path: '/v1/infer', amount: '0.05', description: 'Single inference' },
{ method: 'GET', path: '/v1/data/*', amount: '0.01' },
],
})Add Tempo (crypto) payments
Include a tempo block to accept PATH stablecoin alongside Stripe. Callers see both options and pick whichever their wallet supports.
const proxy = createProxy({
stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
tempo: { recipient: process.env.TEMPO_RECIPIENT as `0x${string}`, testnet: true },
origin: 'https://api.yourservice.com',
routes: [
{
method: 'POST',
path: '/v1/infer',
pricing: {
stripe: { amount: '0.05', currency: 'usd' },
tempo: { amount: '0.04' }, // slightly cheaper to incentivise crypto
},
},
],
})Add Base USDC payments
const proxy = createProxy({
stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
base: {
payTo: process.env.BASE_PAY_TO as `0x${string}`,
network: 'base-sepolia', // 'base' for mainnet
},
origin: 'https://api.yourservice.com',
routes: [
{
method: 'POST',
path: '/v1/infer',
pricing: {
stripe: { amount: '0.05', currency: 'usd' },
base: { amount: '0.05' },
},
},
],
})All three payment methods
Accept Stripe card, Tempo crypto, and Base USDC simultaneously.
const proxy = createProxy({
stripe: { secretKey: process.env.STRIPE_SECRET_KEY! },
tempo: { recipient: process.env.TEMPO_RECIPIENT as `0x${string}`, testnet: true },
base: { payTo: process.env.BASE_PAY_TO as `0x${string}`, network: 'base-sepolia' },
origin: 'https://api.yourservice.com',
routes: [
{
method: 'POST',
path: '/v1/infer',
description: 'Single inference request',
pricing: {
stripe: { amount: '0.05', currency: 'usd' },
tempo: { amount: '0.04' },
base: { amount: '0.05' },
},
},
{
method: 'GET',
path: '/v1/data/*',
pricing: {
stripe: { amount: '0.01', currency: 'usd' },
tempo: { amount: '0.008' },
base: { amount: '0.01' },
},
},
],
})Framework adapters
All adapters delegate to proxy.fetch.
// Bun
Bun.serve({ port: 3000, fetch: proxy.fetch })
// Hono
app.all('*', (c) => proxy.fetch(c.req.raw))
// Express
app.use(proxy.express())
// Next.js App Router (app/api/[[...path]]/route.ts)
export const { GET, POST, PUT, PATCH, DELETE } = proxy.nextjs()
// Cloudflare Workers / Deno
export default { fetch: proxy.fetch }Built-in endpoints
| Path | Description |
|---|---|
| /llms.txt | Human/LLM-readable pricing and billing info |
| /__stripe-proxy/discover | JSON pricing discovery per route |
| /__stripe-proxy/health | Liveness probe |
| /api/stripe-proxy/create-spt | Test SPT for browser flows (test mode only) |
_meta in request bodies
The proxy reads a _meta object from JSON bodies for customer enrichment, then forwards the full body — including _meta — to the origin unchanged.
{
"prompt": "Hello",
"_meta": {
"email": "[email protected]",
"payment_intent_metadata": { "tenant": "acme" }
}
}Configuration reference
createProxy(options)
| Option | Type | Description |
|---|---|---|
| stripe | StripeConfig? | Stripe card / Link payments |
| tempo | TempoConfig? | Tempo crypto (PATH stablecoin) payments |
| base | BaseConfig? | Base USDC payments |
| origin | string | Upstream service base URL |
| routes | RoutePriceConfig[] | Per-route pricing table |
| services | Record<string, ServiceConfig>? | Named sub-services at /{id}/* |
| title | string? | Proxy name — surfaced in /llms.txt |
| description | string? | Short description — surfaced in /llms.txt |
| blockUnlistedRoutes | boolean? | 404 for routes not in the table (default false) |
| paymentMetadata | Record<string, string>? | Static metadata on every PaymentIntent |
| createCustomers | boolean? | Stripe customer reconciliation (default true) |
| sptEndpoint | string \| null? | Test SPT path (default /api/stripe-proxy/create-spt) |
StripeConfig
| Field | Type | Description |
|---|---|---|
| secretKey | string | sk_test_… or sk_live_… |
| networkId | string? | Stripe Business Network profile ID ('internal' for test) |
| paymentMethodTypes | string[]? | Default: ['card', 'link'] |
TempoConfig
| Field | Type | Description |
|---|---|---|
| recipient | `0x${string}` | Wallet address that receives PATH payments |
| testnet | boolean? | Use Tempo testnet (default false) |
| currency | string? | PATH token address (defaults to PATH_USD) |
BaseConfig
| Field | Type | Description |
|---|---|---|
| payTo | `0x${string}` | EVM wallet that receives USDC |
| network | string? | 'base', 'base-sepolia' (default), or EIP-155 chain ID |
| facilitatorUrl | string? | Payment verification URL (default: https://x402.org/facilitator) |
RoutePriceConfig
| Field | Type | Description |
|---|---|---|
| method | string | HTTP method or '*' |
| path | string | URL path — supports a single * wildcard per segment |
| description | string? | Human-readable label in the payment challenge |
| amount | string? | Flat Stripe price in USD (e.g. '0.05') |
| currency | string? | Currency for flat amount (default 'usd') |
| pricing | RoutePricing? | Per-method pricing (overrides amount/currency) |
| free | boolean? | Forward without a payment gate |
| requireEmail | boolean? | Require _meta.email in the request body |
| requirePhone | boolean? | Require _meta.phone in the request body |
| requireBillingAddress | boolean? | Require _meta.billing_address |
| schema | RouteSchema? | Zod-compatible validators for body/query |
RoutePricing
| Field | Type | Description |
|---|---|---|
| stripe | { amount: string; currency: string }? | Stripe card price |
| tempo | { amount: string }? | Tempo price in PATH units |
| base | { amount: string }? | Base price in USD (converted to USDC internally) |
Peer dependencies
mppx >=0.6.0
stripe >=17.0.0