Skip to main content
Version: v0.12.11

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:

DimensionMPP / paymentauthx402
HTTP mechanismAuthorization / WWW-Authenticate headersHTTP 402 status code + custom headers
Challenge formatWWW-Authenticate: paymentauth challenge="..."X-PAYMENT-REQUIRED header
Payment credentialAuthorization: paymentauth token="..."X-PAYMENT header
IETF statusActive internet draft (draft-ryan-httpauth-payment)Linux Foundation spec (x402.org)
PEAC package@peac/mappings-paymentauth@peac/adapter-x402, @peac/rails-x402
Evidence typeChallenge observation + receipt observationPayment request + payment proof

Both MPP and x402 are supported by PEAC. Use them together for maximum payment rail coverage.


Install

Terminal
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:

mpp-challenge.ts
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:

mpp-receipt.ts
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 URIDescription
org.peacprotocol/paymentauth-challenge-observedServer issued an MPP payment challenge
org.peacprotocol/paymentauth-receipt-observedClient presented valid payment proof
org.peacprotocol/paymentauth-rejection-observedPayment credential was rejected
org.peacprotocol/paymentauth-cancellation-observedPayment flow was cancelled

Express middleware integration

express-mpp.ts
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

Observer scope

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:

multi-rail.ts
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 paymentauth credential alone