|
| 1 | +# x402 Payments (buyer / payer) |
| 2 | + |
| 3 | +Use this when an HTTP request returns **`402 Payment Required`** following the |
| 4 | +[x402 protocol](https://docs.x402.org), or when the user asks to pay for / fetch a paywalled API, |
| 5 | +endpoint, file, or resource over HTTP. |
| 6 | + |
| 7 | +`scripts/x402_pay.py` performs the payment: it fetches the URL, reads the server's payment |
| 8 | +requirements, signs an EIP-3009 authorization with `mm wallet sign-typed-data`, retries with the |
| 9 | +payment header, and reports the settlement. Signing is delegated to `mm`, so the private key stays |
| 10 | +in the wallet. The script is pure Python standard library (run with `python3`). |
| 11 | + |
| 12 | +## How x402 works (exact scheme, EVM) |
| 13 | + |
| 14 | +1. The client requests a resource. The server replies `402` with one or more **payment options** |
| 15 | + (scheme, network, amount, asset, `payTo`, validity window). |
| 16 | +2. The client signs an EIP-3009 `TransferWithAuthorization` for one option. This is a gasless, |
| 17 | + off-chain authorization (no on-chain tx from the payer) permitting a pull of exactly the amount |
| 18 | + to `payTo`. |
| 19 | +3. The client retries with the payment header. The server's facilitator settles on-chain and |
| 20 | + returns the resource plus a settlement header (tx hash). |
| 21 | + |
| 22 | +The script handles both protocol versions: v1 (requirements in the `402` body, retry header |
| 23 | +`X-PAYMENT`) and v2 (requirements in the `PAYMENT-REQUIRED` header, retry header |
| 24 | +`PAYMENT-SIGNATURE`). |
| 25 | + |
| 26 | +## Usage |
| 27 | + |
| 28 | +Inspect first (read-only: no signing, no spending), show the result to the user, then pay. |
| 29 | + |
| 30 | +```bash |
| 31 | +python3 scripts/x402_pay.py inspect <url> |
| 32 | +python3 scripts/x402_pay.py pay <url> --confirm [--asset <contract>] [--network <network>] |
| 33 | +``` |
| 34 | + |
| 35 | +`inspect` prints the payment requirement(s) as JSON, including the human-readable amount, asset |
| 36 | +symbol, network, `payTo`, and resource. `pay` runs the payment for a single eligible option and |
| 37 | +prints the settlement (`transaction`) and the resource body. It requires `--confirm`. When the |
| 38 | +`402` offers more than one eligible option, choose one with `--asset` or `--network`. |
| 39 | + |
| 40 | +### Example |
| 41 | + |
| 42 | +```bash |
| 43 | +python3 scripts/x402_pay.py inspect https://api.example.com/premium |
| 44 | +# review the amount / payTo / resource with the user, then: |
| 45 | +python3 scripts/x402_pay.py pay https://api.example.com/premium --confirm |
| 46 | +``` |
| 47 | + |
| 48 | +## What the script checks |
| 49 | + |
| 50 | +It pays an option whose `scheme` is `exact` on a network `mm` supports (resolved from |
| 51 | +`mm chains list`). Before signing it verifies the amount is a positive atomic-unit integer, the |
| 52 | +asset and `payTo` are valid addresses, the EIP-712 domain (`name`/`version`) is present, and the |
| 53 | +URL is `https://` (plain `http` is allowed only on loopback for local testing). It does not follow |
| 54 | +redirects, so a cross-host redirect cannot divert payment. After paying it makes a single retry |
| 55 | +and reports settlement; it never retries a payment. |
| 56 | + |
| 57 | +These are protocol-correctness checks. Which currencies and amounts are allowed is the wallet's |
| 58 | +decision: the asset comes from the server's offer, the user confirms it, and `mm` signs (and is |
| 59 | +where spend policy applies). The script does not keep its own currency allowlist. |
| 60 | + |
| 61 | +## Assets and decimals |
| 62 | + |
| 63 | +The server chooses which assets it accepts; the client can only pay one the server offered. The |
| 64 | +script reads the asset's symbol and decimals from `mm token assets` for display. When `mm` cannot |
| 65 | +resolve them (for example on testnets the Token API does not index), it shows the raw atomic |
| 66 | +amount; the signed value is the server's atomic amount either way. |
| 67 | + |
| 68 | +## Wallet modes |
| 69 | + |
| 70 | +- **Server-wallet:** signing runs synchronously via `--wait` (guard mode permits EIP-712 signing). |
| 71 | + The x402 window is short, so if a signature needs manual approval and is slow, the authorization |
| 72 | + can expire; rerun `pay` to sign again with fresh values. |
| 73 | +- **BYOK:** signing returns immediately. Set `MM_PASSWORD` for an encrypted mnemonic so signing is |
| 74 | + non-interactive. |
| 75 | + |
| 76 | +## Confirmation |
| 77 | + |
| 78 | +Run `inspect` and show the user the asset, amount, network, `payTo`, and resource URL. Run |
| 79 | +`pay ... --confirm` only after the user approves. A signature authorizes a real token debit. |
| 80 | + |
| 81 | +## Idempotency |
| 82 | + |
| 83 | +The script is stateless. The EIP-3009 nonce prevents the same signed authorization from settling |
| 84 | +twice, and each run makes one payment, but rerunning `pay` for the same resource makes a new |
| 85 | +payment. Guard repeated calls at the caller. A local idempotency ledger (a caller-supplied key |
| 86 | +mapped to prior settlements) is a possible future improvement. |
0 commit comments