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

```http
WWW-Authenticate: Payment id="<uuid>", realm="<seller_id>", method="inflow", intent="charge", request="<base64url>", opaque="<base64url>"
```

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

```json
{
    "amount": "0.0098",
    "currency": "USDC",
    "methodDetails": {
        "rail": "balance"
    }
}
```

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

```json
{
    "challenge": {
        /* echoed challenge object */
    },
    "payload": {
        "transactionId": "tx_abc123"
    },
    "source": "buyer-identity"
}
```

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

```json
{
    "method": "inflow",
    "reference": "tx-ref-abc123",
    "status": "settled",
    "timestamp": 1722470400
}
```

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

1. **JCS (RFC 8785)** — JSON Canonicalization Scheme: keys sorted alphabetically, null values omitted, no whitespace
2. **Base64url** — URL-safe Base64 without padding (`=`)

### Example Encoding

Input:

```json
{ "currency": "USDC", "amount": "0.0098" }
```

JCS canonical form (keys sorted):

```json
{ "amount": "0.0098", "currency": "USDC" }
```

Base64url encoded:

```
eyJhbW91bnQiOiIwLjAxIiwiY3VycmVuY3kiOiJVU0RDIn0
```

## 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.

```json
{
    "error": {
        "code": "payment_required",
        "message": "Payment required. Use mppx CLI or x402 USDC on Base."
    },
    "payment": {
        "amount": "0.0098",
        "currency": "USDC",
        "display": "$9.80 per 1,000 requests",
        "supported_rails": ["tempo_mpp", "x402_base"]
    },
    "agent_instructions": "{\"action\":\"pay_then_retry\",\"steps\":[...]}",
    "agent_memory": {
        "save_for_future_tomba_agents_gates": true,
        "pattern_summary": "...",
        "payment_paths": { "mppx_cli": "...", "x402_base": "..." }
    },
    "how_to_pay": {
        "mppx": "mppx https://agents.tomba.io/<endpoint>",
        "x402": "agentscore-pay pay GET https://agents.tomba.io/<endpoint> --chain base"
    }
}
```

### 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 `opaque` field 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.
