TypeScript implementation of the "Payment" HTTP Authentication Scheme (402 Protocol).
mppx provides abstractions for the complete HTTP 402 payment flow — both client and server. The architecture has two layers:
-
Mppx— Top-level payment handler. Groups relatedMethods and handles the HTTP 402 flow (challenge/credential parsing, header serialization, verification). -
Method— A payment method definition. Each method has aname(e.g.,charge,session), amethod(e.g.,tempo,stripe), and schemas for request validation and credential payloads.
┌────────────────────┐ ┌────────────────┐
│ Mppx │ 1 * │ Method │
│ (handler) ├───────┤ (definition) │
└────────────────────┘ has └────────────────┘
│ payment │ │ tempo/charge │
│ │ │ tempo/session │
│ │ │ stripe/charge │
└────────────────────┘ └────────────────┘
Client (Mppx) Server (Mppx)
│ │
│ (1) GET /resource │
├──────────────────────────────────────────────────>│
│ │
│ (2) handler.charge(request, { ... }) │
│ 402 + WWW-Authenticate: Payment │
│<──────────────────────────────────────────────────┤
│ │
│ (3) handler.createCredential(response) │
│ │
│ (4) GET /resource │
│ Authorization: Payment <credential> │
├──────────────────────────────────────────────────>│
│ │
│ (5) handler.charge(request) │
│ │
│ (6) 200 OK │
│ Payment-Receipt: <receipt> │
│<──────────────────────────────────────────────────┤
│ │
Low-level data structures that compose into the core abstractions:
Challenge— Server-issued payment request (appears inWWW-Authenticateheader). Containsid,realm,method,intent,request, and optionalexpires/digest.Credential— Client-submitted payment proof (appears inAuthorizationheader). Containschallengeecho,payload(method-specific proof), and optionalsource(payer identity).Method— Payment method definition (e.g.,tempo/charge,stripe/charge). Containsmethod,name, and validatedschema(credential payload + request).Mppx— Top-level payment handler. Groups relatedMethods and handles the HTTP 402 flow.Receipt— Server-issued settlement confirmation (appears inPayment-Receiptheader). Containsstatus,method,timestamp, andreference.Request— Method-specific payment parameters (e.g.,amount,currency,recipient). Validated by the method's schema and serialized in the challenge.
Methods are flat structural types with method, name, and schema:
const tempoCharge = Method.from({
method: 'tempo',
name: 'charge',
schema: {
credential: {
payload: z.object({ signature: z.string(), type: z.literal('transaction') }),
},
request: z.pipe(
z.object({
amount: z.amount(),
chainId: z.optional(z.number()),
currency: z.string(),
decimals: z.number(),
recipient: z.optional(z.string()),
// ...
}),
z.transform(({ amount, decimals, chainId, ... }) => ({
amount: parseUnits(amount, decimals).toString(),
...(chainId !== undefined ? { methodDetails: { chainId } } : {}),
})),
),
},
})Methods are extended with client or server logic via Method.toClient() and Method.toServer():
// Client-side: adds credential creation
const client = Method.toClient(Methods.charge, {
async createCredential({ challenge }) { ... },
})
// Server-side: adds verification
const server = Method.toServer(Methods.charge, {
async verify({ credential }) { ... },
})Canonical specs live at tempoxyz/payment-auth-spec.
| Layer | Spec | Description |
|---|---|---|
| Core | draft-httpauth-payment-00 | 402 flow, WWW-Authenticate/Authorization headers, Payment-Receipt |
| Intent | draft-payment-intent-charge-00 | One-time immediate payment |
| Intent | draft-payment-intent-session-00 | Pay-as-you-go streaming payments |
| Method | draft-tempo-charge-00 | TIP-20 token transfers on Tempo |
| Method | draft-tempo-session-00 | Tempo payment channels for streaming |
| Extension | draft-payment-discovery-00 | OpenAPI-first discovery via /openapi.json |
- Challenge:
WWW-Authenticate: Payment id="...", realm="...", method="...", intent="...", request="<base64url>" - Credential:
Authorization: Payment <base64url>→{ challenge, payload, source? } - Receipt:
Payment-Receipt: <base64url>→{ status, method, timestamp, reference } - Encoding: All JSON payloads use base64url without padding (RFC 4648)
The challenge id is an HMAC-SHA256 over the challenge parameters, cryptographically binding the ID to its contents. This prevents tampering and ensures the server can verify challenge integrity without storing state.
HMAC input (concatenated, pipe-delimited):
realm | method | intent | request | expires | digest
Generation:
id = base64url(HMAC-SHA256(server_secret, input))
Verification: Server recomputes HMAC from echoed challenge parameters and compares to id. If mismatch, reject credential.
mppx is pre-v1. Always use patch bumps unless a change is a substantial, unavoidable breaking change to the public API. New features, additive API surface, internal refactors, and bug fixes are all patches. Reserve minor for genuinely breaking changes that require consumer migration (e.g., removing/renaming a public export, changing a hook signature incompatibly). Never use major until v1.
Never manually edit CHANGELOG.md. Use changesets instead:
Create a .changeset/<name>.md file with frontmatter specifying the package and bump type:
---
'mppx': patch
---
Description of the change.Changeset descriptions must use past tense (e.g. "Added support for …", "Fixed parsing of …"). Describe what the changeset did, not what it does.
The changelog is auto-generated from changesets during changeset version.
pnpm build # Build HTML with rolldown and library with zile
pnpm check # Lint with oxlint + format with oxfmt
pnpm check:types # TypeScript type checking
pnpm check:types:examples # Examples type checking
pnpm check:types:html # HTML type checking
pnpm test # Run tests with vitest
pnpm test:html # Run HTML tests with playwrightLoad these skills for specialized guidance:
Use when: Implementing payment methods, understanding the 402 protocol flow, working with Tempo/Stripe payment method schemas, or referencing the IETF spec.
Use when: Building new modules, structuring exports, or following library patterns.
Use when: Writing or reviewing TypeScript code for style and conventions.
Use when: Referencing Tempo protocol specifics, understanding TIP-20 tokens, Tempo transactions (0x76), or protocol-level details.