Proxy
Paid API proxy
Gates upstream API services behind MPP 402 payments. The proxy handles routing, Credential injection, and payment verification—you configure which endpoints require payment and which are free passthrough.
Install
Usage
Import Proxy and a service preset from mppx/proxy, then create an Mppx server instance from mppx/server to define payment intents.
import { , } from 'mppx/proxy'
import { , } from 'mppx/server'
const = .({ : [.()] })
const = .({
: [
({
: ..!,
: {
'POST /v1/chat/completions': .({ : '0.05' }),
'GET /v1/models': true,
},
}),
],
})
// Bun / Deno
export default { : . }
// Node.js
import { } from 'node:http'
(.).(3000)The proxy returns two handlers:
fetch— Fetch API handler. Works with Bun, Deno, Next.js, Hono, Elysia, and SvelteKit.listener— Node.js request listener. Works with Express, Fastify, andhttp.createServer.
Route values use the current EndpointMap shape:
- Use an mppx intent handler like
mppx.charge({ amount: '0.05' })for paid routes. - Use
truefor free passthrough routes. - Use a method-specific handler, such as
mppx.tempo.session({ amount, unitType }), for session-priced routes.
Multiple services
Pass multiple services to gate several upstream APIs behind a single proxy.
import { , , , } from 'mppx/proxy'
import { , } from 'mppx/server'
const = .({ : [.()] })
const = .({
: 'Multi-service paid API proxy',
: 'My Proxy',
: [
({
: ..!,
: {
'POST /v1/chat/completions': .({ : '0.05' }),
},
}),
({
: ..!,
: {
'POST /v1/messages': .({ : '0.03' }),
},
}),
({
: ..!,
: {
'POST /v1/charges': .({ : '1' }),
'GET /v1/customers/:id': true,
},
}),
],
})Each service is mounted at /{serviceId}/—for example, requests to /openai/v1/chat/completions route to https://api.openai.com/v1/chat/completions.
Built-in services
openai
Creates an OpenAI service definition. Injects Authorization: Bearer header for upstream authentication.
import { openai } from 'mppx/proxy'
openai({
apiKey: 'sk-...',
routes: {
'POST /v1/chat/completions': mppx.charge({ amount: '0.05' }),
'POST /v1/embeddings': mppx.charge({ amount: '0.01' }),
'POST /v1/images/generations': mppx.charge({ amount: '0.10' }),
'GET /v1/models': true,
},
})| Parameter | Type | Description |
|---|---|---|
apiKey | string | OpenAI API key. Used as Authorization: Bearer header. |
baseUrl (optional) | string | Base URL override. Defaults to 'https://api.openai.com'. |
onUpstreamError (optional) | UpstreamErrorHandler | Handles failed upstream attempts and can retry them. |
routes | EndpointMap | Route definitions for OpenAI endpoints. |
Typed routes: POST /v1/chat/completions, POST /v1/completions, POST /v1/embeddings, POST /v1/images/generations, POST /v1/images/edits, POST /v1/images/variations, POST /v1/audio/transcriptions, POST /v1/audio/translations
anthropic
Creates an Anthropic service definition. Injects x-api-key header for upstream authentication.
import { anthropic } from 'mppx/proxy'
anthropic({
apiKey: 'sk-ant-...',
routes: {
'POST /v1/messages': mppx.charge({ amount: '0.03' }),
'POST /v1/complete': mppx.charge({ amount: '0.02' }),
},
})| Parameter | Type | Description |
|---|---|---|
apiKey | string | Anthropic API key. Used as x-api-key header. |
baseUrl (optional) | string | Base URL override. Defaults to 'https://api.anthropic.com'. |
onUpstreamError (optional) | UpstreamErrorHandler | Handles failed upstream attempts and can retry them. |
routes | EndpointMap | Route definitions for Anthropic endpoints. |
Typed routes: POST /v1/messages, POST /v1/messages/batches, GET /v1/messages/batches, GET /v1/messages/batches/:batchId, POST /v1/complete
stripe
Creates a Stripe service definition. Injects Authorization: Basic header (API key as username) for upstream authentication. This is a proxy service for the Stripe API—not a payment method.
import { stripe } from 'mppx/proxy'
stripe({
apiKey: 'sk-...',
routes: {
'POST /v1/charges': mppx.charge({ amount: '1' }),
'GET /v1/customers/:id': true,
},
})| Parameter | Type | Description |
|---|---|---|
apiKey | string | Stripe API key. Used as Basic auth username. |
baseUrl (optional) | string | Base URL override. Defaults to 'https://api.stripe.com'. |
onUpstreamError (optional) | UpstreamErrorHandler | Handles failed upstream attempts and can retry them. |
routes | EndpointMap | Route definitions for Stripe endpoints. |
Typed routes: POST /v1/charges, POST /v1/customers, GET /v1/customers/:id, POST /v1/payment_intents, GET /v1/payment_intents/:id, POST /v1/subscriptions, GET /v1/subscriptions/:id, POST /v1/invoices, GET /v1/invoices/:id
Custom services
Use Service.from (or its alias custom) to define a service for any upstream API.
With bearer shorthand
import { , } from 'mppx/proxy'
import { , } from 'mppx/server'
const = .({ : [.()] })
const = .({
: [
.('my-api', {
: 'https://api.example.com',
: ..!,
: 'Example upstream API',
: 'My API',
: {
'POST /v1/generate': .({ : '0.01' }),
'GET /v1/status': true,
},
}),
],
})With headers shorthand
import { Service } from 'mppx/proxy'
Service.from('custom-api', {
baseUrl: 'https://api.example.com',
headers: {
'X-API-Key': process.env.CUSTOM_API_KEY!,
'X-Org-Id': 'org-123',
},
routes: {
'POST /v1/query': mppx.charge({ amount: '0.02' }),
},
})With rewriteRequest
For full control over the upstream request, use rewriteRequest. The context includes per-endpoint options set via the options field on an endpoint definition.
import { Service } from 'mppx/proxy'
Service.from('advanced-api', {
baseUrl: 'https://api.example.com',
rewriteRequest(request, ctx) {
request.headers.set('Authorization', `Token ${process.env.API_TOKEN}`)
return request
},
routes: {
'POST /v1/generate': mppx.charge({ amount: '0.05' }),
},
})Recover from upstream errors
Use onUpstreamError to retry thrown request errors or non-2xx upstream responses. The hook receives the one-based attempt number, the rewritten upstream request, and either an error or a cloned response.
import { } from 'mppx/proxy'
.('resilient-api', {
: 'https://api.example.com',
({ , }) {
const = ! || . === 429 || . >= 500
if ( < 3 && ) {
return {
: 250 * ,
: true,
}
}
return { : false }
},
: {
'POST /v1/generate': true,
},
})Request bodies remain available across retries, and retries don't re-verify payment. Return { retry: false } to preserve the original failure, or include a response to replace it. A service-level hook overrides the default hook on Proxy.create.
Discovery endpoints
The proxy automatically serves discovery endpoints that describe available services and their routes. Coding agents and CLI tools use these endpoints to understand what the proxy offers.
| Endpoint | Content-Type | Description |
|---|---|---|
GET /discover | application/json or text/plain | Lists all services. Returns JSON by default, markdown for AI user agents and terminal clients. |
GET /discover/{id} | application/json or text/markdown | Details for a single service, including routes and pricing. |
GET /discover/{id}.md | text/markdown | Markdown description of a single service. |
GET /discover/all | application/json or text/markdown | All services with full route details. |
GET /discover/all.md | text/markdown | Markdown listing of all services and routes. |
GET /llms.txt | text/plain | llms.txt-formatted overview of the proxy and its services. |
GET /discover.md | text/plain | Alias for /llms.txt. |
The proxy returns markdown instead of JSON when the request comes from a known AI user agent (for example, ChatGPT-User, ClaudeBot, PerplexityBot) or a terminal client (for example, curl, HTTPie, mppx).
Parameters
Proxy.create accepts these config fields:
basePath (optional)
- Type:
string
Base path prefix to strip before routing (for example, '/api/proxy'). Use when the proxy is mounted at a sub-path.
description (optional)
- Type:
string
Short description of the proxy shown in llms.txt and discovery endpoints.
fetch (optional)
- Type:
typeof globalThis.fetch
Custom fetch implementation. Defaults to globalThis.fetch.
onUpstreamError (optional)
- Type:
Service.UpstreamErrorHandler
Default handler for thrown upstream request errors and non-2xx responses. Return { retry: true, delay? } to retry or { retry: false, response? } to stop. A service can override this hook.
services
- Type:
Service[]
Array of service definitions to proxy. Each service is mounted at /{serviceId}/.
title (optional)
- Type:
string
Human-readable title for the proxy shown in llms.txt and discovery endpoints.
Service type reference
Service.from config
baseUrl
- Type:
string
Base URL of the upstream service (for example, 'https://api.openai.com').
bearer (optional)
- Type:
string
Shorthand: injects Authorization: Bearer {token} header on upstream requests.
description (optional)
- Type:
string
Short description of the service, shown in discovery endpoints.
docsLlmsUrl (optional)
- Type:
string | ((options: { route?: string }) => string | undefined)
Documentation URL for the service. Provide a string for a static URL, or a function that receives an optional route pattern and returns a per-endpoint docs URL.
headers (optional)
- Type:
Record<string, string>
Shorthand: injects custom headers on upstream requests.
mutate (optional)
- Type:
(req: Request) => Request | Promise<Request>
Shorthand: full request mutation function. Takes priority over bearer and headers.
onUpstreamError (optional)
- Type:
(context: UpstreamErrorContext) => MaybePromise<UpstreamErrorAction>
Handles thrown upstream request errors and non-2xx responses. The context includes attempt, error, response, upstreamRequest, and the standard service context. Return { retry: true, delay? } to retry or { retry: false, response? } to stop.
rewriteRequest (optional)
- Type:
(req: Request, ctx: Context) => Request | Promise<Request>
Hook to modify the upstream request before sending. Receives per-endpoint options via ctx.
routes
- Type:
EndpointMap
Map of "METHOD /pattern" keys to endpoint definitions. Each value is one of:
IntentHandler— Payment required. The handler issues a402Challenge or verifies payment.{ pay: IntentHandler, options: EndpointOptions }— Payment required with per-endpoint config overrides passed torewriteRequestviactx.true— Free passthrough. No payment required;rewriteRequestis still applied.
title (optional)
- Type:
string
Human-readable title for the service (for example, 'OpenAI').