MPP Protocol Reference
Protocol Overview
MPP implements the IETF Payment HTTP authentication scheme. It uses standard HTTP headers to negotiate payments between buyers (AI agents) and sellers (API providers).
HTTP Headers
| Phase | Header | Direction | Description |
|---|---|---|---|
| Challenge | WWW-Authenticate: Payment | Server → Client | Payment challenge with pricing |
| Payment | Authorization: Payment <credential> | Client → Server | Payment proof |
| Receipt | Payment-Receipt | Server → Client | Settlement confirmation |
Challenge Format
When a request lacks payment, the server returns 402 Payment Required with:
Code
Challenge Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique challenge identifier (UUID) |
realm | string | Seller identifier |
method | string | Payment method (always "inflow") |
intent | string | Payment intent (always "charge") |
request | string | Base64url-JCS encoded charge request |
opaque | string | HMAC-signed binding blob (do not modify) |
expires | number | Unix timestamp when challenge expires (5 minutes) |
Decoded Request Object
The request field decodes to:
Code
| Field | Type | Description |
|---|---|---|
amount | string | Decimal amount to charge |
currency | string | Currency code (USDC, USD, etc.) |
methodDetails.rail | string | Payment rail: "balance" (crypto) or "instrument" (fiat) |
Credential Format
The buyer constructs a credential and sends it via Authorization: Payment <base64url-JCS>:
Code
| Field | Type | Description |
|---|---|---|
challenge | object | The original challenge, echoed back |
payload.transactionId | string | InFlow transaction ID from payment |
source | string | Buyer identity (set by InFlow) |
Receipt Format
On successful payment, the server includes Payment-Receipt header:
Code
| Field | Type | Description |
|---|---|---|
method | string | Payment method used |
reference | string | Settlement reference ID |
status | string | Settlement status |
timestamp | number | Unix timestamp of settlement |
Encoding
All MPP messages use Base64url-JCS encoding:
- JCS (RFC 8785) — JSON Canonicalization Scheme: keys sorted alphabetically, null values omitted, no whitespace
- Base64url — URL-safe Base64 without padding (
=)
Example Encoding
Input:
Code
JCS canonical form (keys sorted):
Code
Base64url encoded:
Code
Rail Selection
The payment rail is determined by the currency:
| Currency | Rail | Description |
|---|---|---|
USDC, USDT, ETH | balance | Crypto via InFlow internal ledger |
USD, EUR, GBP, CAD, AUD, JPY | instrument | Fiat via payment instruments |
Error Responses
402 Payment Required
Returned when no Authorization: Payment header is present or payment verification fails.
Code
Payment Verification Failures
If the credential is invalid, expired, or tampered with, a new 402 challenge is issued. Common reasons:
| Reason | Description |
|---|---|
| Challenge expired | The 5-minute challenge window has passed |
| Invalid binding | The opaque field has been tampered with |
| Redeem failed | InFlow rejected the payment credential |
| Decode error | The credential is not valid Base64url-JCS |
Security
- HMAC binding — The
opaquefield contains an HMAC-SHA256 signature binding the amount, currency, rail, and expiry. Tampering is detected and rejected. - Short-lived challenges — Challenges expire after 5 minutes to prevent replay attacks.
- Server-side verification — All credentials are verified server-side via the InFlow payment network. No client-side trust.
- Idempotent settlement — InFlow handles idempotency via transaction IDs.