MPP / paymentauth
The @peac/mappings-paymentauth package provides PEAC evidence for the Machine Payments Protocol (MPP), also known as paymentauth (draft-ryan-httpauth-payment). MPP enables HTTP-native payment challenges and receipts using the Authorization and WWW-Authenticate headers, complementing x402-style payment flows.
What is MPP?
MPP (Machine Payments Protocol) defines an HTTP authentication-based payment mechanism. A server signals that payment is required by returning a WWW-Authenticate: paymentauth challenge. The client responds with an Authorization: paymentauth credential containing payment proof.
IETF draft: draft-ryan-httpauth-payment (Machine Payments Protocol)
How MPP and x402 compare:
| Dimension | MPP / paymentauth | x402 |
|---|---|---|
| HTTP mechanism | Authorization / WWW-Authenticate headers | HTTP 402 status code + custom headers |
| Challenge format | WWW-Authenticate: paymentauth challenge="..." | X-PAYMENT-REQUIRED header |
| Payment credential | Authorization: paymentauth token="..." | X-PAYMENT header |
| IETF status | Active internet draft (draft-ryan-httpauth-payment) | Linux Foundation spec (x402.org) |
| PEAC package | @peac/mappings-paymentauth | @peac/adapter-x402, @peac/rails-x402 |
| Evidence type | Challenge observation + receipt observation | Payment request + payment proof |
Both MPP and x402 are supported by PEAC. Use them together for maximum payment rail coverage.
Install
pnpm add @peac/mappings-paymentauth @peac/protocol
Quick start
Record an MPP payment challenge
When your server issues an MPP payment challenge, issue a PEAC record of the challenge:
import { fromPaymentauthChallenge } from '@peac/mappings-paymentauth';
import { issue } from '@peac/protocol';
// Build extension from the challenge you issued
const ext = fromPaymentauthChallenge({
challenge: 'paymentauth realm="api.example.com" scheme="usdcbase"',
resource_ref: 'ref:resource/premium-endpoint',
amount_minor: '100',
currency: 'USD',
scheme_id: 'usdcbase',
issued_at: new Date().toISOString(),
});
const jws = await issue({
sub: 'ref:resource/premium-endpoint',
iss: 'https://api.example.com',
type: 'org.peacprotocol/paymentauth-challenge-observed',
extensions: ext,
}, signingKey);
// Return in HTTP response
// WWW-Authenticate: paymentauth ...
// PEAC-Receipt: <jws>
Record an MPP payment receipt
When a client presents valid payment proof, record the receipt:
import { fromPaymentauthReceipt } from '@peac/mappings-paymentauth';
import { issue } from '@peac/protocol';
// Build extension from the payment credential the client presented
const ext = fromPaymentauthReceipt({
credential_ref: 'ref:payment-credential/txn-001',
scheme_id: 'usdcbase',
resource_ref: 'ref:resource/premium-endpoint',
settled_at: new Date().toISOString(),
});
const jws = await issue({
sub: 'ref:payment-credential/txn-001',
iss: 'https://api.example.com',
type: 'org.peacprotocol/paymentauth-receipt-observed',
extensions: ext,
}, signingKey);
Type URIs
| Type URI | Description |
|---|---|
org.peacprotocol/paymentauth-challenge-observed | Server issued an MPP payment challenge |
org.peacprotocol/paymentauth-receipt-observed | Client presented valid payment proof |
org.peacprotocol/paymentauth-rejection-observed | Payment credential was rejected |
org.peacprotocol/paymentauth-cancellation-observed | Payment flow was cancelled |
Express middleware integration
import express from 'express';
import { fromPaymentauthChallenge } from '@peac/mappings-paymentauth';
import { issue } from '@peac/protocol';
const app = express();
app.use('/premium', async (req, res, next) => {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('paymentauth ')) {
// Issue challenge + PEAC record of the challenge
const ext = fromPaymentauthChallenge({
challenge: 'paymentauth realm="api.example.com"',
resource_ref: `ref:resource${req.path}`,
issued_at: new Date().toISOString(),
});
const jws = await issue({
sub: `ref:resource${req.path}`,
iss: process.env.PEAC_ISSUER_URL!,
type: 'org.peacprotocol/paymentauth-challenge-observed',
extensions: ext,
}, signingKey);
res
.status(401)
.set('WWW-Authenticate', 'paymentauth realm="api.example.com"')
.set('PEAC-Receipt', jws)
.json({ error: 'Payment required' });
return;
}
// Validate payment credential, then record the receipt
next();
});
Finality rules
MPP payment records are observer scope only. A paymentauth-receipt-observed record means your server observed the client present a payment credential. It does not guarantee:
- That the underlying payment settled on-chain or in the payment network
- That funds were transferred
- That the payment credential was valid (only that it was presented)
Issue a paymentauth-receipt-observed record only after your payment validation logic confirms the credential is valid. The record attests to your server's validation outcome, not the payment network's settlement.
Combining MPP and x402
For maximum coverage across payment rail clients, support both MPP (HTTP Auth headers) and x402 (HTTP 402 status). PEAC provides evidence packages for both:
import { fromPaymentauthChallenge } from '@peac/mappings-paymentauth';
import { fromX402PaymentRequired } from '@peac/adapter-x402';
// Detect the client's preferred payment mechanism
const clientPrefers = req.headers['accept-payment']?.includes('paymentauth')
? 'mpp'
: 'x402';
if (clientPrefers === 'mpp') {
// MPP: WWW-Authenticate: paymentauth + 401
const ext = fromPaymentauthChallenge({ ... });
// ...
} else {
// x402: HTTP 402 + X-PAYMENT-REQUIRED
const ext = fromX402PaymentRequired({ ... });
// ...
}
Non-goals
MPP / paymentauth records do not:
- Process payments or move funds
- Validate payment credentials against a payment network
- Replace your payment processor or settlement infrastructure
- Guarantee finality from the
paymentauthcredential alone
Related
- x402 Integration: x402 payment evidence
- Payment Rails: All supported payment rail adapters
- A2A Integration: Carry payment evidence through A2A metadata
- Verification: Verify MPP records offline