MPP (Machine Payments Protocol)

MPP (the Machine Payments Protocol) carries pay-per-request payments through HTTP's standard authentication headers: a 402 challenges with WWW-Authenticate: Payment, the client answers with an Authorization: Payment credential, and the settled response returns a signed Payment-Receipt. Its evm method settles USDC by EIP-3009; its tempo method settles natively on Tempo.

Payment as an HTTP auth scheme

The web already has a way for a server to say "you need to present something before I answer": the WWW-Authenticate and Authorization headers defined in RFC 9110, the mechanism behind login prompts. MPP adds a scheme to it called Payment. A server challenges with WWW-Authenticate: Payment, the client answers with Authorization: Payment, and a successful answer carries a signed Payment-Receipt.

MPP and x402 express the same idea in different headers. A server can speak both on one route at one price, and every paid route on this server does.

Anatomy of a challenge

This is the challenge this server sends for POST /api/hash:

WWW-Authenticate: Payment id="8w5V62E37kA2OiliORKf6BFEX56u4_eomTkyMpYJDeY",
  realm="agent402.tools", method="evm", intent="charge",
  request="eyJhbW91bnQiOiIxMDAwIi...", expires="2026-09-24T12:41:07.520Z",
  opaque="eyJ4NDAyIjoie1wic2NoZW1l..."
  • method: how the payment settles. evm is an EIP-3009 USDC authorization; tempo is a native transfer on the Tempo chain.
  • intent: charge is a one-off payment for this request.
  • request: base64url JSON with the amount, currency, recipient and chain.
  • id: a signed binding, so the server can check it minted this challenge.
  • expires: after this time the challenge is no longer accepted.
// base64url-decoded "request" parameter of the challenge above
{
  "amount": "1000",
  "currency": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "methodDetails": { "chainId": 8453, "credentialTypes": ["authorization"], "decimals": 6 },
  "recipient": "0xPAYTO..."
}

Paying it

The mppx client wraps fetch and pays whichever method it has configured. With both methods listed it can pay on Tempo or on an EVM chain from the same key.

import { Fetch, evm, tempo } from "mppx/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.AGENT_KEY);
const mppFetch = Fetch.from({ methods: [tempo.charge({ account }), evm.charge({ account })] });

const res = await mppFetch("https://agent402.tools/api/hash", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ text: "hello world" }),
});
console.log(res.headers.get("payment-receipt"));   // signed receipt on success

When a credential is refused

A refused credential is answered with a 402, fresh challenges and an application/problem+json body in the RFC 9457 shape: a type URL naming the reason (for example verification-failed or payment-insufficient), a title and a detail sentence. Nothing is charged, and the client can retry with the new challenge.

Related