# Machine Payments Protocol (MPP) — full corpus # LLM Wiki An open-source template for building LLM-powered knowledge bases, following [Andrej Karpathy's "LLM Wiki" pattern](https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f). You provide raw sources. The LLM reads them, writes structured wiki pages, cross-links everything, and maintains it over time. You never edit the wiki directly — you curate sources and ask questions. ## How It Works The system has three layers: ``` raw/ Sources you collect (articles, transcripts, notes, PDFs) wiki/ LLM-written & maintained pages (summaries, concepts, entities, syntheses) CLAUDE.md Schema that tells the LLM how to structure everything ``` Three operations drive the workflow: | Operation | Trigger | What happens | |-----------|---------|--------------| | **Ingest** | "ingest raw/my-source.txt" | LLM reads the source, creates a summary page, creates/updates concept and entity pages, adds cross-links, updates the index and log | | **Query** | Ask any question | LLM searches the wiki, synthesizes an answer with citations, optionally creates a synthesis page for novel insights | | **Lint** | "lint" or "health check" | LLM audits all pages for orphans, contradictions, missing links, incomplete sections, and low-confidence claims — fixes what it can, reports the rest | ## Quick Start 1. **Clone this repo** ```bash git clone https://github.com/YOUR_USERNAME/llm-wiki.git my-knowledge-base cd my-knowledge-base ``` 2. **Customize CLAUDE.md** for your domain - Update the Purpose section with your topic - Replace the placeholder tagging taxonomy with your own categories - Adjust confidence level descriptions if needed - Everything else (workflows, page formats, linking rules) works as-is 3. **Drop sources into `raw/`** - Text files, transcripts, articles, notes — any plain text - These are immutable once added; the LLM never modifies them 4. **Tell the LLM to ingest** ``` ingest raw/my-first-source.txt ``` The LLM will create summary pages, concept pages, entity pages, cross-links, and update the index. 5. **Ask questions** ``` What are the key differences between X and Y? ``` The LLM answers from the wiki, citing specific pages. 6. **Run health checks** ``` lint ``` The LLM audits the wiki and fixes issues. ## Directory Structure ``` . ├── CLAUDE.md # Schema — the LLM's instructions ├── raw/ # Your source documents (immutable) └── wiki/ ├── index.md # Master catalog of all pages ├── log.md # Append-only activity log ├── dashboard.md # Dataview dashboard (Obsidian) ├── analytics.md # Charts View analytics (Obsidian) ├── flashcards.md # Spaced repetition cards ├── summaries/ # One page per source document ├── concepts/ # Concept and framework pages ├── entities/ # People, tools, organizations, etc. ├── syntheses/ # Cross-cutting analyses and comparisons ├── journal/ # Research/session journal entries │ └── template.md # Journal entry template └── presentations/ # Marp slide decks ``` ## Enhancements This template includes several extras beyond the core wiki pattern: ### Dataview Dashboard (`wiki/dashboard.md`) Live queries that surface low-confidence pages, recent updates, concepts by tag, and pages with the most sources. Requires the [Dataview](https://github.com/blacksmithgu/obsidian-dataview) Obsidian plugin. ### Charts View Analytics (`wiki/analytics.md`) Visual analytics with pie charts, bar charts, and word clouds. Requires the [Charts View](https://github.com/caronchen/obsidian-chartsview-plugin) Obsidian plugin. ### Mermaid Diagrams Use Mermaid code blocks in any wiki page to create flowcharts, sequence diagrams, or concept maps. Native support in Obsidian and GitHub. ### Marp Slides (`wiki/presentations/`) Create slide decks from markdown using [Marp](https://marp.app/). Drop presentation files in this directory. ### Research Journal (`wiki/journal/`) Track your research sessions, experiments, or applied work with the included template. The LLM can reference journal entries when answering queries. ### Spaced Repetition (`wiki/flashcards.md`) Flashcards in the format used by the [Spaced Repetition](https://github.com/st3v3nmw/obsidian-spaced-repetition) Obsidian plugin. Ask the LLM to generate flashcards from any wiki page. ### MCP Server This repo works with Claude Code's MCP server capabilities. Point an MCP-compatible client at this repo and the LLM can read/write the wiki programmatically. ## Customizing for Your Domain The schema in `CLAUDE.md` is domain-agnostic. To adapt it: 1. **Purpose** — Describe your knowledge domain in one paragraph 2. **Tagging taxonomy** — Replace placeholder categories with your own (e.g., for a cooking KB: `cuisine`, `technique`, `ingredient`, `equipment`) 3. **Confidence levels** — Adjust the descriptions to match your domain's evidence standards 4. **Entity types** — Update the entity page description to match what entities mean in your domain (people, tools, companies, etc.) 5. **Journal template** — Customize `wiki/journal/template.md` for your workflow Everything else — page format, linking conventions, workflows, rules — is universal and works across domains. ## Example Domains This template works for any knowledge-intensive topic: - **Research notes** — papers, experiments, methodologies - **Book analysis** — themes, characters, author techniques - **Competitive analysis** — companies, products, market trends - **Course notes** — lectures, readings, key concepts - **Personal development** — frameworks, habits, book summaries - **Technical documentation** — APIs, architectures, design patterns - **Hobby deep-dives** — any subject you want to master ## License MIT # Machine Payments Protocol (MPP) Knowledge Base An LLM-maintained knowledge base on the **Machine Payments Protocol (MPP)** (mpp.dev, tempoxyz/mpp-specs) — an open standard for machine-to-machine payments co-authored by **Tempo and Stripe**, standardizing HTTP 402 via a 'Payment' HTTP auth scheme so any client can pay inside one HTTP request. Payment-method agnostic. Verified against the spec repo snapshot 2026-08-10 (early IETF-style draft-00). ## Concepts - [[concepts/mpp-overview|MPP Overview]] - [[concepts/payment-http-auth-scheme|The Payment HTTP Authentication Scheme]] - [[concepts/payment-intents|Payment Intents (Charge and Subscription)]] - [[concepts/payment-discovery|Payment Discovery Extension]] - [[concepts/mcp-transport|MCP / JSON-RPC Transport Extension]] - [[concepts/using-mpp|Using MPP (Rust SDK Integration)]] - [[concepts/extending-mpp|Extending MPP (Spec Authoring)]] - [[concepts/ecosystem|MPP Ecosystem and Registry]] ## Payment Methods - [[entities/methods-catalog|MPP Methods Catalog]] — start here - [[entities/method-card|Method: Card]] - [[entities/method-evm|Method: EVM]] - [[entities/method-hedera|Method: Hedera]] - [[entities/method-lightning|Method: Lightning]] - [[entities/method-near-intents|Method: NEAR Intents]] - [[entities/method-solana|Method: Solana]] - [[entities/method-stellar|Method: Stellar]] - [[entities/method-stripe|Method: Stripe]] - [[entities/method-tempo|Method: Tempo]] - [[entities/method-usdc|Method: USDC]] --- title: "MPP Ecosystem and Registry" type: concept tags: [ecosystem, sdk, methods, crypto, fiat, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-readme-md-3.md"] confidence: medium mpp_snapshot: "2026-08-10" --- ## Definition The MPP ecosystem is the broader set of third-party and official software — SDKs, payment-method plugins, framework integrations, infrastructure, CLIs, middleware, and live services — built around the Machine Payments Protocol, beyond the core spec repository (`mpp-specs`) and the official Rust SDK (`mpp-rs`). It is characterized here through `awesome-mpp` (`github.com/mbeato/awesome-mpp`), a community-maintained "awesome list" that self-describes as "the MPP registry — 100+ Machine Payments Protocol tools, SDKs, services, and payment methods across 15+ chains," billing itself as "the definitive directory for Stripe + Tempo agent payments." It is explicitly a **community registry** (maintained by a third party, `mbeato`, not by Tempo or Stripe directly), separate from the official `mpp` repository that hosts mpp.dev's own documentation and service directory. ## How It Works `awesome-mpp` organizes the ecosystem into ten top-level categories: Protocol and Specs, SDKs, Payment Methods, Framework Integrations, Infrastructure and Proxies, Agent Tools and CLIs, Middleware and Extensions, Services, Community Projects, and Tempo Blockchain, plus a closing Resources section. Community Projects is itself subdivided into Agent Frameworks, MCP Bridges, Applications, and Demos and Examples. Contributions are accepted via a `CONTRIBUTING.md` process, consistent with the standard "awesome list" convention (curated, PR-driven, community-submitted). ### Category landscape (not exhaustive — see the raw README for the full entry list) - **Protocol and Specs**: points back to `mpp-specs` (the official RFC-style spec repo), `mpp` (the protocol docs site and service registry), and the IETF Internet-Draft (`draft-ryan-httpauth-payment`, co-authored by Brendan Ryan at Tempo and Jeff Weinstein at Stripe). - **SDKs**: split into *Official* (`mppx` for TypeScript with Hono/Express/Next.js middleware and reverse-proxy support, `pympp` for Python, `mpp-rs` for Rust, `tempo-go`/`tempo-ts` for Tempo-specific tooling) and *Community* (a Ruby port, a community Go SDK, a FastAPI middleware, an Elixir implementation, a .NET SDK, and a Dart SDK) — i.e. the official language coverage (TS/Python/Rust/Go/Ruby, matching the mpp-specs README's SDK list) is supplemented by community reimplementations in additional ecosystems (.NET, Elixir, Dart). - **Payment Methods**: confirms the protocol's payment-method-agnostic design in practice — plugins exist for Solana (six separate listed projects, including an official Solana Foundation SDK), Lightning (three listed projects, including Spark- and LND/NWC-based ones), and a long tail of "Other Chains" covering Sui, Stellar, XRP Ledger, Abstract, Movement, TON, Algorand, Avalanche, MultiversX, MegaETH, SKALE, Zcash, Monad, Canton, and cross-chain routers (e.g. via Squid Router) — this is the concrete evidence behind the "15+ chains" claim in the README's own footnote/tagline. - **Framework Integrations**: built-in middleware for Hono, Express, Next.js, Elysia, Bun.serve, and Deno.serve ships inside `mppx` itself; community integrations extend this to e.g. Next.js App Router combined auth (MPP + x402 + API-key) and AWS infrastructure glue. - **Infrastructure and Proxies**: standalone reverse proxies (`mppx-proxy`), a Cloudflare Workers proxy maintained by the Tempo team itself (`mpp-proxy-cf`), a transaction explorer/service-discovery site (`mppscan.com`), and paid-infrastructure examples like an MPP-powered VPS host and a GitHub REST API proxy gated by MPP payments. - **Agent Tools and CLIs**: CLI wallets and frameworks for agents/humans (`incur`/`incur-rs`), an official Tempo "agent skill pack," debugging tools (`MPP-Inspector`), and a cluster of dual-protocol tools that bridge MPP with the competing/complementary `x402` protocol (e.g. `x402-proxy`, `402Router`, `APIbase`) — signaling that in practice, agent-payment tooling in this ecosystem often supports MPP and x402 side by side rather than exclusively one or the other. - **Middleware and Extensions**: rate limiting, token-gating, tax computation, trust/reputation layers, KYC-style "Know Your Agent" screening, spend-verification/budget-cap tooling, and — again — a large cluster of x402-adjacent projects (Coinbase's own `x402` repo is listed here as a related/complementary protocol implementation, not an MPP component). - **Services**: split into *First-Party* (services with built-in MPP support, e.g. pay-per-call API bundles, pay-per-request image generation, voice/video AI, browser automation, C2PA content-provenance verification, code execution sandboxes, GPU compute) and *Proxied via Tempo* (third-party APIs made payable through Tempo's `mpp.tempo.xyz` proxy without native MPP support — spanning AI/ML providers like Anthropic, OpenAI, Google Gemini, and Mistral; data/search providers like Exa, Firecrawl, and Brave Search; developer tools like Deepgram and Mapbox; and business, travel/weather, and generic "Abstract APIs" categories). - **Community Projects**: the largest and most heterogeneous category — agent frameworks and agent-to-agent marketplaces, MCP bridges that turn MCP server tools into paid endpoints (e.g. `mpp-mcp`, `mpp-bundler` as a Claude Code plugin for scaffolding MPP billing, `402index-mcp-server` for discovery across "15,000+ paid API endpoints"), and a long tail of applications and hackathon demos (DoorDash/Shopify ordering agents, NBA micro-betting, voice-as-a-service, agent-to-agent settlement engines and even Solidity contracts for it). - **Tempo Blockchain**: the underlying chain infrastructure that Tempo-flavored MPP methods settle on — the chain itself, a frontend apps monorepo, a Foundry fork, Solidity standard libraries, and a Ledger hardware-wallet plugin. - **Resources**: documentation (mpp.dev, docs.tempo.xyz) and articles (Stripe's own MPP announcement blog post, Tempo's mainnet-launch post introducing MPP, and Stripe's broader "Agentic Commerce Solutions" post) situating MPP within Stripe's and Tempo's larger agentic-commerce strategy. ## Key Parameters - **Scale claim**: "100+" tools/SDKs/services and "15+ chains," per the README's title tagline and its own self-listing entry. - **Launch context** (README footnote): MPP is described as launched **March 2026**, an open HTTP payment standard created by Stripe and Tempo Labs, using HTTP 402 with an extensible challenge-credential-receipt flow; payment-method agnostic (stablecoins, credit cards, Lightning, 15+ chains); supports one-time charges, pre-authorized-spending sessions, and streaming. - **Official vs. community distinction**: the SDKs and Payment Methods sections both explicitly separate "Official" (Tempo/Stripe/partner-maintained, e.g. Solana Foundation's own SDK) from "Community" (independently authored, third-party) entries — a useful signal for trust/maintenance-risk when picking a dependency from the list. - **Cross-protocol overlap**: a large fraction of "Middleware and Extensions" and "Agent Tools and CLIs" entries are dual- or multi-protocol (MPP + x402, or MPP + x402 + L402 + other agent-payment schemes like Google AP2, Visa TAP, Mastercard Agent Pay), reflecting that x402 (Coinbase's competing/adjacent HTTP-402 payment protocol) is the most commonly paired protocol in this ecosystem, not a one-off. ## When To Use - Consult `awesome-mpp` when looking for a payment-method plugin for a chain not covered by the official `mpp-rs`/`mppx` SDKs (e.g. Solana, Stellar, Lightning, or one of the long-tail chains) rather than building one from scratch. - Consult it when choosing infrastructure to gate an existing API/service with MPP (proxies, framework middleware) without writing custom 402-handling code. - Consult it for prior art before building new agent-payment tooling (CLIs, MCP bridges, trust/reputation layers) — the "Community Projects" and "MCP Bridges" subsections in particular show many teams have already built overlapping pieces. - Treat entries as a discovery starting point, not a certification — see Risks & Pitfalls below. ## Risks & Pitfalls - This is a **community-maintained registry**, not an official Tempo/Stripe directory — inclusion in `awesome-mpp` does not imply endorsement, security review, or maintenance guarantees by the protocol's authors. The official service directory lives in the separate `mpp` repository / mpp.dev, referenced but not duplicated here. - Confidence for this material is **medium**: it is grounded in a single source (the `awesome-mpp` README itself), which is inherently a self-reported, PR-driven listing — entry descriptions are one-line self-summaries from each linked project, not independently verified by this wiki. - Many "Community" and third-party entries are hackathon-scale or early-stage projects (the README's own Demos/Examples and hackathon-tagged entries make this explicit); do not treat listing density in a category as a signal of production readiness. - The ecosystem heavily overlaps with the separate **x402** protocol (Coinbase-originated) — several tools listed under MPP categories are actually dual-protocol or x402-primary with MPP as a secondary integration. When evaluating a tool from this list, check which protocol(s) it actually implements natively versus which it merely proxies or bridges to. - "Proxied via Tempo" services (e.g. Anthropic, OpenAI, Exa) are not native MPP integrations — they are made payable through Tempo's own `mpp.tempo.xyz` proxy layer, which is a distinct trust and reliability boundary from a service that implements the `Payment` scheme itself per [[concepts/payment-http-auth-scheme]]. ## Related Concepts - [[concepts/mpp-overview]] — the protocol this ecosystem builds on top of, including the official SDK list this registry supplements - [[concepts/using-mpp]] — the official Rust SDK (`mpp-rs`) covered in depth elsewhere; this page covers everything around it in other languages and layers - [[concepts/payment-discovery]] — the protocol-level discovery mechanism that registry/catalog tools like `mppscan.com` and the catalog-client pattern build on - [[concepts/extending-mpp]] — how a new entry in this ecosystem (e.g. a new chain's payment-method plugin) would formally register itself as a spec ## Sources - raw/github_doc-readme-md-3.md (`mbeato/awesome-mpp` README: full category listing, SDK official/community split, payment-method chain coverage, services split, footnote description of MPP's launch and design) --- title: "Extending MPP (Spec Authoring)" type: concept tags: [core-spec, methods, spec-author, foundational] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-style-md.md", "raw/github_doc-examples-readme-md.md", "raw/github_doc-examples-method-template-md.md", "raw/github_doc-examples-extension-template-md.md", "raw/github_doc-examples-intent-template-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition Extending MPP means adding new capability to the protocol at one of its two designed extension points — a new **payment method** (support for a network like a new chain or processor) or a new **extension** (an optional protocol addition like discovery or identity) — or, more rarely, proposing a new **intent** (a new abstract payment pattern alongside charge and subscription). The `mpp-specs` repository (`tempoxyz/mpp-specs`) formalizes this as IETF-style Internet-Draft authoring: each extension point has a document template (`examples/method-template.md`, `examples/extension-template.md`, `examples/intent-template.md`) and the whole repo follows a `STYLE.md` guide that fixes both the protocol's design principles and its RFC writing conventions. ## How It Works ### The three extension points Per `examples/README.md` ("Specification Templates"), the ecosystem has three templates, each tied to a different IETF track: | Template | Track | Use When | |----------|-------|----------| | `intent-template.md` | Standards Track | Defining a new payment intent | | `method-template.md` | Informational | Adding support for a payment network | | `extension-template.md` | Informational | Adding optional protocol extensions | Naming conventions for the resulting drafts: | Type | Pattern | Example | |------|---------|---------| | Core | `draft-httpauth-payment-XX` | `draft-httpauth-payment-00` | | Intent | `draft-payment-intent-{name}-XX` | `draft-payment-intent-charge-00` | | Method | `draft-{network}-payment-method-XX` | `draft-tempo-payment-method-00` | | Extension | `draft-payment-{feature}-XX` | `draft-payment-discovery-00` | **Methods** (Informational track) define a concrete implementation of the protocol for one payment network. `method-template.md` requires: a method identifier (registered lowercase string, e.g. `{network}`), a table of which intents it supports (charge REQUIRED; authorize and subscription OPTIONAL), per-intent request schema and credential payload definitions, a verification procedure, a settlement procedure (timing, finality, failure handling), security considerations, and an IANA "Payment Method Registration" entry. The template's own payment-flow diagram frames the method spec as filling in step (3), "[Method-specific payment process]", inside the generic challenge → pay → credential → verify → receipt exchange — i.e. a method spec is a plugin into the core scheme, per Section 9.1 of the core httpauth draft. **Extensions** (Informational track) add optional capability without being required for baseline interop. `extension-template.md` requires explicitly framing the extension as OPTIONAL — "Servers MAY implement this extension... Clients MUST NOT require this extension to function" — plus a Scope subsection listing what the extension DOES and explicitly DOES NOT do, an Architecture diagram showing how it layers onto the core protocol, a Specification section broken into components (each with request/response/example subsections as applicable), security considerations (including a dedicated Privacy Considerations subsection where relevant), and IANA considerations if it registers new identifiers. **Intents** (Standards Track — the most demanding track, since intents are core vocabulary) define a new abstract payment pattern. `intent-template.md` requires: a formal semantic definition and a properties table (Intent Identifier, Payment Timing — immediate/deferred/recurring, Idempotency — single-use/reusable, Reversibility — method-dependent/revocable/final), a "Relationship to Payment Methods" table sketching how at least two example methods would implement it, a request schema (required/optional fields), credential requirements (payload fields, proof types, reusability/validity), a verification and settlement description, security considerations, and an IANA "Payment Intent Registration" entry in the "HTTP Payment Intents" registry established by the core draft. All three templates share the same skeleton for boilerplate: Abstract, Status of This Memo, Copyright Notice, Table of Contents, Introduction, Requirements Language (RFC 2119 boilerplate), a technical body specific to the extension point, Security Considerations, IANA Considerations, References (Normative/Informative), and Authors' Addresses. This mirrors the two structures `examples/README.md` lays out for "Standards Track (Core, Intents)" vs. "Informational (Methods, Extensions)" — the Informational track drops the "Requirements Language" and "Terminology" sections from REQUIRED to omittable/optional, and IANA Considerations is conditional ("if registering identifiers") rather than always required. ### IETF-draft authoring conventions (STYLE.md) STYLE.md sets five design principles every new spec (method, extension, or intent) must respect: 1. **Payment-Method Agnostic** — the core makes no assumptions about how payment works; method-specific detail belongs only in the Methods layer. Style example given: write "The credential field contains method-specific authorization data", not "...a signed transaction". 2. **Layered Architecture** — Core (rarely changes) → Intents (occasionally extended) → Methods (frequently added) → Extensions (as needed). New specs should target the right layer rather than pushing complexity upward into Core. 3. **Minimal Core** — the core spec holds only what's necessary for interoperability; complexity is pushed to method specs. 4. **Explicit Over Implicit** — servers must advertise payment requirements explicitly; clients must consent explicitly. 5. **Fail Closed** — invalid credentials, expired challenges, and verification failures all result in `402`, never a silent pass-through. Writing-convention rules that apply to every new draft: - **IETF conformance**: follow the standard IETF format and style guide (authors.ietf.org). - **RFC 2119 keywords** used precisely: MUST (absolute requirement), MUST NOT (absolute prohibition), SHOULD / SHOULD NOT (recommended/discouraged, with room for exceptions), MAY (truly optional). - **Structure**: Abstract → Introduction → Requirements → Terminology → technical body → Security (never empty) → IANA → References. - **Terminology consistency**: define terms on first use; the canonical vocabulary is Challenge (a `WWW-Authenticate` header with scheme "Payment"), Credential (an `Authorization` header with scheme "Payment"), Intent (what kind of payment), Method (how payment works), Receipt (server acknowledgment of successful payment). - **Examples**: include one for every non-trivial concept, using realistic but obviously fake values, e.g.: ```http HTTP/1.1 402 Payment Required WWW-Authenticate: Payment id="pay_abc123", method="tempo", intent="charge", request="eyJ..." ``` - **Cross-references**: prefer stable labels/anchors over hardcoded section numbers (e.g. `{{payment-receipt-header}}`); for external drafts prefer section-agnostic wording like "defined in `{{I-D.httpauth-payment}}`" over "Section X.Y of...". - **Security Considerations must never be empty**: address, at minimum, authentication/authorization boundaries, replay protection/idempotency, information disclosure, and denial-of-service vectors. - **Formatting**: JSON uses 2-space indentation and no trailing commas; markdown source lines should stay under 72 characters for proper RFC rendering. - **File organization**: specs live under `specs/{core,intents,methods,extensions}/`, and cross-references should flow downward only (core → intents → methods), never upward. ### Versioning conventions for new specs STYLE.md fixes a two-layer versioning strategy that any new method/intent spec must follow: | Layer | Versioning | Breaking Change | |-------|------------|-----------------| | Core | None (stable scheme name `Payment`) | New scheme name (e.g. `Payment2`) | | Methods | Optional `methodDetails.version` field (absent = implicitly v1) | Add or increment `version` | | Intents | None (stable intent identifier) | New identifier (e.g. `charge-v2`) | The universal compatibility rule underlying all of this: "Implementations MUST ignore unknown fields in challenges, credentials, request objects, and receipts." A new method spec should prefer adding optional fields with defined defaults (compatible, same version) over introducing a `version` bump; a `version` bump (or an entirely new method identifier like `tempo-v2`) is reserved for genuinely breaking changes such as removing a required field or changing semantics. ## Key Parameters - **`category` frontmatter values**: `std` (Standards Track — core spec, intents), `info` (Informational — methods, extensions), `exp` (Experimental — early-stage ideas). - **Frontmatter fields common to all templates**: `title`, `abbrev`, `docname` (versioned document name, e.g. `draft-{network}-payment-method-00`), `version` (e.g. `00`), `category`, `ipr` (IPR declaration, e.g. `noModificationTrust200902`), `submissiontype: IETF`, `consensus: true`, and an `author` list (`name`, `ins`, `email`, `org`). - **Method identifier constraint**: registered identifiers are case-sensitive and MUST be lowercase (per `method-template.md` Section 4). - **Intent support table** (method spec): `charge` REQUIRED; `authorize` and `subscription` OPTIONAL — a method spec may omit unsupported intent sections entirely. - **`methodDetails.version`**: absence implies version 1; add the field (starting at `2`) only for breaking changes to a method's request/payload schema. ## When To Use - **Adding a new payment network/rail** (e.g. a chain or processor not yet covered by an existing method entity page) — author a method spec from `method-template.md`, at Informational track, defining at minimum the `charge` intent's request/credential schemas and verification/settlement procedures. - **Adding optional protocol capability** that servers/clients can adopt without breaking baseline interop (e.g. richer discovery metadata, identity attestation) — author an extension spec from `extension-template.md`, being explicit about what MUST NOT be required of clients that don't implement it. - **Proposing a genuinely new payment pattern** not expressible as a variant of charge/subscription (e.g. a new settlement-timing shape) — author an intent spec from `intent-template.md` at Standards Track, including a "Relationship to Payment Methods" table showing at least two methods implementing it, since intents are core, widely-relied-upon vocabulary and warrant the heavier track. - **Evolving an existing method's wire format** — prefer additive, optional fields under the existing `methodDetails` shape; only introduce `version: 2` (or a new identifier) when the change is incompatible with existing implementations, per STYLE.md's versioning rules. - **Any new spec authoring in this repo** — apply STYLE.md's five design principles and RFC 2119 conventions regardless of which template is used, since they're stated as blanket rules for the whole `mpp-specs` repo, not just the core document. ## Risks & Pitfalls - Writing method-specific mechanics (e.g. "the credential field contains a signed transaction") directly into a shared/Intents-level document violates the Payment-Method Agnostic principle — that detail belongs only in the Methods layer, per STYLE.md's own worked example of the anti-pattern. - Leaving Security Considerations sparse or boilerplate is explicitly disallowed — STYLE.md says this section must never be empty and lists four required topics (auth boundaries, replay/idempotency, information disclosure, DoS) that every new spec should address, not just mention. - Hardcoding `Section X.Y of {{I-D...}}`-style references instead of stable anchors/section-agnostic wording makes a spec brittle to renumbering in future drafts — STYLE.md flags this as something to avoid "unless there is no practical alternative." - Confusing which track a spec needs: an Intent is Standards Track (heavier boilerplate: Requirements Language and Terminology are REQUIRED, not just RECOMMENDED) while a Method or Extension is Informational — using the wrong template's required-section list produces a spec inconsistent with `mpp-specs`' own structural conventions. - Skipping the "ignore unknown fields" compatibility rule when designing a method's request/credential schema removes the protocol's main forward-compatibility mechanism, forcing unnecessary version bumps down the line. - The templates are explicitly fill-in-the-blank documents (`[Describe the payment network/infrastructure this method uses]`, `{network}`, `{feature}`, `{name}` placeholders) — leaving template placeholder text unfilled in a submitted draft is the most literal way to fail STYLE.md's IETF-conformance requirement. ## Related Concepts - [[concepts/payment-http-auth-scheme]] — the core `Payment` HTTP authentication scheme that every method, intent, and extension spec extends or plugs into (`I-D.httpauth-payment` in all three templates' references) - [[concepts/mpp-overview]] — the layered Core/Intents/Methods/Extensions architecture that motivates why there are three distinct templates rather than one - [[concepts/payment-intents]] — the existing charge/subscription intents that any new intent spec sits alongside - [[concepts/payment-discovery]] — a concrete example of an Informational-track extension spec (discovery) built on this same extension-template shape - [[concepts/using-mpp]] — the implementation side; a new method spec written this way is what an SDK like `mpp-rs` would eventually implement in code ## Sources - raw/github_doc-style-md.md (STYLE.md: design principles, RFC 2119 conventions, structure, terminology, cross-references, security considerations, formatting, file organization, versioning strategy) - raw/github_doc-examples-readme-md.md (mpp-specs `examples/README.md`: template table, required-sections-by-track tables, frontmatter fields, category values, naming conventions) - raw/github_doc-examples-method-template-md.md (`examples/method-template.md`: full method spec skeleton, intent-support table, verification/settlement sections, IANA registration) - raw/github_doc-examples-extension-template-md.md (`examples/extension-template.md`: OPTIONAL framing, Scope DOES/DOES NOT, architecture/capabilities sections) - raw/github_doc-examples-intent-template-md.md (`examples/intent-template.md`: intent semantics/properties table, relationship-to-methods table, request schema, credential requirements) --- title: "MCP / JSON-RPC Transport Extension" type: concept tags: [transport, extensions, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-extensions-transports-draft-payment-transport-mcp-00-m.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition `draft-payment-transport-mcp-00` defines how the [[concepts/payment-http-auth-scheme|"Payment" HTTP Authentication Scheme]] operates over JSON-RPC 2.0 message exchanges, independent of the underlying transport — applicable to WebSocket, plain HTTP, stdio, and protocol frameworks built on JSON-RPC such as the **Model Context Protocol (MCP)**. It re-expresses the same challenge/credential/receipt model from the core HTTP spec as native JSON-RPC error objects and `_meta` metadata fields (rather than HTTP headers with base64url-encoded values), and defines MCP-specific conventions for paying to invoke tools (`tools/call`), read resources (`resources/read`), and fetch prompts (`prompts/get`). ## How It Works ### Design goals Native JSON (no base64url encoding — JSON-RPC's own structure carries the data), transport independence (defined at the JSON-RPC layer, works over any carrier), minimal overhead (`_meta` only added when payment is actually needed), and support for multiple simultaneous payment options in one challenge. ### Protocol overview ``` Client Server │ (1) JSON-RPC Request {method: "...", params: {...}} │ ├─────────────────────────────────────────────────────>│ │ (2) JSON-RPC Error {code: -32042, data: {challenges: [...]}} │ │<─────────────────────────────────────────────────────┤ │ (3) Client fulfills challenge │ │ (4) JSON-RPC Request {method: "...", _meta: {credential: {...}}} │ ├─────────────────────────────────────────────────────>│ │ (5) JSON-RPC Result {result: {...}, _meta: {receipt: {...}}} │ │<─────────────────────────────────────────────────────┤ ``` ### Capability advertisement Servers/clients SHOULD advertise supported payment methods/intents before a payment flow starts. Capability object shape: `methods` (REQUIRED) — object mapping payment method identifiers to a config object containing an `intents` array of supported intent types, e.g. `{"methods": {"tempo": {"intents": ["charge"]}, "stripe": {"intents": ["charge"]}}}`. For **MCP specifically**, servers SHOULD advertise this in `InitializeResult` under `capabilities.experimental.payment`: ```json { "protocolVersion": "2025-11-25", "capabilities": { "tools": {}, "resources": {}, "experimental": { "payment": { "methods": { "tempo": {"intents": ["charge"]}, "stripe": {"intents": ["charge"]} } } } }, "serverInfo": { "name": "example-server", "version": "1.0.0" } } ``` Clients SHOULD symmetrically advertise in `InitializeRequest` under the same `capabilities.experimental.payment.methods` shape. Servers MAY use client-advertised capabilities to filter which offers to present. Capability advertisement is not itself trustworthy for security: clients MUST NOT rely solely on it and SHOULD validate the actual challenge structure before paying. ### Payment challenge (`error.code -32042`) When a JSON-RPC method requires payment, the server MUST respond with a JSON-RPC error using **code `-32042`** ("Payment Required"), inside the JSON-RPC implementation-defined server-error range (-32000 to -32099): ```json { "jsonrpc": "2.0", "id": 1, "error": { "code": -32042, "message": "Payment Required", "data": { "httpStatus": 402, "challenges": [{ "id": "qB3wErTyU7iOpAsD9fGhJk", "realm": "api.example.com", "method": "tempo", "intent": "charge", "request": {"amount": "1000", "currency": "usd", "recipient": "0x742d35Cc6634C0532925a3b844Bc9e7595f8fE00"}, "expires": "2025-01-15T12:05:00Z", "description": "API call fee" }], "problem": {"type": "https://paymentauth.org/problems/payment-required", "title": "Payment Required", "status": 402, "detail": "Payment required for access."} } } } ``` `error.data.httpStatus` SHOULD be `402`, for transports that bridge to HTTP (e.g. MCP Streamable HTTP). `error.data` MUST contain `challenges` (REQUIRED, array of one or more challenge objects) and MAY contain `problem` (RFC 9457 Problem Details). **Challenge object fields** — note `request` here is a **native JSON object, not base64url-encoded** (unlike the core HTTP spec): Required: `id` (server MUST cryptographically bind it to at minimum `realm`, `method`, `intent`, `request` canonical hash, and `expires`; clients MUST echo unchanged), `realm`, `method`, `intent`, `request` (both parties canonicalize via JCS (RFC 8785) and hash the canonicalized bytes for binding/verification). Optional: `expires` (RFC 3339; if absent, server defines validity), `description`. Multiple challenges in one array are **alternatives** — clients MUST select exactly one and send exactly one credential; servers MUST NOT require multiple simultaneous payments this way. ### Payment credential — `_meta` placement Two placement strategies: - **Root-level `_meta`** (generic JSON-RPC): placed at the root of the message object — works regardless of whether `params` is an object or array. Example: `{"jsonrpc":"2.0","id":2,"method":"eth_getBlockByNumber","params":["latest",false],"_meta":{"org.paymentauth/credential": {...}}}` - **Nested `_meta`** (MCP): placed inside `params` for requests / `result` for responses, since MCP's `params` is always an object. Example: `{"method":"tools/call","params":{"name":"expensive-api","_meta":{"org.paymentauth/credential": {...}}}}` Servers MUST check both locations and MUST NOT require clients to use a specific one; servers MUST ignore `org.paymentauth/credential` on methods that don't require payment. **Metadata key**: `org.paymentauth/credential` (reverse-DNS naming to avoid collisions). The credential object MUST contain `challenge` (the complete challenge object from the `-32042` response, echoed unchanged) and `payload` (method-specific proof, JSON object). It MAY contain `source` (e.g. a DID or address). ### Payment receipt — `org.paymentauth/receipt` After successful verification/settlement, servers MUST include a receipt via `_meta` key **`org.paymentauth/receipt`**, following the same root-level-vs-nested-in-`result` placement rule. Required fields: `status` (MUST be `"success"`), `method`, `timestamp` (RFC 3339), `challengeId` (the fulfilled challenge's `id`). Optional: `reference` (method-specific settlement reference, e.g. tx hash or invoice id). Servers MUST return the receipt on every successful paid response and MUST NOT return one for unpaid requests. ### MCP-covered operations Payment MAY gate `tools/call` (tool invocations), `resources/read` (resource reads), and `prompts/get` (prompt retrieval) — the spec gives a worked challenge example for each, all using the same `-32042` challenge shape shown above with method-appropriate `realm`/`amount`. ### Error code mapping | Condition | Code | Description | |-----------|------|-------------| | Payment required | `-32042` | Payment challenge in `error.data` | | Payment verification failed | `-32043` | Fresh challenge + failure reason | | Malformed credential | `-32602` | Invalid params (bad JSON structure) | | Internal payment error | `-32603` | Payment processor failure | `-32700` (Parse error) applies only when the entire JSON-RPC message is unparseable — not for malformed `_meta` subfields (use `-32602` for those). On verification failure (`-32043`), the server MAY reissue the same challenge if still valid or issue a fresh one, and adds a `failure` object with optional `reason` (machine-readable) and `detail` (human-readable). ### Notifications JSON-RPC notifications (no `id`, expect no response) **cannot support payment flows** — servers MUST NOT process payment-gated operations invoked as notifications, and SHOULD silently drop them (MAY log for debugging). Clients SHOULD NOT invoke payment-gated operations as notifications; operations that might require payment SHOULD always include a request `id`. ## Key Parameters - **JSON-RPC error codes**: `-32042` (Payment Required), `-32043` (Payment Verification Failed) — both in the -32000..-32099 server-error range; implementations MUST use these exact codes for interoperability. - **`_meta` keys**: `org.paymentauth/credential` (client → server), `org.paymentauth/receipt` (server → client) — reverse-DNS namespaced. - **`_meta` placement**: root-level for generic JSON-RPC; nested inside `params` (request) / `result` (response) for MCP. - **Challenge object fields**: `id`, `realm`, `method`, `intent`, `request` (native JSON, JCS-canonicalized for hashing — not base64url as in the HTTP core spec), `expires` (optional), `description` (optional). - **Credential object fields**: `challenge` (required, echoed), `payload` (required), `source` (optional). - **Receipt object fields**: `status`, `method`, `timestamp`, `challengeId` (all required), `reference` (optional). - **MCP capability path**: `capabilities.experimental.payment.methods..intents[]` in `InitializeResult`/`InitializeRequest`. - **MCP protocol version referenced**: `2025-11-25`. ## When To Use Use this transport mapping whenever payment needs to gate an MCP tool call, resource read, or prompt fetch — i.e., whenever an MCP server wants to charge for a paid tool, and the underlying wire format is JSON-RPC rather than a plain HTTP request/response the core [[concepts/payment-http-auth-scheme]] was written for. It's also the general-purpose way to carry MPP payment semantics over any JSON-RPC transport (WebSocket, stdio, HTTP-as-JSON-RPC), not just MCP — the worked example over Ethereum JSON-RPC-over-WebSocket (`eth_getBlockByNumber`) demonstrates the non-MCP case. ## Risks & Pitfalls - **Challenge binding**: servers MUST cryptographically bind challenge `id`s to at minimum `realm`, `method`, `intent`, the JCS-canonicalized `request` hash, and `expires` — and SHOULD further bind to the specific operation (tool name, resource URI) so a challenge issued for one operation can't be reused for another. - **Replay protection**: servers MUST reject unknown, expired, or previously-used challenge IDs; concurrent requests racing on the same challenge MUST be resolved so only one succeeds (atomic check-and-mark). - **Transport security**: network transports (HTTP, WebSocket) MUST use TLS 1.2+ (1.3 recommended); stdio transport security depends entirely on OS-level process isolation instead. - **Credential confidentiality**: clients MUST NOT log or persist credentials beyond immediate use; servers MUST NOT log full credential payloads, including in crash dumps, tracing, or analytics. - **Metadata stripping**: on-path attackers/intermediaries could strip `org.paymentauth/credential` (causing repeated challenges) or `org.paymentauth/receipt` (breaking auditability) — TLS protects network transports; stdio relies on process isolation instead. - **Confused deputy**: misleading method names or realms could trick a client into paying for an unintended operation — client implementations SHOULD display `realm`/`amount`/`currency`/`recipient` before fulfilling, allow per-realm payment policy, and validate challenge parameters match the requested operation. - **DoS**: attackers may trigger many challenges to exhaust server or payment-processor resources — servers SHOULD rate-limit challenge issuance, prefer stateless challenge encoding, and back off on repeated failures. - **Capability spoofing**: capability advertisement is informational only, not a security guarantee — a malicious server could claim payment capabilities it doesn't correctly implement. ## Related Concepts - [[concepts/payment-http-auth-scheme]] — the HTTP-header-based core scheme this document re-expresses as JSON-RPC error objects and `_meta` fields - [[concepts/payment-intents]] — the `charge` intent used in every worked example in this document (no `subscription`-over-MCP example is given in this source) - [[concepts/mpp-overview]] — situates the MCP/JSON-RPC transport as one of the optional Extensions layered on the core protocol - [[concepts/payment-discovery]] — a separate, OpenAPI-based pre-flight discovery mechanism; this document instead defines in-session MCP capability advertisement via `InitializeResult`/`InitializeRequest` ## Sources - raw/github_doc-specs-extensions-transports-draft-payment-transport-mcp-00-m.md (`specs/extensions/transports/draft-payment-transport-mcp-00.md` — Payment Authentication Scheme: JSON-RPC & MCP Transport) --- title: "MPP Overview" type: concept tags: [overview, core-spec, foundational, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-readme-md.md", "raw/web_community-machine-payments-protocol-mpp.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition The Machine Payments Protocol (MPP) is an open standard for machine-to-machine payments, co-authored by [[entities/method-tempo|Tempo]] (Tempo Labs) and [[entities/method-stripe|Stripe]]. It lets any client — an AI agent, an app, or a human — pay for an internet resource (an API call, a dataset, a unit of compute) inside the same HTTP request, using the native `402 Payment Required` status code, instead of requiring an account, API key, or pre-arranged billing relationship. MPP is published as an early IETF-style draft (`draft-00` documents; the core spec is tracked as `draft-ryan-httpauth-payment`), with a full rendered spec set at paymentauth.org and a marketing/docs site at mpp.dev. ## How It Works MPP standardizes a `Payment` HTTP authentication scheme (defined in [[concepts/payment-http-auth-scheme]]) built on top of HTTP's reserved-but-never-standardized `402 Payment Required` status code. The end-to-end client-server exchange is: 1. **Client** requests a protected resource: `GET /resource` 2. **Server** responds `402 Payment Required` with a `WWW-Authenticate: Payment ...` challenge describing what payment is needed (method, intent, amount, recipient, etc.) 3. **Client** fulfills the payment off-band, via whichever payment method the challenge specifies (signs a transaction, pays an invoice, completes a card payment) 4. **Client** retries the same request, this time with an `Authorization: Payment ` header containing proof of payment 5. **Server** verifies the credential and settles the payment, then returns `200 OK` with the resource and (optionally) a `Payment-Receipt` header proving delivery ```mermaid sequenceDiagram participant Client participant Server Client->>Server: GET /resource Server-->>Client: 402 Payment Required, WWW-Authenticate: Payment ... Note over Client: Client fulfills payment challenge Client->>Server: GET /resource, Authorization: Payment credential Server-->>Client: 200 OK ``` This challenge/response mechanic is the exact mechanism defined in [[concepts/payment-http-auth-scheme]]. The specification is deliberately modular, separating stable protocol mechanics from evolving payment ecosystems into four layers (per the mpp-specs README "Architecture" section): - **Core**: HTTP 402 semantics, headers, IANA registries — see [[concepts/payment-http-auth-scheme]] - **Intents**: abstract payment patterns such as charge and subscription, defining *what* kind of payment without specifying *how* — see [[concepts/payment-intents]] - **Methods**: concrete implementations for specific networks (Tempo, Stripe, ACH, and more) — each rail ships as its own plugin-style specification (see method entity pages below) - **Extensions**: optional protocol additions such as discovery and identity — see [[concepts/payment-discovery]] and [[concepts/mcp-transport]] ## Key Parameters - **Payment-method agnosticism**: the core protocol does not favor any payment network or currency. Each rail (card, EVM, Solana, Stellar, Hedera, Lightning, NEAR Intents, Stripe, Tempo, USDC) is defined by its own payment method specification that plugs into the same `Payment` challenge/credential shape, registering a lowercase method identifier and its own `request`/`payload` schemas. - **Crypto vs. fiat, side by side**: MPP treats stablecoin/on-chain rails (Tempo, EVM, Solana, Stellar, Hedera, Lightning, NEAR Intents, USDC) and processor/fiat rails (Stripe, ACH-style bank rails, credit cards) as equally first-class "methods" under the same core scheme — "any currency" (USD, EUR, BRL, USDC.e, BTC, etc.) is a stated design goal. - **Tempo + Stripe origin**: MPP is jointly authored and maintained by Tempo Labs and Stripe; the core httpauth spec's author list includes engineers from both organizations (see [[concepts/payment-http-auth-scheme]]). - **Three parties**: Developers (integrate an MPP client so their agent/app can pay), Agents (autonomously call and pay for APIs on a user's behalf), and Services (integrate an MPP server to accept payment with zero onboarding friction). - **First-class primitives**: idempotency, security, and Receipts are called out as designed-in primitives, not afterthoughts. - **Design principles** (from the mpp-specs README): extensible core (minimal protocol designed for safe extension), network-agnostic/multi-rail, currency-agnostic (no implicit advantage for any currency or asset), and durable-by-design (replay protection and security as first-class concerns, following web standards). - **Official SDKs**: TypeScript (`mppx`, the reference implementation, maintained with Wevm), Python (`pympp`), Rust (`mpp-rs`), Go (`mpp-go`), and Ruby (`mpp-rb`, maintained by Stripe). ## When To Use MPP applies wherever a service wants to charge for programmatic access without pre-provisioned accounts, and wherever a client (especially an autonomous agent) needs to pay for a resource inline rather than through a human checkout flow. Cited use cases: - **Agentic payments**: an AI agent calling LLM providers, search APIs, or image generators through MPP, paying per request without API keys or human intervention. - **API monetization**: accepting payment from any client — agent, app, or human — without requiring signups, billing accounts, or API keys. - **Micropayments**: charging sub-cent amounts per token, per query, or per request, using off-chain payment sessions with on-chain settlement. - **Machine-to-machine commerce and usage-based billing** more broadly, per the README's stated primary use cases. MPP is explicitly positioned against the alternative of fighting browser automation pipelines, visual captchas, and ever-changing checkout forms to make human-oriented payment flows work programmatically — the mpp.dev overview frames this as a structural, interface-level problem that MPP's HTTP-native challenge/credential exchange is designed to sidestep. ## Risks & Pitfalls - MPP specs are early **IETF-style `draft-00`** documents — normative behavior may still change before ratification; implementers should track the IETF draft (`draft-ryan-httpauth-payment`) and the rendered spec set at paymentauth.org for updates. - Because the protocol is payment-method agnostic, a server's actual security and finality guarantees depend entirely on which method specification is in play (see individual method entity pages) — the core scheme itself does not guarantee settlement finality. - Discovery of payment methods/prices is optional and advisory, not authoritative — see [[concepts/payment-discovery]] for why the runtime 402 challenge always wins over any pre-fetched metadata. ## Related Concepts - [[concepts/payment-http-auth-scheme]] — the core "Payment" HTTP authentication scheme that implements the challenge/credential exchange described here - [[concepts/payment-intents]] — the abstract charge/subscription patterns layered on top of the core scheme - [[concepts/payment-discovery]] — how clients find which methods/prices a server accepts before making a request - [[concepts/mcp-transport]] — how the same payment flow is carried over JSON-RPC/MCP instead of raw HTTP ## Sources - raw/github_doc-readme-md.md (mpp-specs repository README: what MPP is, architecture, design principles, related SDKs) - raw/web_community-machine-payments-protocol-mpp.md (mpp.dev overview page: problem statement, three parties, payment flow, use cases, SDKs) --- title: "Payment Discovery Extension" type: concept tags: [discovery, extensions, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-extensions-draft-payment-discovery-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition `draft-payment-discovery-00` defines an **optional** service-discovery framework layered on top of the [[concepts/payment-http-auth-scheme]]. Services publish an OpenAPI 3.x document annotated with two payment-specific extensions — `x-service-info` (service metadata) and `x-payment-info` (per-operation payment offers) — so that a client or agent can find and evaluate payment-enabled endpoints, and construct valid requests, before ever making an HTTP call. The OpenAPI document is the canonical machine-readable contract for both pricing metadata and input schemas. Discovery is explicitly advisory: the runtime `402` challenge is always authoritative for the actual payment parameters. ## How It Works ### Publishing the document A discovering service MUST publish an OpenAPI 3.x document at `GET /openapi.json`, served over HTTPS with `Content-Type: application/json`. Required top-level OpenAPI fields: `openapi` (version string, e.g. `"3.1.0"`), `info.title`, `info.version`, and `paths` (at least one path with operations). ### `x-service-info` (top-level, optional) | Field | Type | Required | Description | |-------|------|----------|-------------| | `categories` | array of strings | OPTIONAL | Free-form service categories. RECOMMENDED starting vocabulary: `communication, compute, data, developer-tools, media, search, social, storage, travel`. Lowercase, hyphenated, concise; registries SHOULD cap at 5 categories; clients SHOULD ignore unrecognized values. | | `docs` | object | OPTIONAL | `apiReference` (URI), `homepage` (URI), `llms` (URI — LLM-friendly docs per the llms.txt proposal). All URIs conform to RFC 3986. | ### `x-payment-info` (per operation, required on every payable operation) Each **Payable Operation** (one that can return 402) MUST carry `x-payment-info` describing one or more **Payment Offers** — alternative runtime challenges the operation may issue. Two equivalent forms: - **Single-offer shorthand**: an object with the offer's fields directly. - **Multi-offer form**: an object with an `offers` array of offer objects. Servers publishing new documents SHOULD use this form; clients/registries MUST accept both and MUST treat shorthand as a one-element `offers` array. **Payment Offer object:** | Field | Type | Required | Description | |-------|------|----------|-------------| | `intent` | string | REQUIRED | `"charge"` (per-request) or `"session"` (pay-as-you-go) | | `method` | string | REQUIRED | Payment method identifier (e.g. `"tempo"`, `"stripe"`) | | `amount` | string or null | REQUIRED | Cost in base currency units; `null` = dynamic/variable pricing. When non-null: ASCII-digit string, non-negative integer, no leading zeros except `"0"` itself — consistent with the `amount` field in the core spec's request object | | `currency` | string | OPTIONAL | Token contract address (blockchain methods) or ISO 4217 code (fiat) | | `description` | string | OPTIONAL | Human-readable pricing note | Note: discovery's offer `intent` enum is `["charge", "session"]` — the discovery spec does not itself list `subscription` as an offerable intent value, though the JSON Schema does not forbid other registered intent strings appearing in practice; `charge` and `session` are the two values shown throughout. When multiple offers appear, clients treat them as alternative ways to reach the same operation — pick one at runtime and fulfill its corresponding 402 challenge. Example patterns shown in the spec: same intent priced in different currencies; the same intent offered via different methods; a mix of fixed-price and dynamic (`amount: null`) offers side by side; and an operation advertising multiple methods and multiple intents (e.g. `session`/tempo and `charge`/tempo and `charge`/stripe) simultaneously. ### 402 response declaration and input schema Each payable operation MUST declare a `402` entry in its OpenAPI `responses` object (e.g. `description: "Payment Required"`), signaling that the operation may 402. Operations SHOULD also define their input schema via the standard OpenAPI `requestBody` field, so agents can construct valid calls without extra documentation; operations that omit input schemas MAY be flagged "schema-missing" by discovery clients/registries. ### Caching Servers SHOULD send `Cache-Control` headers on the discovery document; a max age of 5 minutes (`Cache-Control: max-age=300`) is RECOMMENDED for services whose capabilities change infrequently. Clients SHOULD respect these headers and refetch when capabilities may have changed. ### Relationship to the runtime 402 challenge Discovery metadata is **advisory only**. If discovery-advertised offer details (method, intent, amount, or currency) differ from the actual runtime [[concepts/payment-http-auth-scheme|402 challenge]], **the 402 challenge takes precedence**. Clients MUST NOT cache discovery data as a substitute for processing the live 402 challenge. Discovery exists to help clients/agents find and evaluate services beforehand, not to replace runtime payment negotiation. ### Registries and aggregators (informative appendix) A **registry** discovers, validates, and indexes payment-enabled services (crawling submitted domains, accepting submissions, or consuming other registries' snapshots); a valid OpenAPI document with `x-payment-info` served over HTTPS is treated as sufficient proof of domain ownership. Registries SHOULD re-crawl at least every 24 hours and SHOULD delist after 7+ consecutive crawl failures; SHOULD enforce HTTPS-only, 10-second timeouts, 64KB size limits, and rate limiting. **Aggregators** consume registry data and layer curation, enrichment (trust/uptime/volume scores), reshaping (e.g. into llms.txt), or federation across registries — the only universal contract is the OpenAPI discovery mechanism itself. ## Key Parameters - Discovery document location: `GET /openapi.json` (HTTPS, `Content-Type: application/json`) - `x-service-info.categories`, `x-service-info.docs.{apiReference,homepage,llms}` - `x-payment-info` offer fields: `intent` (`charge`|`session`), `method`, `amount` (string|null), `currency`, `description` - 402 declared in `responses."402"` - `Cache-Control: max-age=300` recommended ## When To Use Use payment discovery when you want clients or agents to be able to browse, compare, and pre-select among payment-enabled services or operations before making the first paid call — e.g., an agent shopping across multiple compute providers by price, or a registry/aggregator (à la x402scan) building a searchable catalog of payable APIs. It is entirely optional per the core protocol: a server can support MPP payments with no discovery document at all, and a client can always fall back to hitting the endpoint directly and reading the live [[concepts/payment-http-auth-scheme|402 challenge]]. ## Risks & Pitfalls - **Discovery spoofing / no cryptographic authentication**: discovery info is only as trustworthy as HTTPS transport security — it is not otherwise authenticated. Clients MUST NOT make security decisions based on discovery metadata; the 402 challenge is authoritative for all payment parameters. - **Information disclosure**: publishing `/openapi.json` reveals payment capabilities, endpoint structure, input schemas, and pricing to any unauthenticated client — operators should weigh whether that disclosure is acceptable. - **Cross-origin access**: browser-based clients may need the discovery endpoint reachable cross-origin; servers intending to support them SHOULD add CORS headers. - **Staleness**: clients that over-cache discovery data (beyond the server's `Cache-Control`) risk acting on stale pricing/offer data that the live 402 challenge will simply override — better to treat discovery purely as a planning aid. ## Related Concepts - [[concepts/payment-http-auth-scheme]] — the runtime 402 challenge/credential mechanism that discovery is always subordinate to - [[concepts/payment-intents]] — the `charge` intent (and `session`, referenced here as an offerable intent though not one of the two intent specs curated in this KB) that discovery offers describe - [[concepts/mpp-overview]] — situates Discovery as one of the optional "Extensions" in the four-layer architecture - [[concepts/mcp-transport]] — a separate mechanism (capability advertisement) for signaling payment support within an MCP/JSON-RPC session, rather than via OpenAPI ## Sources - raw/github_doc-specs-extensions-draft-payment-discovery-00-md.md (`specs/extensions/draft-payment-discovery-00.md` — Service Discovery for HTTP Payment Authentication) --- title: "The Payment HTTP Authentication Scheme" type: concept tags: [core-spec, overview, foundational, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-core-draft-httpauth-payment-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition `draft-httpauth-payment-00` defines the **"Payment" HTTP authentication scheme**, the core of MPP (see [[concepts/mpp-overview]]). It extends HTTP Authentication (RFC 9110) using the `402 Payment Required` status code, giving that long-reserved-but-never-standardized code real semantics: a resource may require a **Payment Challenge** to be fulfilled before access, and a client proves it has paid by presenting a **Payment Credential**. The scheme itself is payment-method agnostic — it defines the envelope (headers, fields, status-code behavior); concrete payment methods (see method entity pages) and payment intents ([[concepts/payment-intents]]) fill in the method- and intent-specific pieces. ## How It Works ### Request flow ``` Client Server │ (1) GET /resource │ ├─────────────────────────────────────────────────>│ │ (2) 402 Payment Required │ │ WWW-Authenticate: Payment id="..", │ │ method="..", intent="..", request=".." │ │<─────────────────────────────────────────────────┤ │ (3) Client fulfills payment challenge │ │ (signs transaction, pays invoice, etc.) │ │ (4) GET /resource │ │ Authorization: Payment │ ├─────────────────────────────────────────────────>│ │ (5) Server verifies and settles │ │ (6) 200 OK │ │ Payment-Receipt: │ │<─────────────────────────────────────────────────┤ ``` ### Status-code semantics (server MUST behavior) | Condition | Status | Response | |-----------|--------|----------| | Resource requires payment, no credential provided | 402 | Fresh challenge in `WWW-Authenticate` | | Malformed credential (invalid base64url, bad JSON) | 402 | Fresh challenge + `malformed-credential` problem | | Unknown, expired, or already-used challenge `id` | 402 | Fresh challenge + `invalid-challenge` problem | | Payment proof invalid or verification failed | 402 | Fresh challenge + `verification-failed` problem | | Payment verified, access granted | 200 | Resource + optional `Payment-Receipt` | | Payment verified, but policy denies access | 403 | No challenge (payment was valid) | The spec deliberately uses **402 for all payment-related conditions, including failed credential validation** — diverging from the traditional 401 retry pattern. The three-way split is explicit: **402** = payment barrier, **401** = authentication failure unrelated to payment, **403** = payment succeeded but policy denies access. When a resource needs both authentication and payment, servers must check authentication first (401 if it fails), and only return 402 after successful authentication, to avoid leaking payment requirements to unauthenticated clients. ### The Challenge (`WWW-Authenticate: Payment`) Uses standard RFC 9110 auth-param syntax: `Payment [ 1*SP auth-params ]`, `auth-param = token BWS "=" BWS ( token / quoted-string )`. **Required parameters:** | Parameter | Description | |-----------|-------------| | `id` | Unique challenge identifier. REQUIRED, MUST be non-empty. Servers MUST bind it to the challenge parameters (Challenge Binding, below); clients MUST echo it unchanged in the credential. | | `realm` | Protection space identifier per RFC 9110. | | `method` | Payment method identifier (lowercase ASCII, e.g. `tempo`, `stripe`, `solana`). | | `intent` | Payment intent type — a registered value in the IANA "HTTP Payment Intents" registry (see [[concepts/payment-intents]]). | | `request` | Base64url-encoded (no padding) JSON, method-specific data needed to complete payment. MUST be JCS-canonicalized (RFC 8785) before encoding, for deterministic challenge-binding hashes. | **Optional parameters:** | Parameter | Description | |-----------|-------------| | `digest` | Content digest of the request body (RFC 9530 format), for requests with a body (POST/PUT/PATCH). Clients must submit a body whose digest matches. | | `expires` | RFC 3339 timestamp after which the challenge is invalid. | | `description` | Human-readable purpose — display only, MUST NOT be relied on for verification. | | `opaque` | Base64url-encoded, JCS-canonicalized JSON object (flat string-to-string map) of server correlation data; clients MUST echo it back unmodified. | Unknown parameters MUST be ignored by clients. Example challenge: ``` WWW-Authenticate: Payment id="x7Tg2pLqR9mKvNwY3hBcZa", realm="api.example.com", method="example", intent="charge", expires="2025-01-15T12:05:00Z", request="eyJhbW91bnQiOiIxMDAwIiwiY3VycmVuY3kiOiJVU0QiLCJyZWNpcGllbnQiOiJhY2N0XzEyMyJ9" ``` ### Challenge Binding Servers SHOULD bind `id` to the challenge parameters to prevent request-integrity attacks (a client signing/submitting a different payment than the server intended); servers MUST verify credentials present an `id` matching the expected binding. The binding mechanism is implementation-defined (stateful DB lookup or stateless HMAC/AEAD). **Recommended: HMAC-SHA256 binding.** Seven fixed positional slots (required fields = string value, optional fields = empty string `""` if absent): `realm`, `method`, `intent`, `request` (JCS-serialized, base64url), `expires`, `digest`, `opaque` (JCS-serialized, base64url). Join with `|`, then: ``` input = "|".join([realm, method, intent, request_b64url, expires or "", digest or "", opaque_b64url or ""]) id = base64url(HMAC-SHA256(server_secret, input)) ``` Fixed positional (never omitted) slots avoid ambiguity between combinations of optional fields and keep future optional-slot additions from changing the HMAC of challenges that omit them. ### The Credential (`Authorization: Payment`) Syntax: `credentials = "Payment" 1*SP base64url-nopad`. The base64url-nopad value decodes to a JSON object: | Field | Type | Required | Description | |-------|------|----------|-------------| | `challenge` | object | Yes | Echoed challenge parameters (`id`, `realm`, `method`, `intent`, `request`, `description`, `opaque`, `digest`, `expires`) | | `source` | string | No | Payer identifier, RECOMMENDED as a W3C DID | | `payload` | object | Yes | Method-specific payment proof | Example decoded credential: ```json { "challenge": { "id": "x7Tg2pLqR9mKvNwY3hBcZa", "realm": "api.example.com", "method": "example", "intent": "charge", "request": "eyJhbW91bnQiOiIxMDAwIiwiY3VycmVuY3kiOiJVU0QiLCJyZWNpcGllbnQiOiJhY2N0XzEyMyJ9", "expires": "2025-01-15T12:05:00Z" }, "payload": { "proof": "0xabc123..." } } ``` ### The `Payment-Receipt` header Servers SHOULD include `Payment-Receipt` on successful responses; decoded JSON contains `status` (MUST be `"success"` — receipts are only issued on success), `method`, `timestamp` (RFC 3339), and `reference` (method-specific, e.g. tx hash or invoice id). Method specs may add fields. Servers MUST NOT return `Payment-Receipt` on error responses. ### Method and intent identifiers - `payment-method-id = 1*LOWERALPHA` — lowercase ASCII only, case-sensitive. Registered in the IANA "HTTP Payment Methods" registry (Specification Required policy). - `intent = 1*( ALPHA / DIGIT / "-" )` — registered in the IANA "HTTP Payment Intents" registry (Specification Required policy). See [[concepts/payment-intents]]. - A server supporting multiple intents MAY issue multiple `WWW-Authenticate` challenge lines in one 402 response; clients pick one. ### Client preference negotiation: `Accept-Payment` Clients MAY send `Accept-Payment` to declare which method/intent combinations they support, using the same weighted `q`-value model as other HTTP negotiation headers (omitted `q` = `q=1`; `q=0` = "do not use"): ``` Accept-Payment = #payment-range payment-range = payment-token [ weight ] payment-token = payment-method-or-wildcard "/" intent-or-wildcard ``` Example: `Accept-Payment: tempo/charge, tempo/session, stripe/charge;q=0.5, solana/charge;q=0.3` or wildcarded: `Accept-Payment: tempo/*, solana/*;q=0.6, */session;q=0.3`. When present, servers SHOULD filter to matching `q>0` ranges, order by descending `q`, preserve server preference order on ties, and prefer the most specific matching range. If absent, servers MUST behave as if the client accepts any combination. If malformed, servers MAY ignore it. The returned `WWW-Authenticate` challenge remains authoritative regardless — clients MUST validate it before paying. ## Key Parameters - **Required challenge params**: `id`, `realm`, `method`, `intent`, `request`. - **Optional challenge params**: `digest`, `expires`, `description`, `opaque`. - **Credential fields**: `challenge` (object, required), `source` (string, optional, DID-recommended), `payload` (object, required). - **Registered header fields**: `Accept-Payment` (client preference), `Payment-Receipt` (server proof-of-payment) — both registered permanent in the HTTP header registry by this document. - **Error codes** (Problem Details, RFC 9457, base URI `https://paymentauth.org/problems/`): `payment-required` (402), `payment-insufficient` (402), `payment-expired` (402), `verification-failed` (402), `method-unsupported` (400), `malformed-credential` (402), `invalid-challenge` (402). - **Versioning**: the `Payment` scheme name itself is unversioned on the wire (like `Basic`/`Bearer`/`Digest`); a truly incompatible change would need a new scheme name (e.g. `Payment2`). Payment methods MAY carry a `version` field inside `methodDetails` (absence = version 1). Intents never carry a version — breaking intent changes require a new intent identifier (e.g. `charge-v2`). - **Size limits**: challenges SHOULD stay under 8KB; clients MUST handle challenges of at least 4KB; servers MUST handle credentials of at least 4KB. - **Transport security**: TLS 1.2 minimum, TLS 1.3 RECOMMENDED; Payment challenges/credentials MUST NOT be sent over unencrypted HTTP. - **Caching**: 402 responses MUST send `Cache-Control: no-store`; responses carrying `Payment-Receipt` MUST send `Cache-Control: private`. ## When To Use Use the Payment scheme whenever a resource should be gated purely on payment (not identity/authorization) and the exchange needs to happen inline within a single logical HTTP resource-fetch flow — e.g., APIs charging per call, per token, or per session. It is the substrate that [[concepts/payment-intents]] (charge/subscription semantics), the method entity pages (concrete rails), [[concepts/payment-discovery]] (pre-flight discovery), and [[concepts/mcp-transport]] (JSON-RPC/MCP carriage) all build on. Choose 402/`Payment` specifically (not 401) so clients can distinguish "you must pay" from "you must authenticate," and reserve 403 for "you paid, but policy still denies you." ## Risks & Pitfalls - **Amount verification**: clients MUST verify amount, recipient/address, currency/asset, and validity window themselves before paying — the `description` parameter is display-only and MUST NOT be trusted; a malicious server could show a friendly description while `request` asks for something else. - **Replay and idempotency**: payment proofs MUST be single-use; servers MUST NOT perform side effects for unpaid requests; non-idempotent methods (POST/PUT/DELETE) SHOULD support an `Idempotency-Key` header to make retries safe; concurrent requests with the same credential MUST settle at most once (atomic check-and-mark / distributed locks recommended). - **Challenge-binding secret handling**: HMAC/shared secrets used for stateless binding MUST stay server-side only and MUST NOT be logged; on rotation, servers SHOULD keep verifying under the old secret until outstanding challenges expire. - **Credential handling**: `Authorization: Payment` and `Payment-Receipt` are sensitive — MUST NOT be logged, included in error messages/debugging output/analytics, and SHOULD be memory-only, cleared after use. - **Intermediary handling of 402**: proxies/caches/CDNs may not treat 402 the way they special-case 401 (e.g. stripping credentials or prompting) — servers/clients cannot rely on that behavior. - **Multiple challenges / multiple credentials**: clients MUST send only one `Authorization: Payment` header corresponding to one chosen challenge; servers receiving multiple payment credentials in a single request SHOULD reject with 400. - **DoS surface**: issuing challenges and verifying credentials are both rate-limit targets; servers SHOULD rate-limit both. ## Related Concepts - [[concepts/mpp-overview]] — the broader protocol this scheme is the core of - [[concepts/payment-intents]] — defines the `intent` values (`charge`, `subscription`) referenced in every challenge - [[concepts/payment-discovery]] — advisory, pre-flight discovery of which challenges a server will offer; the 402 challenge defined here always wins on conflict - [[concepts/mcp-transport]] — maps this exact challenge/credential/receipt model onto JSON-RPC and MCP instead of raw HTTP headers ## Sources - raw/github_doc-specs-core-draft-httpauth-payment-00-md.md (`specs/core/draft-httpauth-payment-00.md` — the full core "Payment" HTTP Authentication Scheme specification) --- title: "Payment Intents (Charge and Subscription)" type: concept tags: [intents, core-spec, foundational, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-intents-draft-payment-intent-charge-00-md.md", "raw/github_doc-specs-intents-draft-payment-intent-subscription-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition A **Payment Intent** is the abstract "type of payment request" carried in the `intent` field of a [[concepts/payment-http-auth-scheme|Payment challenge]] — it says *what kind* of payment is being requested without saying *how* it's carried out on any particular network. Intents are registered in the IANA "HTTP Payment Intents" registry established by the core httpauth-payment spec. Two intents are currently defined at draft-00: **`charge`** — a one-time payment where the payer provides proof of payment immediately in exchange for resource access — and **`subscription`** — a recurring fixed-amount payment authorization, charged once per billing period until cancellation or invalidation. Payment method specifications (see method entity pages) implement these abstract intents using their own concrete mechanisms. ## How It Works ### Charge intent (`draft-payment-intent-charge-00`) **Properties:** | Property | Value | |----------|-------| | Intent Identifier | `charge` | | Payment Timing | Immediate (before or with request) | | Idempotency | Single-use per challenge | | Reversibility | Method-dependent | **Flow:** (1) server issues 402 with `intent="charge"`; (2) client fulfills the payment (method-specific); (3) client submits a credential with proof of payment; (4) server verifies and grants access; (5) server returns a `Payment-Receipt` header. The intent implies **atomic exchange** — the server SHOULD NOT provide partial access on failed verification; either the full resource is delivered or access is denied. **Request schema — shared fields** (the `request` parameter, JCS-canonicalized then base64url-encoded per the core spec): Required: `amount` (string, base units/smallest denomination), `currency` (string — ISO 4217 lowercase code for fiat, e.g. `"usd"`; on-chain token contract address for crypto; or method-defined). Optional: `recipient` (payment recipient, method-native format), `description` (human-readable, display-only), `externalId` (merchant's own reference/order ID), `methodDetails` (object, method-specific extension data). Methods MAY elevate optional fields to required — e.g., blockchain methods typically require `recipient` and `expires`. Challenge expiry itself is conveyed by the `expires` auth-param on `WWW-Authenticate`, not duplicated inside `request`. **Credential payload proof types** are method-specific: preimage (Lightning), signature (Tempo, EVM), processor confirmation identifier (Stripe), or ledger transaction hash (Bitcoin, Ethereum). Each credential MUST be usable only once per challenge. **Server verification MUST**: (1) verify `id` matches an outstanding challenge, (2) verify not expired, (3) verify the payment proof via method-specific procedure, (4) verify amount matches the request, (5) verify recipient matches the request. **Settlement varies by method**: immediate (Lightning preimage, confirmed blockchain tx), deferred (signed authorization submitted to chain after verification), or processor-mediated (e.g. Stripe PaymentIntent). ### Subscription intent (`draft-payment-intent-subscription-00`) **Properties:** | Property | Value | |----------|-------| | Intent Identifier | `subscription` | | Payment Timing | Recurring (initial charge at activation, then once per period) | | Idempotency | Credential single-use; subscription grant reusable across billing periods | | Reversibility | Cancellable | The spec is explicit that this standardizes the **recurring payment authorization itself**, not a full billing system — it deliberately does not define price catalogs, quantities/seats, plan swaps, prorations, deferred starts, billing-cycle realignment, or invoice state; those are application-layer or method-profile concerns. A method MUST either preserve these semantics exactly or reject the request — it MUST NOT approximate them. **Flow:** ``` Client Server Payment Network │ (1) GET /resource │ │ ├───────────────────────────────>│ │ │ (2) 402, intent="subscription" │ │ │<───────────────────────────────┤ │ │ (3) Sign subscription grant │ │ │ (4) Authorization: Payment │ │ ├───────────────────────────────>│ │ │ │ (5) Activate + collect 1st charge │ ├─────────────────────────────>│ │ (6) 200 OK + Receipt │ │ │<───────────────────────────────┤ │ │ ... later period ... │ │ │ │ (7) Collect renewal │ │ ├─────────────────────────────>│ │ (8) 200 OK + Receipt │ │ │<───────────────────────────────┤ │ ``` **Request schema — required shared fields**: `amount` (fixed per-billing-period amount, base units), `currency`, `periodUnit` (MUST be `day`, `week`, or `month`), `periodCount` (positive integer string, count of `periodUnit` per billing period). Both `amount` and `periodCount` MUST be plain base-10 positive-integer strings — no sign, decimal point, exponent, leading zeros, or whitespace. Period math: `day` = fixed `periodCount * 86400`-second windows; `week` = fixed `periodCount * 604800`-second windows; `month` = calendar-month periods anchored at activation, computed by adding `N * periodCount` calendar months to the **original activation anchor** (not the previous boundary) using UTC calendar fields — if the target month lacks the anchor's day-of-month, use the last valid day of that month while preserving time-of-day. **Optional shared fields**: `recipient`, `subscriptionExpires` (RFC 3339 timestamp bounding the reusable lifetime of the authorization), `description`, `externalId`, `methodDetails`. Method-specific parameters MUST live only inside `methodDetails` — methods MUST NOT define new top-level request fields. **Activation**: the server MUST (1) verify the subscription authorization proof, (2) perform method-specific setup and collect the first billing-period charge, (3) initialize durable subscription state, (4) return 200 with a `Payment-Receipt` including a `subscriptionId`. The subscription is active only once these succeed. **Renewal**: for each later period, the server MAY collect one renewal charge via the method-specific recurring-authorization flow; it MUST ensure the renewal is collected before or atomically with delivering that period's service; MUST NOT collect more than one renewal per billing period; and missed periods do NOT accumulate — at most one charge is authorized for the current period even after a gap. **Subscription Identifier**: after successful activation, the server MUST return a `subscriptionId` in the `Payment-Receipt` — a base64url (no padding) string, unique within the server's namespace. The spec does not define a request header/parameter for selecting an existing subscription on later calls; that's an application-layer concern (session state, account identity, resource scope, etc.). Possession of a `subscriptionId` alone is NOT sufficient authorization — servers MUST separately authenticate/authorize the client's use of it. **Cancellation**: payers SHOULD be able to cancel before any method-specific expiry; exact mechanics and effective-time rules are method/application-specific, but servers MUST NOT collect renewal charges for periods after cancellation takes effect. **Error responses** — all conditions below return `402 Payment Required` with a fresh `WWW-Authenticate` challenge: method-specific expiry reached; cancellation effective or authorization revoked; current billing period unpaid or renewal failed; invalid credential. Clients seeing a 402 after a previously valid subscription SHOULD treat it as dead and start a new subscription flow. ## Key Parameters **Charge — required**: `amount`, `currency`. **Charge — optional**: `recipient`, `description`, `externalId`, `methodDetails`. **Subscription — required**: `amount`, `currency`, `periodUnit` (`day`|`week`|`month`), `periodCount`. **Subscription — optional**: `recipient`, `subscriptionExpires`, `description`, `externalId`, `methodDetails`. **Subscription lifecycle terms**: Billing Period, Activation, Renewal, Cancellation, Subscription Identifier (server-issued opaque id, base64url-nopad, returned in `Payment-Receipt`). **Both intents**: `currency` accepts ISO 4217 lowercase codes, on-chain token contract addresses, or method-defined identifiers (see [[concepts/payment-http-auth-scheme]] for the underlying `request` encoding rules — JCS canonicalization, base64url-nopad). ## When To Use Use `charge` for one-off, pay-per-use access: single API calls, per-token inference, per-query search, per-download content — anywhere a single proof-of-payment should unlock a single resource fetch atomically. Use `subscription` for recurring fixed-price access: monthly/weekly/daily API plans, content subscriptions, or any service billed at a stable per-period price where the client wants to grant a standing (but cancellable, bounded) recurring authorization rather than re-paying on every request. Both intents can be offered together — see the core spec's Intent Negotiation, where a server issues multiple `WWW-Authenticate` lines and the client picks one — and both are referenced as offerable `intent` values in [[concepts/payment-discovery]] offers. ## Risks & Pitfalls - **Charge**: clients MUST independently verify amount, currency, and (where exposed) recipient before paying — never trust `description`. Not all methods expose a recipient (processor-based methods like Stripe route internally), so recipient-verification guidance only applies where the method surfaces one. Finality varies (instant for Lightning, delayed for blockchain confirmations, potentially reversible for card chargebacks) — servers should size access decisions to the method's actual finality guarantees. - **Subscription — no accumulation**: a missed renewal does NOT grant authority to collect two charges later; servers MUST NOT treat missed periods as banking up permission for extra charges. - **Subscription — narrow contract**: the shared intent intentionally excludes trials, prorations, discounts, metered billing, pause/resume, quantity/plan changes, and open-ended renewals — a method exposing these must map them explicitly onto the shared semantics or reject the request; it must not approximate. - **Subscription — duplicate-charge risk**: servers MUST maintain durable state (subscription id, billing anchor, last-charged period index, expiry/bounded-lifetime state, cancellation status) sufficient to prevent double-charging across retries, concurrent requests, and out-of-band events; clients SHOULD send `Idempotency-Key` for non-idempotent requests. - **Subscription — recurring-charge awareness**: clients MUST clearly communicate to the (human or agent) payer that activating a subscription authorizes future charges without a new action each period. - **Caching**: 402 responses for either intent MUST include `Cache-Control: no-store`; responses with `Payment-Receipt` MUST include `Cache-Control: private`. ## Related Concepts - [[concepts/payment-http-auth-scheme]] — defines the `intent` auth-param and the challenge/credential envelope that both intents plug into - [[concepts/mpp-overview]] — situates Intents as one of the four architectural layers (Core / Intents / Methods / Extensions) - [[concepts/payment-discovery]] — advertises which intents (`charge`, `session`) a service offers per operation, ahead of the runtime 402 - [[concepts/mcp-transport]] — carries `charge`-intent challenges (in the worked examples) over JSON-RPC/MCP ## Sources - raw/github_doc-specs-intents-draft-payment-intent-charge-00-md.md (`specs/intents/draft-payment-intent-charge-00.md`) - raw/github_doc-specs-intents-draft-payment-intent-subscription-00-md.md (`specs/intents/draft-payment-intent-subscription-00.md`) --- title: "Using MPP (Rust SDK Integration)" type: concept tags: [sdk, integrator, transport, methods, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-readme-md-2.md", "raw/github_doc-examples-readme-md-2.md", "raw/github_doc-examples-basic-readme-md.md", "raw/github_doc-examples-axum-extractor-readme-md.md", "raw/github_doc-examples-catalog-client-readme-md.md", "raw/github_doc-examples-session-multi-fetch-readme-md.md", "raw/github_doc-examples-session-sse-readme-md.md", "raw/github_doc-examples-stripe-readme-md.md", "raw/github_doc-examples-ws-readme-md.md", "raw/github_doc-crates-alloy-transport-mpp-readme-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Definition Using MPP, in the implementation sense, means wiring the protocol's challenge/credential exchange into real client and server code rather than reading about it in the abstract. The `mpp-rs` crate (repository `tempoxyz/mpp-rs`, `cargo add mpp`) is the official Rust SDK for MPP: it gives servers a way to charge for HTTP endpoints (Tempo or Stripe) and gives clients a way to detect and automatically fulfill `402 Payment Required` challenges. The same repository also ships `alloy-transport-mpp`, a payment-aware JSON-RPC transport for the `alloy` Ethereum library, and a set of standalone runnable examples covering basic charges, per-route Axum pricing, Stripe SPTs, session/channel reuse, SSE streaming, and WebSocket payments. ## How It Works ### Server side: charging for a request The core server pattern is: build an `Mpp` instance configured with a payment method, call a `charge`-style method to mint a challenge, and verify a returned credential. For Tempo: ```rust use mpp::server::{Mpp, tempo, TempoConfig}; let mpp = Mpp::create(tempo(TempoConfig { recipient: "0x742d35Cc6634C0532925a3b844Bc9e7595f1B0F2", }))?; let challenge = mpp.charge("1")?; let receipt = mpp.verify_credential(&credential).await?; ``` For Stripe (Shared Payment Token flow): ```rust use mpp::server::{Mpp, stripe, StripeConfig}; let mpp = Mpp::create_stripe(stripe(StripeConfig { secret_key: "sk_test_...", network_id: "internal", payment_method_types: &["card"], currency: "usd", decimals: 2, }))?; let challenge = mpp.stripe_charge("1")?; let receipt = mpp.verify_credential(&credential).await?; ``` For Axum-based servers, the `axum` feature exposes a `MppCharge` extractor that handles the entire 402 flow (challenge issuance, credential parsing, verification) without manual header parsing. Each price point is a `ChargeConfig` impl: ```rust use mpp::server::axum::{ChargeConfig, MppCharge, WithReceipt}; struct OneCent; impl ChargeConfig for OneCent { fn amount() -> &'static str { "0.01" } } struct OneDollar; impl ChargeConfig for OneDollar { fn amount() -> &'static str { "1.00" } fn description() -> Option<&'static str> { Some("Premium content") } } async fn cheap(charge: MppCharge) -> WithReceipt<&'static str> { WithReceipt { receipt: charge.receipt, body: "cheap" } } async fn expensive(charge: MppCharge) -> WithReceipt<&'static str> { WithReceipt { receipt: charge.receipt, body: "premium" } } ``` (`examples/axum-extractor`: `GET /api/fortune` costs `$0.01` via `MppCharge`, `GET /api/premium` costs `$1.00` via `MppCharge`.) ### Client side: paying automatically On the client, a `PaymentMiddleware` (feature `middleware`, requires `reqwest-middleware`) wraps a `reqwest::Client` so that any `402` response is transparently paid and retried: ```rust use mpp::client::{PaymentMiddleware, TempoProvider}; use reqwest_middleware::ClientBuilder; let provider = TempoProvider::new(signer, "https://rpc.moderato.tempo.xyz")?; let client = ClientBuilder::new(reqwest::Client::new()) .with(PaymentMiddleware::new(provider)) .build(); // Requests now handle 402 automatically let resp = client.get("https://mpp.dev/api/ping/paid").send().await?; ``` For Stripe, the client supplies a `StripeProvider` closure that proxies Shared Payment Token (SPT) creation through the developer's own backend (so the Stripe secret key never leaves the server), then calls `send_with_payment` directly on a plain `reqwest::Client`: ```rust use mpp::client::{Fetch, StripeProvider}; use mpp::protocol::methods::stripe::CreateTokenResult; let provider = StripeProvider::new(|params| { Box::pin(async move { // Proxy SPT creation through your backend (requires Stripe secret key) let resp = reqwest::Client::new() .post("https://my-server.com/api/create-spt") .json(¶ms) .send().await?.json::().await?; Ok(CreateTokenResult::from(resp["spt"].as_str().unwrap().to_string())) }) }); let resp = reqwest::Client::new() .get("https://api.example.com/paid") .send_with_payment(&provider) .await?; ``` The `examples/stripe` example spells out the full Stripe round trip: client requests `/api/fortune` → server replies `402` with a `WWW-Authenticate` challenge → client's SDK calls `create_token`, which POSTs to the app's own `/api/create-spt` endpoint (server-side, holding the secret key) → server creates the SPT via Stripe → client retries `/api/fortune` with `Authorization: Payment ` containing the SPT → server creates a Stripe PaymentIntent with `shared_payment_granted_token` and `confirm=true` → on success, the server returns the fortune with a receipt (e.g. `pi_3Q...`). ### Session reuse (payment channels) `examples/session/multi-fetch` demonstrates paying for many requests over one on-chain-opened channel instead of paying per call: 1. **Server** exposes `/api/scrape`, costing 0.01 pathUSD per request. 2. **Client** opens a payment channel on the first request (on-chain). 3. Subsequent requests use off-chain vouchers — no gas, instant settlement. 4. Each voucher is cumulative: request N carries a voucher for `N × 0.01` pathUSD. 5. **Client** closes the channel, triggering on-chain settlement and refund of unused deposit. The `catalog-client` example (`examples/catalog-client`) generalizes this: it calls arbitrary endpoints from the MPP service catalog (mpp.dev/services) purely by reading the server's `402` challenge to pick a provider — it has no service-specific adapters. Tempo `charge` and `session` challenges reuse the active account and P-256 access key from the Tempo Wallet's `~/.tempo/wallet/store.json`, and session channels persist in an MPPx-compatible `~/.tempo/wallet/channels.db` scoped to the target service origin, so a cold process can resume an existing channel: ```bash cargo run -p catalog-client-example -- \ GET 'https://stabletravel.dev/api/reference/locations?keyword=SFO&subType=AIRPORT%2CCITY' cargo run -p catalog-client-example -- \ POST https://rpc.mpp.tempo.xyz/ \ '{"jsonrpc":"2.0","id":1,"method":"eth_chainId","params":[]}' ``` Relevant env vars: `TEMPO_RPC_URL` (override RPC), `MPP_CHANNEL_STORE` (channel DB path), `MPP_DEFAULT_DEPOSIT` (default `20000` atomic units), `MPP_MAX_DEPOSIT` (default `1000000` atomic units), `MPP_REQUEST_HEADERS`, `STRIPE_SPT_ENDPOINT`. ### Streaming transports: SSE and WebSocket `examples/session/sse` shows pay-per-token LLM streaming: client `GET /api/chat?prompt=...` → server responds `402` with a session challenge → client opens a payment channel on-chain and sends an open credential → server verifies and responds `200` → client sends a `GET` with a voucher credential → server streams tokens as SSE events, charging per token; mid-stream, if the channel balance runs out, the server emits `payment-need-voucher` events and the client sends updated vouchers. Server-side this uses `mpp::server::sse::serve()`; client-side it uses a `TempoSessionProvider` for channel lifecycle management plus SSE event parsing. `examples/ws` shows the WebSocket flow directly at the message level: client connects, server sends `{"type":"challenge",...}`, client responds `{"type":"credential","credential":"Payment ..."}`, server verifies and streams `{"type":"message","data":"..."}` frames, then sends a final `{"type":"receipt",...}` and closes. (That example's credential is a mock — production code should sign real transactions via `TempoProvider`.) The SDK's own `ws` feature provides these message shapes directly: ```rust use mpp::server::ws::{WsMessage, WsResponse}; // Server: parse incoming WS message, send challenge/receipt let msg: WsMessage = serde_json::from_str(&text)?; if let WsMessage::Credential { credential } = msg { let parsed = mpp::parse_authorization(&credential)?; let receipt = mpp.verify_credential(&parsed).await?; let resp = WsResponse::Receipt { receipt: serde_json::to_value(&receipt)?, }; socket.send(resp.to_text()).await; } // Client: detect challenge, send credential let msg: mpp::client::ws::WsServerMessage = serde_json::from_str(&text)?; if let WsServerMessage::Challenge { challenge, .. } = msg { let cred_msg = serde_json::json!({ "type": "credential", "credential": auth_string, }); ws.send(cred_msg.to_string()).await; } ``` WSS is handled at the connection layer — the transport itself is protocol-agnostic. Servers terminate TLS via a reverse proxy (nginx, Cloudflare) or `axum-server` with rustls; clients use `tokio-tungstenite` with `native-tls` or `rustls` features, e.g. `tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] }`. ### EVM/alloy transport `alloy-transport-mpp` (crate `crates/alloy-transport-mpp` in the same `mpp-rs` repo) supplies a drop-in `alloy` transport for paid JSON-RPC. `MppHttpTransport` delegates the entire 402-challenge/pay/retry/commit-or-rollback lifecycle to `mpp`: ```rust,ignore use alloy_provider::ProviderBuilder; use alloy_rpc_client::RpcClient; use alloy_transport_mpp::MppHttpTransport; let transport = MppHttpTransport::with_default_client(rpc_url, payment_provider)? .with_max_concurrent_requests(16); let client = RpcClient::new(transport, false); let provider = ProviderBuilder::new().connect_client(client); ``` It also ships opt-in WebSocket transports speaking the MPP wire protocol: `MppWsConnect` is a drop-in `PubSubConnect` for JSON-RPC, and `MppApplicationWsConnect` carries arbitrary text application messages (e.g. the OpenAI Responses WebSocket API) — both wrap payloads in canonical MPP `message` envelopes and handle `challenge`, `needVoucher`, `receipt`, signed session close, and `error` frames internally via a user-supplied `PaymentProvider` (and a `VoucherProvider` for streaming/session intents): ```rust,ignore use alloy_provider::ProviderBuilder; use alloy_transport_mpp::MppWsConnect; let connect = MppWsConnect::new("wss://paid.example/rpc", my_provider); let provider = ProviderBuilder::new().connect_pubsub(connect).await?; ``` ```rust,ignore use alloy_transport_mpp::MppApplicationWsConnect; let connect = MppApplicationWsConnect::new( "wss://paid.example/v1/responses", payment_provider, voucher_provider, ); let mut socket = connect.connect().await?; socket.send(r#"{"type":"response.create","model":"gpt-5.6-sol"}"#).await?; while let Ok(message) = socket.next().await { // Handle application messages. Payment frames stay inside the transport. } // Performs the canonical close-request/close-ready/signed-close handshake. let final_receipt = socket.close().await?; ``` Ring is the default TLS backend for the crate; to select another, disable default features so Cargo does not compile more than one crypto provider (backends: `ring`, `aws-lc-rs`, `native-tls`; `rustls-tls` exposes provider-neutral plumbing for apps that install their own process-wide Rustls crypto provider): ```toml alloy-transport-mpp = { git = "https://github.com/tempoxyz/mpp-rs", default-features = false, features = ["aws-lc-rs"] } ``` ## Key Parameters - **Install**: `cargo add mpp`. - **Feature flags** (mpp-rs README): `client` (payment providers, `Fetch` extension), `server` (`ChargeMethod` trait), `tempo` (Tempo blockchain support, implies `evm`), `stripe` (SPT-based payments), `evm` (shared EVM utilities), `middleware` (reqwest-middleware `PaymentMiddleware`, implies `client`), `tower` (Tower middleware for server integration), `axum` (Axum extractor convenience), `ws` (WebSocket transport for bidirectional session payments), `utils` (hex/random dev utilities). - **What this SDK implements**: Tempo (charge and session intents) and Stripe (charge intent via Shared Payment Tokens) — the two methods with concrete Rust support, out of the broader method-agnostic protocol. - **Runnable examples in the repo**: `basic` (Tempo Fortune Teller API), `catalog-client` (arbitrary MPP catalog endpoint calls with Tempo Wallet state), `stripe` (Fortune Teller via Stripe SPT), `axum-extractor` (per-route pricing via `MppCharge`), `session/multi-fetch` (multiple paid requests over one channel), `session/sse` (pay-per-token LLM streaming). Each is a standalone Cargo crate with a server and client binary, e.g. `cd examples/basic && cargo run --bin basic-server` / `cargo run --bin basic-client`. - **Common env vars across examples**: `PRIVATE_KEY` (client signing key, random if unset), `BASE_URL` (server URL, default `http://localhost:3000`), `RPC_URL` (Tempo RPC, default `https://rpc.moderato.tempo.xyz`), `MPP_SECRET_KEY` (axum-extractor server challenge-verification secret), `STRIPE_SECRET_KEY` (stripe example). ## When To Use - Building a Rust HTTP service that should charge per request/route without pre-provisioned API keys — use the `server` feature (`axum` extractor for the least boilerplate) with `tempo` and/or `stripe`. - Building a Rust client or agent that needs to autonomously pay for resources as it works — use `client` + `middleware` for transparent 402-handling on top of `reqwest`, or the lower-level `Fetch`/`send_with_payment` API when you need to control provider selection (e.g. Stripe SPT proxying). - Multiple calls to the same paid endpoint in a session — use the session/channel pattern (`session/multi-fetch`) instead of paying per request, since off-chain vouchers avoid repeated on-chain gas costs. - Streaming or metered responses (LLM token streaming, live data feeds) — use the SSE pattern (`mpp::server::sse::serve()` + `TempoSessionProvider`) or the WebSocket pattern (`mpp::server::ws` / `mpp::client::ws`, or `alloy-transport-mpp`'s `MppApplicationWsConnect` for non-JSON-RPC WS protocols). - Paying for JSON-RPC (e.g. EVM node access) as part of an `alloy`-based application — use `alloy-transport-mpp`'s `MppHttpTransport` or `MppWsConnect` instead of hand-rolling 402 handling around raw RPC calls. - Calling into the broader MPP service catalog generically (not a bespoke integration with one service) — use the `catalog-client` pattern, which selects a payment provider purely from the server's challenge. ## Risks & Pitfalls - The `catalog-client` example explicitly warns that it **pays real challenges** — inspect the target service's catalog price before running it against a live endpoint. - The WebSocket example (`examples/ws`) uses a mock credential for demonstration; production code must sign real transactions via `TempoProvider` rather than fabricating credential strings. - For `alloy-transport-mpp`, enabling more than one TLS crypto-provider feature at once (e.g. leaving `ring` default-enabled while adding `aws-lc-rs`) causes a Cargo build conflict — disable default features when selecting a non-default backend. - The Stripe SPT flow requires the secret key to stay server-side (the `create-spt` proxy endpoint pattern exists specifically so the client never sees `sk_test_...`); a naive client-side SPT creation would leak the secret key. - Session/channel state (Tempo Wallet's `store.json`, `channels.db`) is read from local files by the `catalog-client` example — misconfigured `MPP_CHANNEL_STORE` paths or a stale/foreign wallet store could reuse the wrong account or channel scope. - This SDK only ships Tempo and Stripe method support; other payment methods (EVM sessions, Solana, Lightning, etc., per the method entity pages) are defined in `mpp-specs` but are not necessarily implemented in `mpp-rs` — check feature flags before assuming a method is available in Rust. ## Related Concepts - [[concepts/mpp-overview]] — the overall protocol this SDK implements - [[concepts/payment-http-auth-scheme]] — the wire-level `Payment` challenge/credential scheme that `mpp-rs` implements in code - [[concepts/payment-intents]] — the charge/session/subscription intents this SDK exposes as `mpp.charge()`, session channels, etc. - [[concepts/mcp-transport]] — a related transport binding (JSON-RPC/MCP) alongside the HTTP, SSE, and WebSocket transports shown here - [[concepts/extending-mpp]] — how to add support for a payment method or transport not yet covered by this SDK ## Sources - raw/github_doc-readme-md-2.md (mpp-rs repository README: install, feature flags, server/client/WebSocket quick-start code) - raw/github_doc-examples-readme-md-2.md (mpp-rs `examples/README.md`: example index and run commands) - raw/github_doc-examples-basic-readme-md.md (`examples/basic/README.md`: Tempo Fortune Teller API) - raw/github_doc-examples-axum-extractor-readme-md.md (`examples/axum-extractor/README.md`: `MppCharge` extractor, per-route pricing) - raw/github_doc-examples-catalog-client-readme-md.md (`examples/catalog-client/README.md`: generic catalog client, Tempo Wallet state, env vars) - raw/github_doc-examples-session-multi-fetch-readme-md.md (`examples/session/multi-fetch/README.md`: payment channel reuse) - raw/github_doc-examples-session-sse-readme-md.md (`examples/session/sse/README.md`: pay-per-token SSE streaming) - raw/github_doc-examples-stripe-readme-md.md (`examples/stripe/README.md`: Stripe SPT flow and sequence diagram) - raw/github_doc-examples-ws-readme-md.md (`examples/ws/README.md`: WebSocket payment protocol) - raw/github_doc-crates-alloy-transport-mpp-readme-md.md (`crates/alloy-transport-mpp/README.md`: alloy HTTP/WS transports, TLS backend features) --- title: "Method: Card" type: entity tags: [methods, fiat, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-card-draft-card-charge-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `card` is MPP's fiat payment method for one-time card-network payments. It settles via existing card network rails (Visa, Mastercard, Amex, Discover) using encrypted network tokens rather than raw PANs — the client never sees a decrypted token and the server never sees raw card data. The method is PSP-agnostic: any Payment Service Provider (PSP) can act as the Server Enabler, and any vault provider/token service provider (TSP) can act as the Client Enabler. It is authored by Visa (Jacob Brans) and implements only the **charge** intent — no session or subscription variant is defined in this draft. ## Characteristics **Intent support:** `charge` only. No `session` or `subscription` spec exists for `card`. **Charge flow (8 steps):** 1. Client requests a resource. 2. Server responds 402 with a Challenge (amount, currency, accepted networks, encryption key). 3. Client forwards challenge context to its Client Enabler (CE). 4. CE provisions a network token, encrypts it with the server's key, returns the credential. 5. Client retries with `Authorization: Payment` containing the encrypted credential. 6. Server forwards the credential to its Server Enabler. 7. Server Enabler decrypts and processes the payment through card network rails. 8. Server returns 200 with `Payment-Receipt` and the resource. Clients MAY include Visa Trusted Agent Protocol (TAP) signature headers for additional identity assurance. **Key request/challenge fields:** - Shared: `amount` (smallest currency unit string, e.g. `"4999"` = $49.99), `currency` (lowercase ISO 4217, e.g. `"usd"`), `recipient` (OPTIONAL merchant ID, e.g. `"merch_abc123"`), `description`, `externalId`. - `methodDetails.acceptedNetworks` (REQUIRED array, e.g. `["visa","mastercard"]`), `methodDetails.merchantName` (REQUIRED), `methodDetails.billingRequired` (OPTIONAL boolean). - Encryption key delivery: either `methodDetails.encryptionJwk` (embedded RSA JWK, RECOMMENDED) or `methodDetails.jwksUri` + `methodDetails.kid` (hosted JWKS, same-origin as realm REQUIRED). Key MUST be `"kty":"RSA"`, ≥2048 bits, `"alg":"RSA-OAEP-256"`, `"use":"enc"`. **Credential/payload fields** (in the decrypted `payload` object of the Authorization: Payment credential): `encryptedPayload` (JWE compact serialization, REQUIRED, client/server MUST NOT parse), `network` (`"visa"|"mastercard"|"amex"|"discover"`), `panLastFour`, `panExpirationMonth`, `panExpirationYear`, `billingAddress` (conditional on `billingRequired`), `cardholderFullName` (OPTIONAL), `paymentAccountReference`/PAR (conditional, cross-channel cardholder identifier). **Encrypted payload format:** JWE compact serialization; protected header `{"alg":"RSA-OAEP-256","enc":"A256GCM","kid":"..."}`; plaintext contains `token` object (`paymentToken`, `tokenExpirationMonth`, `tokenExpirationYear`, `eci`) and `dynamicData` object (`dynamicDataValue`, `dynamicDataType` ∈ `CARD_APPLICATION_CRYPTOGRAM_SHORT_FORM|LONG_FORM|CARDHOLDER_AUTHENTICATION_CRYPTOGRAM|NONE`, `dynamicDataExpiration` as Unix epoch). CEK is a random 256-bit key wrapped with RSA-OAEP-256; content encrypted with AES-256-GCM. **Prerequisites:** Both client and server require access to a Client Enabler / Server Enabler respectively (vault provider, TSP, or PSP acting as issuer). No on-chain component. **Verification & replay:** challenge binding (HMAC or server-side lookup of `challenge.id` + amount/currency/networks/recipient/realm/expiry/kid); each credential usable once per challenge; same `challenge.id` + already-processed → cached 200 with `Payment-Receipt`; same `challenge.id` + prior failure → HTTP 409; expired challenge → fresh 402. Challenge IDs MUST contain ≥128 bits of entropy; state retained for expiry + 5 min (RECOMMENDED). **Receipt fields:** `challengeId`, `method:"card"`, `status:"success"`, `reference` (network authorization reference, e.g. `"visa_txn_abc123"`), `timestamp` (RFC 3339), `externalId` (OPTIONAL echo). ## How to Use 1. Client GETs a protected resource; server issues `402` with `WWW-Authenticate: Payment id=..., realm=..., method="card", intent="charge", expires=..., request=`. 2. Client decodes `request`, resolves the encryption key (embedded JWK or JWKS+kid), and calls its Client Enabler's token-provisioning endpoint (e.g. `POST /v1/payment-tokens`) with the card identifier and full challenge context. 3. Client Enabler provisions a network token + cryptogram, encrypts the payload as a JWE with the resolved key, and returns `encryptedPayload` plus display metadata (`network`, `panLastFour`, `panExpirationMonth/Year`, `cardholderFullName`, `paymentAccountReference`). 4. Client assembles the credential (`{challenge, payload}`), base64url-encodes it, and retries the original request with `Authorization: Payment `. 5. Server forwards `encryptedPayload` to its Server Enabler, which decrypts with the matching RSA private key and authorizes over card network rails using `challenge.id` as the idempotency key. 6. On approval, server returns `200` with `Payment-Receipt` (decoded to `challengeId`, `method`, `status`, `reference`, `timestamp`); on decline, server returns an error and SHOULD issue a fresh 402. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the underlying `Payment` HTTP authentication scheme this method implements. - [[concepts/payment-intents]] — defines the shared `charge` intent semantics `card` inherits. - [[entities/method-stripe]] — the other fiat rail in MPP, using Shared Payment Tokens instead of network tokens. - [[entities/method-usdc]] — a crypto-settled alternative for USD-denominated payments. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: EVM" type: entity tags: [methods, crypto, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-evm-draft-evm-charge-00-md.md", "raw/github_doc-specs-methods-evm-draft-evm-session-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `evm` is MPP's payment method for any EVM-compatible blockchain (Ethereum and compatible chains identified by EIP-155 `chainId`). It unifies what earlier drafts proposed as per-chain methods, since control flow, data structures, and verification are identical across EVM chains — only `chainId` and optional RPC extensions differ. It settles ERC-20 token transfers (native ETH transfers are out of scope). It supports both the **charge** intent (one-time payment) and the **session** intent (streaming payment channel); no subscription spec exists for `evm`. ## Characteristics **Intent support:** `charge` (draft-evm-charge-00) and `session` (draft-evm-session-00). No `subscription`. ### Charge Four credential types, selected via `payload.type`: - `type="permit2"` (RECOMMENDED) — client signs an off-chain EIP-712 Permit2 authorization; server submits `permitWitnessTransferFrom()` (single transfer) or `permitBatchWitnessTransferFrom()` (with splits) and pays gas. Requires a one-time ERC-20 `approve()` to the canonical Permit2 contract `0x000000000022D473030F116dDEE9F6B43aC78BA3`. - `type="authorization"` — EIP-3009 `transferWithAuthorization`, opt-in only for tokens that implement EIP-3009 (e.g. USDC, EURC). No prior approval needed. `nonce` binds to `keccak256(abi.encodePacked(challenge.id, challenge.realm))`. - `type="transaction"` — client signs a complete ERC-20 `transfer` transaction; server broadcasts; client pays gas. - `type="hash"` — client broadcasts itself and presents the confirmed tx hash; weakest challenge binding; incompatible with `splits`. Shared request fields: `amount` (base units string), `currency` (ERC-20 contract address, 0x-prefixed 20-byte hex, EIP-55 display but compared by decoded value), `recipient` (EIP-55 address). `methodDetails.chainId` (REQUIRED, EIP-155 chain ID), `methodDetails.permit2Address` (default canonical), `methodDetails.credentialTypes` (ordered preference list), `methodDetails.decimals`, `methodDetails.splits` (max 10 entries, REQUIRES `type="permit2"`; sum of split amounts MUST be strictly less than `amount`). Gas sponsorship is structurally determined by credential type: `permit2`/`authorization` → server pays; `transaction`/`hash` → client pays. ### Session Streaming payment channel using on-chain escrow + off-chain EIP-712 vouchers, adapted from the Tempo session mechanism for any EVM chain. Channel state: `payer`, `payee`, `token`, `authorizedSigner`, `deposit` (uint128), `settled` (uint128), `closeRequestedAt`, `finalized`. `channelId = keccak256(abi.encode(payer, payee, token, salt, authorizedSigner, address(this), block.chainid))`. Mandatory core escrow functions: `open`, `settle`, `topUp`, `close`, `requestClose`, `withdraw`. Optional "Relayed / Gasless Operations profile": `openWithAuthorization`/`topUpWithAuthorization` (EIP-3009, must use `receiveWithAuthorization` not `transferWithAuthorization` to prevent front-running), `openWithPermit2`/`topUpWithPermit2` (Permit2 `permitWitnessTransferFrom`), `settleWithAuthorization`/`closeWithAuthorization` (payee-side EIP-712 authorization, relayer-submitted). Request fields: `amount` (price per unit, not total), `unitType`, `suggestedDeposit`, `currency`, `recipient`. `methodDetails.chainId`, `methodDetails.escrowContract`, `methodDetails.channelId` (OPTIONAL, resume existing), `methodDetails.minVoucherDelta`, `methodDetails.feePayer`, `methodDetails.credentialTypes` (`"permit2"`, `"authorization"`, `"hash"` — no full-transaction path for session), `methodDetails.permit2Contract`. Credential actions (discriminated by `payload.action`): `open`, `topUp`, `voucher`, `close`. Voucher signature: EIP-712 domain `{name, version, chainId, verifyingContract}`, type `Voucher(bytes32 channelId, uint128 cumulativeAmount)`. Vouchers are cumulative, not incremental. Signatures MUST be canonical low-s (`s <= secp256k1_order/2`). Channels have no expiry — closed via cooperative `close()` (payee, with final voucher) or forced close (`requestClose()` → grace period → `withdraw()`). ## How to Use **Charge (Permit2, recommended):** 1. Server issues 402 with `WWW-Authenticate: Payment ... method="evm", intent="charge", request=` decoding to `{amount, currency, recipient, methodDetails:{chainId, credentialTypes:["permit2"]}}`. 2. Client signs an EIP-712 Permit2 `PermitWitnessTransferFrom` message (with `PaymentWitness{challengeHash, externalId}` witness bound to `keccak256(abi.encodePacked(challenge.id, challenge.realm))`). 3. Client submits credential `{challenge, payload:{type:"permit2", permit:{permitted, nonce, deadline}, transferDetails, witness, signature}, source: "did:pkh:eip155::
"}`. 4. Server verifies signature, witness, balances/allowance, then calls `Permit2.permitWitnessTransferFrom()` (or batch variant for splits), waits for receipt, returns `Payment-Receipt` with `{method:"evm", challengeId, reference:, status:"success", chainId}`. **Session (open → voucher → close):** 1. Server issues 402 with `intent="session"`, `methodDetails.escrowContract` and `chainId`. 2. Client opens the channel (directly or via a relayed `openWith*` path) and sends `Authorization: Payment` with `payload.action="open"`. 3. Client signs successive cumulative EIP-712 vouchers (`payload.action="voucher"`) as service is consumed; server persists the highest voucher before serving. 4. Client sends `payload.action="close"`; server calls `close()` on-chain with the final voucher, settling and refunding the remainder. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` and `session` intent semantics this method implements. - [[entities/method-usdc]] — USDC's EVM profile restricts this method's surface to EIP-3009 `authorization` credentials only. - [[entities/method-tempo]] — Tempo's own charge/session/subscription methods, whose session escrow design this method's session spec explicitly adapts. - [[entities/method-solana]] — the analogous non-EVM crypto rail with its own charge/session pair. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: Hedera" type: entity tags: [methods, crypto, integrator, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-hedera-draft-hedera-charge-00-md.md", "raw/github_doc-specs-methods-hedera-draft-hedera-session-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `hedera` is MPP's payment method for the Hedera network, settling Hedera Token Service (HTS) token transfers — including Circle USDC (`0.0.456858` on mainnet) — using Hedera's asynchronous Byzantine Fault Tolerant (aBFT) consensus with deterministic finality in ~3-5 seconds and fixed transaction fees. It supports both the **charge** intent and the **session** intent (a streaming payment channel deployed on Hedera's EVM layer). No subscription spec exists for `hedera`. ## Characteristics **Intent support:** `charge` (draft-hedera-charge-00) and `session` (draft-hedera-session-00). No `subscription`. ### Charge Challenge binding and replay protection are achieved through an **Attribution memo** — a 32-byte value embedded in the Hedera transaction's native memo field, hex-encoded with `0x` prefix (66 chars, within Hedera's 100-byte memo limit): `TAG` (4 bytes, `keccak256("mpp")[0..3]`), `VERSION` (1 byte, `0x01`), `SERVER_ID` (10 bytes, `keccak256(realm)[0..9]`), `CLIENT_ID` (10 bytes, `keccak256(clientId)[0..9]` or zero if anonymous), `NONCE` (7 bytes, `keccak256(challengeId)[0..6]`). This layout is identical to Tempo's attribution memo, differing only in transport (native memo field vs. a contract call). Two credential types: **push mode** (default), `type="hash"` — client broadcasts and presents the Hedera transaction ID (`shard.realm.num@seconds.nanoseconds`, e.g. `0.0.12345@1681234567.123456789`); **pull mode**, `type="transaction"` — client signs and serializes, server broadcasts. Shared fields: `amount` (base units, fits int64), `currency` (HTS Token ID `shard.realm.num`, e.g. `"0.0.456858"` for USDC), `recipient` (Hedera account ID `shard.realm.num`), `externalId` (≤34 bytes — 100-byte memo limit minus the 66-byte attribution memo, so it is never written on-chain, only echoed), `splits` (top-level, not nested under `methodDetails`; ≤9 additional recipients; Hedera's native `TransferTransaction` supports up to 10 atomic transfer entries). `methodDetails.chainId` (295 = mainnet, 296 = testnet; reference implementation defaults to testnet for safety). Verification requires fetching the transaction from the **Mirror Node REST API** (`/api/v1/transactions/{txId}`) with retry (Mirror Node lags consensus by ~3-5 seconds; SHOULD retry up to 10× with 2s delay), checking `result == "SUCCESS"`, the Attribution memo (TAG/VERSION/SERVER_ID/NONCE), and that `token_transfers` entries match the challenge (amount, recipient, splits). ### Session Deployed on **Hedera's EVM layer** as `HederaStreamChannel.sol`, using standard ERC-20 transfers — HTS tokens are exposed as ERC-20 via HIP-218. Channel state and functions mirror the EVM/Tempo session model: `open`, `settle`, `topUp`, `close`, `requestClose`, `withdraw`, plus a Hedera-specific `associateSelf(token)` (calls the HTS precompile at `0x167`; the escrow contract MUST be associated with a token before channels using it can open). HTS precompile interactions need higher gas limits than plain ERC-20 (`approve` ~1,000,000 gas; `open`/`topUp`/`settle`/`close` ~1,500,000 gas each). No `feePayer` field exists in this version — the client always pays channel-operation fees; fee delegation via `feePayerAccountId` is deferred to a future revision. Voucher EIP-712 domain: `{name:"Hedera Stream Channel", version:"1", chainId:295|296, verifyingContract:}`; type `Voucher(bytes32 channelId, uint128 cumulativeAmount)`. Credential actions: `open` (client broadcasts `open()` itself via Hashio JSON-RPC and presents `txHash`, unlike Tempo/EVM sessions where the server broadcasts), `topUp`, `voucher`, `close`. Grace period for forced close: 15 minutes (RECOMMENDED). ## How to Use **Charge (push mode):** 1. Server issues 402 decoding to `{amount, currency:"0.0.456858", recipient:"0.0.12345", methodDetails:{chainId:295}}`. 2. Client builds a `TransferTransaction` (debit `amount` from payer, credit primary recipient and any splits) with `setTransactionMemo()` set to the Attribution memo, signs it, and executes it on Hedera itself. 3. Client submits `{challenge, payload:{type:"hash", transactionId:"0.0.12345@1681234567.123456789"}}`. 4. Server polls the Mirror Node for the transaction, verifies `result=="SUCCESS"`, the Attribution memo, and the token transfers, marks the transaction ID consumed, and returns `Payment-Receipt` (`{method:"hedera", reference:, status:"success", timestamp}`). **Session (open → voucher → close):** 1. Server issues 402 with `intent="session"` and a `challengeId`. 2. Client calls `approve()` + `open()` on `HederaStreamChannel` via Hashio JSON-RPC directly, then sends `Authorization: Payment` with `payload.action="open"` (`channelId`, `txHash`, initial `cumulativeAmount`/`signature`). 3. Client signs successive cumulative EIP-712 vouchers (`payload.action="voucher"`) as service streams; server verifies against on-chain channel state and settles periodically. 4. Client sends `payload.action="close"`; server calls `close(channelId, cumulativeAmount, signature)` via Hashio JSON-RPC. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` and `session` intent semantics this method implements. - [[entities/method-tempo]] — the Attribution memo byte layout used by `hedera` charge is identical to Tempo's, differing only in transport. - [[entities/method-evm]] — `hedera` session reuses the EIP-712 voucher/escrow pattern of the generic EVM session, deployed on Hedera's EVM layer. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: Lightning" type: entity tags: [methods, crypto, integrator, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-lightning-draft-lightning-charge-00-md.md", "raw/github_doc-specs-methods-lightning-draft-lightning-session-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `lightning` is MPP's payment method for the Bitcoin Lightning Network, authored by Lightspark. It settles payments in satoshis (`"sat"`) via BOLT11 invoices, using the cryptographic HTLC preimage as the proof of payment rather than an on-chain transaction. It supports both the **charge** intent (one BOLT11 invoice per request) and the **session** intent (a prepaid balance model using the deposit preimage as a bearer token, well suited to streaming/metered services). No subscription spec exists for `lightning`. ## Characteristics **Intent support:** `charge` (draft-lightning-charge-00) and `session` (draft-lightning-session-00). No `subscription`. ### Charge Single flow, no pull/push distinction: the server generates a fresh BOLT11 invoice per unauthenticated request; the client pays it on the Lightning Network and presents the **payment preimage** as the credential. Settlement is synchronous and final from the payer's perspective — the preimage is only revealed once the HTLC resolves, so verification (matching `sha256(preimage) == paymentHash`) *is* settlement; no external confirmation call is needed. Shared fields: `amount` (positive integer string, satoshis), `currency` (MUST be lowercase `"sat"`), `description` (used as the BOLT11 invoice description), `recipient` (OPTIONAL, typically unused — invoice payee is implied), `externalId`. `methodDetails.invoice` (REQUIRED, the full BOLT11 string, e.g. `"lnbc100n1..."`, authoritative for all payment parameters), `methodDetails.paymentHash` (OPTIONAL convenience, MUST match invoice), `methodDetails.network` (`"mainnet"|"regtest"|"signet"`, default mainnet). Credential payload: `{preimage: <64-char lowercase hex>}`, alongside `challenge` (echo) and optional `source` (RECOMMENDED `did:key:...` DID). Each invoice MUST use a freshly generated random payment hash — reuse would allow indefinite credential replay. Receipt `reference` field is the **payment hash**, not the preimage (the preimage is a bearer secret and must never be logged or shared as a receipt identifier). ### Session A prepaid session model, explicitly inspired by the Tempo/EVM session intent but using a different proof mechanism: a prepaid balance with the **deposit preimage as bearer token**, instead of cumulative on-chain-escrow vouchers. The server tracks a running balance (`depositSats - spent`) and deducts a configured per-chunk cost; on close it refunds any unspent balance to a client-supplied **return invoice** (a zero-amount BOLT11 invoice created at open time). Request fields: `amount` (cost per unit/chunk, satoshis), `currency` (`"sat"`), `unitType`, `depositInvoice` (CONDITIONAL — required for open/topUp challenges, absent for bearer/close), `paymentHash` (REQUIRED, hash of the deposit invoice preimage), `depositAmount` (exact deposit size; RECOMMENDED default `depositAmount = amount * 20`), `idleTimeout` (informational, RECOMMENDED server policy: 5 minutes). Credential actions: `open` (`preimage`, `returnInvoice` — a zero-amount BOLT11, ideally with expiry ≥ 2× `idleTimeout`), `bearer` (`sessionId`, `preimage` — authenticates a request without any new payment; balance deduction is handled entirely by the streaming layer, not by bearer verification), `topUp` (`sessionId`, `topUpPreimage` against a fresh invoice), `close` (`sessionId`, `preimage`; triggers `{status:"closed", refundSats, refundStatus:"succeeded"|"failed"|"skipped"}`). Streaming exhaustion emits an SSE `payment-need-topup` event (`{sessionId, balanceSpent, balanceRequired}`) and holds the connection open pending a top-up; a `session-timeout` event fires if the timeout (RECOMMENDED 60s) elapses first. ## How to Use **Charge:** 1. Server issues 402 decoding to `{amount:"100", currency:"sat", methodDetails:{invoice:"lnbc1u1p...", paymentHash:"bc230847...", network:"mainnet"}}`. 2. Client pays the BOLT11 invoice over the Lightning Network and receives the preimage upon HTLC settlement. 3. Client retries with `Authorization: Payment` encoding `{challenge, source, payload:{preimage:"a3f1...e209"}}`. 4. Server computes `sha256(preimage)`, verifies it equals the stored `paymentHash` and the challenge fields match, atomically marks the challenge consumed, and returns `200` with `Payment-Receipt` (`{method:"lightning", challengeId, reference:, status:"success", timestamp}`). **Session (open → bearer → topUp → close):** 1. Server issues 402 with a fresh `depositInvoice`/`paymentHash` and `depositAmount`. 2. Client pays the deposit invoice, obtains the preimage, and sends `payload:{action:"open", preimage, returnInvoice}`. 3. Client authenticates subsequent metered requests with `payload:{action:"bearer", sessionId:, preimage}`; the streaming layer deducts `amount` sats per chunk from the balance. 4. On exhaustion, client obtains a fresh challenge, pays a new deposit invoice, and sends `payload:{action:"topUp", sessionId, topUpPreimage}` to credit the balance; the paused stream resumes automatically. 5. Client sends `payload:{action:"close", sessionId, preimage}`; server refunds `depositSats - spent` to the `returnInvoice` and returns `{status:"closed", refundSats, refundStatus}`. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` and `session` intent semantics this method implements. - [[entities/method-tempo]] — the Tempo session intent this method's session design is explicitly modeled on, though it swaps cumulative on-chain vouchers for a prepaid preimage-as-bearer-token model. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: NEAR Intents" type: entity tags: [methods, crypto, integrator, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-nearintents-draft-nearintents-charge-01-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `nearintents` is MPP's cross-chain payment method, authored by Near One. It is the only method whose two "legs" can settle in different assets on different chains: the client deposits a source asset on an origin chain, and the NEAR Intents solver network — accessed via the hosted 1Click Swap API — delivers a deterministic amount of a destination asset to the merchant on a possibly different destination chain. Only the **charge** intent is defined; there is no session or subscription variant. ## Characteristics **Intent support:** `charge` only (draft-nearintents-charge-01), with a single settlement flow: **push mode**, `type="hash"`. There is no server-submitted ("pull") flow — the source asset must reach the 1Click deposit address before settlement, so the client always pays its own origin-chain network fee. **Cross-chain field mapping:** to stay compatible with the shared charge request schema, the top-level fields describe the client's **origin-chain payment**, while the merchant's **destination-chain delivery** lives in `methodDetails`: - `recipient` = the 1Click **deposit address** (unique per quote, controlled by the settlement system, not the merchant). - `amount`/`currency` = the source asset and deposit amount (the 1Click quote's `AmountIn`, an upper bound). - `methodDetails.originNetwork` = CAIP-2 chain where `recipient` lives. - `methodDetails.destinationNetwork`, `destinationAsset`, `destinationRecipient`, `amountOut` = the merchant's chain, asset, address, and **exact** amount received (guaranteed via the 1Click `EXACT_OUTPUT` quote mode). - `methodDetails.minAmountIn` = the actual verification threshold (not the display `amount`). - `methodDetails.refundTo` = origin-chain address that receives the deposit back on any non-success terminal state. - `methodDetails.depositMemo`, `slippageTolerance`, `timeEstimate`, `settlementBackend` (`"near-intents"`), `credentialTypes` (only `"hash"` valid). Both `currency` and `destinationAsset` are **CAIP-19** asset identifiers, e.g. `eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831` (Arbitrum USDC), `solana:5eykt.../token:EPjFWdd5Auf...` (Solana USDC), `near:mainnet/nep141:`, or `bip122:.../slip44:0` (native BTC). `originNetwork`/`destinationNetwork` are **CAIP-2** chain identifiers. **Challenge binding is unusually strong for a hash credential**: because 1Click issues a unique deposit address per quote, `recipient` is itself challenge-specific — a deposit observed there is implicitly bound to the one challenge that advertised it, unlike hash credentials on methods with a static merchant address. **Settlement finality** is defined as **destination delivery** (1Click terminal status `SUCCESS`), not origin-chain confirmation — the server MUST NOT return a `Payment-Receipt` before `SUCCESS`. Non-success terminals (`FAILED`, `REFUNDED`, `INCOMPLETE_DEPOSIT`) refund the deposit to `refundTo`; the client must obtain a fresh challenge (new quote, new deposit address) to retry. **Trust model is explicitly not trustless**: for the swap's duration, deposited funds are custodied by the NEAR Intents settlement system — comparable to trusting a payment processor — bounded by the automatic refund path on any non-success outcome. ## How to Use 1. Server requests an `EXACT_OUTPUT` quote from the 1Click Swap API for the merchant's desired `destinationAsset`/`amountOut`/`destinationNetwork`, receiving a single-use deposit address and `minAmountIn`. 2. Server issues 402: `WWW-Authenticate: Payment ... method="nearintents", intent="charge", request=` decoding to `{amount, currency, recipient:, methodDetails:{originNetwork, destinationNetwork, destinationAsset, destinationRecipient, amountOut, minAmountIn, refundTo, settlementBackend:"near-intents", credentialTypes:["hash"]}}`. 3. Client verifies `amount`/`currency`/`recipient`/`originNetwork` and the destination leg, then sends at least `minAmountIn` of `currency` to `recipient` on `originNetwork`. 4. Client submits `{challenge, payload:{type:"hash", hash:}, source:"did:pkh::
"}`. 5. Server confirms the deposit on-chain (or via the 1Click status endpoint), claims the hash as in-flight, notifies 1Click, and polls the 1Click status endpoint to a terminal state. On `SUCCESS`, returns `Payment-Receipt` (`{method:"nearintents", challengeId, reference:, status:"success", originTxHash, destinationNetwork, externalId}`) and permanently consumes the hash. On `FAILED`/`REFUNDED`, returns a `settlement-failed` error; on `INCOMPLETE_DEPOSIT`, `payment-insufficient` — in both cases the client must start over with a fresh challenge. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` intent semantics this method implements, extended here with a cross-chain destination leg. - [[entities/method-usdc]] — USDC's Gateway Transfer profile is another cross-chain charge path (via Circle Gateway rather than a solver network), useful for comparison. - [[entities/method-solana]] — one of several chains that can serve as either the origin or destination leg via CAIP-19 identifiers. - [[entities/method-evm]] — likewise a common origin/destination chain family for this method's cross-chain legs. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: Solana" type: entity tags: [methods, crypto, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-solana-draft-solana-charge-00-md.md", "raw/github_doc-specs-methods-solana-draft-solana-session-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `solana` is MPP's payment method for the Solana blockchain, authored by the Solana Foundation. It settles native SOL or SPL token (including Token-2022) transfers, taking advantage of Solana's sub-second finality and low fees for micropayment use cases. It supports both the **charge** intent (one-time payment, including an optional confidential-transfer profile) and the **session** intent (streaming payment channel via an on-chain channel program). No subscription spec exists for `solana`. ## Characteristics **Intent support:** `charge` (draft-solana-charge-00) and `session` (draft-solana-session-00). No `subscription`. ### Charge Two base credential types plus a confidential-transfer extension: - **Pull mode** (default), `type="transaction"`: client signs the transaction, server broadcasts (enables fee sponsorship). Max 1232 bytes decoded, versioned transaction. - **Push mode** (fallback), `type="signature"`: client broadcasts itself, presents the base58-encoded transaction signature; MUST NOT be used when `feePayer:true`. - **Confidential** (optional profile), `type="bundle"`: an ordered array of signed transactions implementing a Token-2022 Confidential Transfer, since validity/equality/range proofs are too large to fit in one transaction with the transfer itself. The server (as recipient) confirms the amount by decrypting its own confidential account balance with its own ElGamal key — the amount never appears in cleartext on-chain. Shared fields: `amount` (base units, fits uint64), `currency` (`"sol"` for native SOL, or base58 mint address for SPL, e.g. `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` for USDC), `recipient` (base58 pubkey; for SPL, the *owner* of the destination ATA, not the ATA itself), `externalId` (≤566 bytes, carried in a Memo Program instruction). `methodDetails`: `network` (`"mainnet"|"devnet"|"localnet"`, default mainnet), `decimals` (required when `currency` is a mint), `tokenProgram` (`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA` for legacy SPL Token, or `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb` for Token-2022), `feePayer`/`feePayerKey` (server-sponsored fees), `splits` (max 8, with optional `ataCreationRequired`), `recentBlockhash` (advisory), `confidential` (boolean; requires Token-2022 mint with `ConfidentialTransferMint` extension, `type="bundle"`, and forbids `splits`). ### Session An on-chain **channel program** manages escrow via PDAs. Channel state fields include `discriminator`, `version`, `bump`, `status` (`Open|Closing|Sealed|Distributed`), `salt`, `deposit`, `settled`, `payoutWatermark`, `closureStartedAt`, `payerWithdrawnAt`, `gracePeriod`, `distributionHash`, `payer`, `payee`, `authorizedSigner`, `mint`, `rentPayer`, `openSlot`. `channelId` is the base58 channel PDA address, derived deterministically from payer/payee/mint/salt/authorizedSigner/`openSlot`. Instructions: `open`, `settle` (permissionless, Ed25519-precompile-verified voucher), `topUp`, `requestClose`, `seal` (permissionless post-grace crank), `settleAndSeal` (payee-initiated cooperative close), `distribute` (permissionless payout per committed `distributionSplits`), `withdrawPayer`, `reclaim` (permissionless PDA rent recovery, gated by `OPEN_SLOT_WINDOW = 1500` slots ≈ 10 min at 400ms). Voucher signer mode is `client` (default) or `operator` (server signs vouchers after verifying a reusable session bearer proof). Native SOL is unsupported for sessions — clients must wrap to wSOL (`So11111111111111111111111111111111111111112`) first. Request fields: `amount` (price per unit, not total), `unitType`, `suggestedDeposit`, `minimumDeposit`, `recipient`, `currency` (SPL mint only). `methodDetails.network`, `channelProgram` (REQUIRED), `channelId` (OPTIONAL resume), `recentBlockhash`/`recentSlot` (conditionally required for new channels), `decimals`, `tokenProgram`, `feePayer`/`feePayerKey`, `voucherSigner`, `operator`, `minVoucherDelta`, `ttlSeconds`, `idleTimeoutOptionsSeconds`/`idleTimeoutSeconds`, `gracePeriodSeconds` (RECOMMENDED 900), `distributionSplits` (`{recipient, shareBps}`, ≤10000 bps total). Credential actions: `open`, `voucher` (client mode), `use` (operator mode, echoes a reusable session bearer proof), `topUp`, `close`. ## How to Use **Charge (pull mode, SPL token):** 1. Server issues 402 with `request` decoding to `{amount, currency:, recipient, methodDetails:{network, decimals, tokenProgram}}`. 2. Client builds a `TransferChecked` instruction to the recipient's associated token account, signs the transaction (as fee payer, or with the server's `feePayerKey` set if `feePayer:true`), and submits `{challenge, payload:{type:"transaction", transaction:}}`. 3. Server (co-signs if sponsoring gas, then) simulates, broadcasts via `sendTransaction`, waits for confirmation, fetches the confirmed transaction via `getTransaction`, verifies transfer details, and returns `Payment-Receipt` with `reference` = the transaction signature. **Session (open → voucher → close):** 1. Server issues 402 with `intent="session"`, `channelProgram`, `network`, `recentBlockhash`/`recentSlot`. 2. Client derives `channelId` from the PDA seeds (including a chosen `openSlot`), submits the `open` instruction, and sends `payload.action="open"` with the channel descriptor. 3. Client (or operator, per `voucherSigner`) signs successive cumulative vouchers Borsh-encoded and verified via Solana's native `ed25519` precompile; server calls the permissionless `settle` crank periodically. 4. Client sends `payload.action="close"`; server (or anyone) calls `settleAndSeal` then `distribute` to pay out splits, refund the payer, and reclaim rent. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` and `session` intent semantics this method implements. - [[entities/method-usdc]] — USDC's Solana profile restricts this method to the legacy SPL Token program only. - [[entities/method-evm]] — the analogous EVM crypto rail with its own charge/session pair and Permit2-based session escrow. - [[entities/method-near-intents]] — cross-chain settlement can originate or terminate on Solana via CAIP-19 asset identifiers. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: Stellar" type: entity tags: [methods, crypto, integrator, emerging] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-stellar-draft-stellar-charge-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `stellar` is MPP's payment method for the Stellar blockchain, authored by the Stellar Development Foundation. It settles one-time SEP-41 token transfers (a standard smart-contract token interface, including Stellar Asset Contracts / SAC) on Stellar's Soroban smart contract platform, with optional server-sponsored transaction fees. Only the **charge** intent is defined — no session or subscription spec exists for `stellar` in this raw set. ## Characteristics **Intent support:** `charge` only (draft-stellar-charge-00). **Two credential types:** - **Pull mode** (default), `type="transaction"`: client signs the transaction (or, when sponsored, only authorization entries) and the server submits it. Enables fee sponsorship and server-side retry logic. - **Push mode** (fallback), `type="hash"`: client broadcasts itself and presents the transaction hash. MUST NOT be used when `feePayer:true`. **Shared fields:** `amount` (stringified non-negative integer in the SEP-41 token's base units, e.g. `"100000"` for 0.01 USDC at 7 decimals), `currency` (C-prefixed Stellar smart contract ID — the SEP-41 token contract address), `recipient` (Stellar account address), `description`, `externalId`. **Method details:** `methodDetails.network` (REQUIRED CAIP-2 identifier: `stellar:pubnet` or `stellar:testnet`), `methodDetails.feePayer` (OPTIONAL boolean, default `false`). **Sponsored flow (`feePayer:true`):** client obtains `currentLedger` via Stellar RPC `getLatestLedger`, builds an `invokeHostFunction` transaction with the **all-zeros source account** (`GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF`) calling `transfer(from, to, amount)`, and signs only the **authorization entries** using credential type `sorobanCredentialsAddress` (not the full transaction). The server rebuilds the transaction with itself as source account and submits it. **Unsponsored flow:** client builds a fully signed, network-ready transaction (valid sequence number, fee, `timeBounds`) and the server submits it unmodified. **Ledger expiration:** Stellar uses ledger sequence numbers, not wall-clock time, for expiry. `ledgerExpiration = currentLedger + ceil((expires - now) / DEFAULT_LEDGER_CLOSE_TIME)` where `DEFAULT_LEDGER_CLOSE_TIME = 5` seconds and `DEFAULT_CHALLENGE_EXPIRY = 5` minutes (used when `expires` is absent). **Verification (both flows):** exactly one `invokeHostFunction` operation of function type `hostFunctionTypeInvokeContract` calling `transfer(from, to, amount)` on the contract matching `currency`, with `to == recipient` and `amount` (as i128) matching the challenge; network passphrase matches `methodDetails.network`; the server MUST simulate the transaction via Stellar RPC and reject any simulation showing unexpected balance changes. **Error codes:** in addition to base MPP problem types, this method defines `settlement-failed` (HTTP 402) for a verified credential whose on-chain settlement subsequently fails. ## How to Use **Sponsored pull-mode charge:** 1. Server issues 402 with `WWW-Authenticate: Payment ... method="stellar", intent="charge", request=` decoding to `{amount, currency:, recipient, methodDetails:{network:"stellar:testnet", feePayer:true}}`. 2. Client fetches `currentLedger`, computes the authorization-entry expiration, builds the all-zeros-source `invokeHostFunction` transaction calling `transfer`, and signs only the authorization entries. 3. Client submits `{challenge, payload:{type:"transaction", transaction:}, source:"did:pkh:stellar:testnet:GABC..."}`. 4. Server verifies (challenge match, single invoke operation, correct `transfer` args, simulation shows only the expected balance deltas, source is all-zeros, no server address in `from`/authorization entries), rebuilds with itself as source, signs, submits via Stellar RPC `sendTransaction`, polls to `SUCCESS`/`FAILED`, and returns `Payment-Receipt` (`{method:"stellar", reference:, status:"success", timestamp}`) on success or a `settlement-failed` error on chain failure. **Push-mode (unsponsored) charge:** client builds and fully signs the transaction itself, submits `{payload:{type:"hash", hash:<64-hex-char tx hash>}}`; server fetches via `getTransaction`, verifies status `SUCCESS` and the `transfer` call args, and returns the receipt. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` intent semantics this method implements. - [[entities/method-evm]] — the closest analogue: an EIP-3009/authorization-style sponsored-fee credential path on a different smart-contract platform. - [[entities/method-solana]] — another high-throughput, low-fee crypto rail with a comparable pull/push charge split. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: Stripe" type: entity tags: [methods, fiat, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-stripe-draft-stripe-charge-00-md.md", "raw/github_doc-specs-methods-stripe-draft-stripe-subscription-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `stripe` is MPP's fiat payment method, co-authored by Tempo Labs and Stripe. It settles one-time and recurring fiat payments through Stripe's existing processing rails using **Shared Payment Tokens (SPTs)** — single-use tokens (prefixed `spt_`) that abstract away underlying payment method details (cards, bank accounts, wallets) so neither the client nor MPP protocol layer handles raw payment credentials. It supports both the **charge** intent (one-time payment) and the **subscription** intent (a constrained Stripe Billing profile). No session spec exists for `stripe`. ## Characteristics **Intent support:** `charge` (draft-stripe-charge-00) and `subscription` (draft-stripe-subscription-00). No `session`. ### Charge Both Client and Server require a Stripe account. The client creates an SPT via `stripe.sharedPayment.issuedTokens.create({payment_method, usage_limits:{currency, max_amount, expires_at}, seller_details:{networkId}})`. Shared fields: `amount` (smallest currency unit string, e.g. `"5000"` = $50.00), `currency` (three-letter ISO code, e.g. `"usd"`), `description`, `externalId`, `recipient` (OPTIONAL). `methodDetails.networkId` (REQUIRED, Stripe Business Network Profile ID, e.g. `profile_1MqDcVKA5fEO2tZvKQm9g8Yj`), `methodDetails.paymentMethodTypes` (REQUIRED array, e.g. `["card","link"]`), `methodDetails.metadata` (OPTIONAL). Credential payload: `{spt: "spt_...", externalId}`. Server settles by creating a Stripe `PaymentIntent` with `confirm:true` and `shared_payment_granted_token: credential.spt`, using an idempotency key `${challenge.id}_${credential.spt}`. Servers MAY layer Stripe Connect parameters (`Stripe-Account`/`stripeAccount`, `application_fee_amount`, `on_behalf_of`, `transfer_data[destination]`/`[amount]`, `transfer_group`) as **server-controlled settlement policy**, never as client-supplied request fields. ### Subscription A deliberately **constrained** profile of Stripe Billing that models only the recurring transfer agreement, not the full Stripe Billing object surface (no trials, prorations, discounts, usage-based billing, quantity changes, or schedule changes — servers MUST reject or disable these). Request fields: `amount` (fixed per-period), `currency`, `periodUnit` (MUST be `"day"|"week"|"month"`), `periodCount` (positive integer string), `description`, `externalId`; `recipient` and `subscriptionExpires` MUST NOT be present (the merchant is identified by the challenged Stripe account + `networkId` instead). `methodDetails.networkId`, `methodDetails.paymentMethodTypes` (must support synchronous first-invoice activation *and* future off-session charges), `methodDetails.metadata`. Servers MUST create the Stripe Subscription with `collection_method=charge_automatically`, `payment_behavior=error_if_incomplete`, `proration_behavior=none`, exactly one item at `quantity=1`, and none of: `add_invoice_items`, non-immediate `billing_cycle_anchor`, `backdate_start_date`, `cancel_at`/`cancel_at_period_end` at activation, `pending_invoice_item_interval`, or a subscription schedule. Activation succeeds only if the **first invoice is paid synchronously**; if it requires customer action or async settlement, the server MUST treat activation as failed (fresh 402), never exposing a pending-subscription state. Credential payload: `{paymentMethod: "pm_...", customer: "cus_..." (OPTIONAL)}`. Renewal periods are mapped from a canonical billing anchor (the first paid invoice's period start) + `periodUnit`/`periodCount`; servers must durably record paid invoices keyed by canonical billing-period index to prevent duplicate charges from webhook retries. Cancellation defaults to effective-at-period-end. ## How to Use **Charge:** 1. Server issues 402 decoding to `{amount:"5000", currency:"usd", description, methodDetails:{networkId, paymentMethodTypes:["card","link"]}}`. 2. Client creates an SPT via the Stripe API scoped to that `networkId`, amount, and currency. 3. Client submits `{challenge, payload:{spt:"spt_1N4Zv32eZvKYlo2CPhVPkJlW"}}`. 4. Server verifies challenge binding, creates a `PaymentIntent` with `confirm:true` using the SPT, checks `status=="succeeded"`, and returns `Payment-Receipt` (`{method:"stripe", reference:, status:"success", timestamp}`). **Subscription (activation):** 1. Server issues 402 with `intent="subscription"` decoding to `{amount:"5000", currency:"usd", periodUnit:"week", periodCount:"1", methodDetails:{networkId, paymentMethodTypes:["card","link"]}}`. 2. Client collects a reusable Stripe PaymentMethod (with any mandate/setup required for future off-session charges) and submits `{payload:{paymentMethod:"pm_...", customer:"cus_..."}}`. 3. Server creates/reuses the Customer, Price, and Subscription per the constrained profile above, confirms the first invoice is paid, and returns `Payment-Receipt` including `subscriptionId` and `stripeSubscription`. 4. On each later period, the server validates the Stripe renewal invoice against the canonical billing period before granting access and issuing another receipt. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` and `subscription` intent semantics this method implements. - [[entities/method-card]] — MPP's other fiat rail, using encrypted network tokens instead of Shared Payment Tokens. - [[entities/method-tempo]] — the only other method with its own `subscription` profile, using on-chain access-key spending limits instead of Stripe Billing. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: Tempo" type: entity tags: [methods, crypto, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-tempo-draft-tempo-charge-00-md.md", "raw/github_doc-specs-methods-tempo-draft-tempo-session-00-md.md", "raw/github_doc-specs-methods-tempo-draft-tempo-subscription-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `tempo` is MPP's payment method for the Tempo blockchain — the chain built by Tempo Labs, MPP's co-author alongside Stripe. It settles **TIP-20** tokens, Tempo's enshrined token standard implemented as precompiles (6 decimal places; `transfer`, `transferWithMemo`, `transferFrom`, `approve`), using **Tempo Transactions** (EIP-2718 type `0x76`, supporting batched calls, multiple signature types — secp256k1, P256, WebAuthn — 2D nonces, and validity windows). It is the only crypto method with specs for all three intents: **charge**, **session**, and **subscription**. ## Characteristics **Intent support:** `charge` (draft-tempo-charge-00), `session` (draft-tempo-session-00), `subscription` (draft-tempo-subscription-00) — all three. **Note on default `chainId`:** the charge and subscription specs both state `methodDetails.chainId` defaults to **42431**, while the session spec states a default of **4217**; the charge spec's own worked examples use `4217`. This inconsistency exists verbatim in the source drafts and should be treated as method/version-specific rather than assumed uniform. ### Charge Two non-zero submission modes, negotiated via `methodDetails.supportedModes` (`["pull"]`, `["push"]`, or both; servers SHOULD support `pull`): `type="transaction"` (pull, client signs RLP-encoded Tempo Transaction type `0x76`, server broadcasts) or `type="hash"` (push, client broadcasts and presents the tx hash; MUST NOT be used with `feePayer:true`). For **zero-amount** charges, mode negotiation doesn't apply — clients MUST use `type="proof"`, an EIP-712 signature over `{domain:{name:"MPP",version:"1",chainId}, types:{Proof:[{name:"challengeId",type:"string"}]}, message:{challengeId}}`, binding the signature to exactly one challenge with no on-chain transfer. Shared fields: `amount`, `currency` (TIP-20 token address, e.g. `"0x20c0..."`), `recipient`. `methodDetails.chainId` (OPTIONAL), `methodDetails.feePayer` (server sponsors gas via a separate `0x78` fee-payer signature domain), `methodDetails.memo` (bytes32, forces `transferWithMemo`), `methodDetails.splits` (max 10, ~29,000 gas each, sum MUST be strictly less than `amount`). ### Session Two protocol versions selected via `methodDetails.sessionProtocol`: `"v1"` (legacy contract-backed `TempoStreamChannel`, `channelId = keccak256(abi.encode(payer,payee,token,salt,authorizedSigner,address(this),block.chainid))`) or `"v2"` (TIP-20 channel escrow **precompile**, adds an `operator` and `expiringNonceHash` to the channel descriptor and uses **uint96** amounts instead of uint128; `channelId` additionally binds `operator` and `expiringNonceHash`). If `sessionProtocol` is absent, clients MAY treat the challenge as v1. Contract functions: `open`, `settle`, `topUp`, `close`, `requestClose`, `withdraw`. Voucher EIP-712 domain name is `"Tempo Stream Channel"` (v1) or `"TIP20 Channel Reserve"` (v2); type `Voucher(bytes32 channelId, uint128 cumulativeAmount)` (v1) or with `uint96 cumulativeAmount` (v2). `methodDetails.escrowContract`, `channelId` (resume), `minVoucherDelta`, `chainId`, `operator` (v2), `sessionSnapshot` (v2 reusable-channel state, also deliverable via a `Payment-Session-Snapshot` response header). Fee sponsorship for `open`/`topUp` uses the same client-places-`0x00`-placeholder + server-signs-`0x78` pattern as charge; `settle`/`close` are always server-paid regardless of `feePayer`. ### Subscription Models a recurring **TIP-20 transfer authorization** via a recipient-scoped **access key** registered on the **AccountKeychain precompile**, not a richer billing object (no price catalogs, quantities, prorations, or anchor resets). Requires **TIP-1011** (periodic token-limit + `allowed_calls` scoping) and **TIP-1020** (signature verification precompile), both introduced in the Tempo **T3** network upgrade — servers MUST NOT issue `subscription` challenges on pre-T3 deployments. Unlike the shared subscription intent's optional expiry, Tempo requires an explicit **`subscriptionExpires`** (RFC 3339) because the underlying key authorization is time-bounded, and it MUST be strictly later than the challenge's own `expires`. Request fields: `amount`, `currency`, `periodUnit` (MUST be `"day"` or `"week"` — **not** `"month"`, since TIP-1011 periods are fixed elapsed-time), `periodCount`, `subscriptionExpires` (REQUIRED), `recipient`. `methodDetails.accessKey.accessKeyAddress`/`keyType` (`p256|secp256k1|webAuthn`), `methodDetails.chainId` (default 42431). Period mapping: `day` → `periodCount*86400` seconds, `week` → `periodCount*604800` seconds. The signed key authorization (credential `type="keyAuthorization"`, RLP-serialized, hex-encoded) MUST configure: the exact access key, a `TokenLimit` for `currency` with `amount` = challenge amount and `period` = mapped seconds, exactly one `allowed_calls` target scope for `currency` with explicit selectors for `transfer(address,uint256)` (`0xa9059cbb`) and optionally `transferWithMemo(address,uint256,bytes32)` (`0x95777d59`), and a recipient allowlist containing only the challenge `recipient` — never `approve` or unrestricted target mode. Activation registers the key and collects the first period's charge atomically in one transaction; TIP-1011 periodic limits reset (don't accumulate) across missed periods. ## How to Use **Charge (pull mode):** server issues 402 with `methodDetails.supportedModes:["pull"]`; client signs a Tempo Transaction calling `transfer`/`transferWithMemo` and submits `{payload:{type:"transaction", signature:<0x76-prefixed RLP hex>}}`; server broadcasts via `eth_sendRawTxSync` (~500ms finality) and returns `Payment-Receipt`. **Session (v2, open → voucher → close):** server issues 402 with `methodDetails.sessionProtocol:"v2"`, `escrowContract`, `chainId`; client submits `payload.action="open"` with a signed open transaction plus the v2 `descriptor`; client signs successive cumulative vouchers (`payload.action="voucher"`) as service streams; client sends `payload.action="close"` to trigger on-chain settlement and refund. **Subscription (activation):** server issues 402 decoding to `{amount:"10000000", currency, periodUnit:"day", periodCount:"30", subscriptionExpires:"2026-07-14T12:00:00Z", recipient, methodDetails:{accessKey:{accessKeyAddress, keyType:"p256"}}}`; client signs a key authorization scoping `transfer` to `recipient` with the matching `TokenLimit` and submits `{payload:{type:"keyAuthorization", signature:}}`; server broadcasts a transaction registering the key and executing the first `transfer(recipient, amount)` atomically; on each later period the server submits one `transfer` call using the registered key. ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge`, `session`, and `subscription` intent semantics this method implements. - [[entities/method-hedera]] — its charge attribution memo and session escrow pattern are directly derived from Tempo's. - [[entities/method-lightning]] — its session design (prepaid balance, bearer credential, refund on close) is explicitly modeled on this method's session intent. - [[entities/method-evm]] — the generic EVM session spec adapts this method's streaming-channel mechanism for any EVM chain. - [[entities/method-stripe]] — the only other method with a `subscription` spec, using Stripe Billing instead of on-chain access keys. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "Method: USDC" type: entity tags: [methods, crypto, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-usdc-draft-usdc-charge-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview `usdc` is Circle's USDC-specific payment method, giving merchants **one USDC acceptance surface** across multiple chain families rather than requiring them to integrate `evm`, `solana`, and other chain methods separately. It is not a new generic chain method — it *profiles* the existing EVM and Solana charge specs down to a restricted USDC-only subset, and directly defines two profiles that have no generic MPP chain method to inherit from: USDCx on Stacks (backed 1:1 by USDC via Circle xReserve) and cross-chain **Gateway Transfer** (via Circle Gateway, letting a payer on one chain fund USDC delivered on another). Only the **charge** intent is defined; there is no session or subscription spec. ## Characteristics **Intent support:** `charge` only, with **four profiles** selected by `methodDetails.type`: `evm`, `solana`, `stacks`, `gateway`. The `methodDetails` object MUST contain exactly one profile object matching `type` (e.g. `type:"solana"` requires `methodDetails.solana` and forbids `methodDetails.evm`/`stacks`/`gateway`). This nested-by-type shape intentionally differs from the flat `methodDetails` of the base `evm`/`solana` charge specs — a generic EVM/Solana verifier will not parse `usdc` credentials and vice versa. Shared fields: `amount` (USDC base units), `currency` (direct profiles use the chain-native token identifier; Gateway Transfer uses the literal string `"usdc"`), `recipient`, `description`, `externalId`. **EVM profile:** inherits `evm-charge`, restricted to `payload.type="authorization"` (EIP-3009) only — no Permit2, raw transaction, or hash types (use `method="evm"` directly for those). `methodDetails.evm.chainId`, `decimals` (MUST be `6`). The EIP-3009 **nonce derivation is overridden** to also bind `method`, `intent`, and a `requestHash` (not just `challenge.id`/`realm` as in base `evm`), so `usdc` EVM credentials are **not interchangeable** with `method="evm"` credentials even on the same chain. **Solana profile:** inherits `solana-charge`, restricted to `payload.type="transaction"` (pull mode only) and the **legacy SPL Token program** (`TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`) — Token-2022 is out of scope in v00. `methodDetails.solana.network`, `decimals` (`6`), `tokenProgram`, `feePayer`/`feePayerKey`. Verification allows only SPL transfer, ATA setup, bounded Compute Budget, and optional Memo instructions — no delegate/multisig authority flows. **Stacks profile:** the one profile with **no generic MPP chain method to inherit from**; defined directly using SIP-005 consensus-serialized transactions and SIP-010 `transfer`. `currency` is the full SIP-010 identifier `.::`; the mainnet USDCx token is `SP120SBRBQJ00MCWS7TM5R8WJNTTKD5K0HFRC2CNE.usdcx::usdcx-token`. `methodDetails.stacks.network` (`mainnet|testnet`), `chainId` (`1` or `2147483648`), `contractAddress`/`contractName`/`assetName`, `functionName` (MUST be `transfer`), `decimals:6`, `feePayer`/`feePayerAddress` (Stacks sponsored-transaction authorization). Requires exactly one `FungiblePostCondition` with `condition_code=SentEq` and `post_condition_mode=Deny`. **Gateway Transfer profile:** cross-chain, via Circle Gateway. Merchant fixes `destinationNetwork`; payer selects one `sourceNetwork` from the merchant's advertised `methodDetails.gateway.acceptedSources` (CAIP-2 identifiers). `methodDetails.gateway.maxFee` (absolute fee cap in USDC base units, separate from `amount`), `maxFeeBps` (optional ratio cap), `credentialTypes` (only `"transfer"`). Every Gateway TransferSpec MUST carry a **challenge-bound salt** — `keccak256` of a JCS-canonicalized object binding `id`, `method`, `realm`, `intent`, `type`, `requestHash`, source/destination networks, depositor/signer/recipient, amount, and `maxFee` — so a Gateway authorization cannot be replayed across challenges. Settlement is complete only once Circle Gateway reports **destination** settlement (not merely submitted/attested/pending). **Receipt** uses a single CAIP-2 `network` field across all four profiles (deliberately unlike base `evm`'s numeric `chainId` or `solana`'s absent network field), plus `type` (the active profile) and profile-specific `reference` (EVM tx hash, Solana signature, Stacks tx ID, or Gateway destination settlement reference). ## How to Use **EVM direct charge:** server issues 402 decoding to `{amount:"1000000", currency:, recipient, methodDetails:{type:"evm", evm:{chainId, decimals:6, credentialTypes:["authorization"]}}}`; client signs an EIP-3009 authorization with `to==recipient`, `value==amount`, and `nonce` = the `usdc`-specific derivation (binding `method`, `intent`, challenge id/realm, `requestHash`); submits `{payload:{type:"authorization", from, to, value, validAfter, validBefore, nonce, signature}}`; server submits `transferWithAuthorization` and pays gas. **Gateway Transfer charge:** server issues 402 with `methodDetails:{type:"gateway", gateway:{acceptedSources, destinationNetwork, maxFee}}`; client picks a `sourceNetwork` from `acceptedSources`, signs a Circle Gateway authorization whose TransferSpec `salt` equals the challenge-bound salt and whose `value` equals `request.amount`; submits `{payload:{type:"transfer", sourceNetwork, destinationNetwork, maxFee, authorization:}}`; server verifies the salt binding and fee caps, submits to Circle Gateway, waits for destination settlement, and returns `Payment-Receipt` with `network = destinationNetwork` and an optional `gateway` audit object (`transferId`, `transferSpecHash`). ## Related Entities - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme. - [[concepts/payment-intents]] — defines the shared `charge` intent semantics this method profiles across four chain families. - [[entities/method-evm]] — the generic EVM charge method this method's `evm` profile restricts to EIP-3009 `authorization` credentials only. - [[entities/method-solana]] — the generic Solana charge method this method's `solana` profile restricts to the legacy SPL Token program. - [[entities/method-near-intents]] — an alternative cross-chain settlement path (via a solver network rather than Circle Gateway). - [[entities/method-card]] — MPP's fiat USD rail, for comparison against USDC's crypto-settled USD-denominated payments. - [[entities/methods-catalog]] — hub page comparing all MPP payment methods. --- title: "MPP Methods Catalog" type: entity tags: [methods, overview, integrator, well-established] created: 2026-08-10 updated: 2026-08-10 sources: ["raw/github_doc-specs-methods-card-draft-card-charge-00-md.md", "raw/github_doc-specs-methods-evm-draft-evm-charge-00-md.md", "raw/github_doc-specs-methods-evm-draft-evm-session-00-md.md", "raw/github_doc-specs-methods-solana-draft-solana-charge-00-md.md", "raw/github_doc-specs-methods-solana-draft-solana-session-00-md.md", "raw/github_doc-specs-methods-stellar-draft-stellar-charge-00-md.md", "raw/github_doc-specs-methods-hedera-draft-hedera-charge-00-md.md", "raw/github_doc-specs-methods-hedera-draft-hedera-session-00-md.md", "raw/github_doc-specs-methods-lightning-draft-lightning-charge-00-md.md", "raw/github_doc-specs-methods-lightning-draft-lightning-session-00-md.md", "raw/github_doc-specs-methods-nearintents-draft-nearintents-charge-01-md.md", "raw/github_doc-specs-methods-stripe-draft-stripe-charge-00-md.md", "raw/github_doc-specs-methods-stripe-draft-stripe-subscription-00-md.md", "raw/github_doc-specs-methods-tempo-draft-tempo-charge-00-md.md", "raw/github_doc-specs-methods-tempo-draft-tempo-session-00-md.md", "raw/github_doc-specs-methods-tempo-draft-tempo-subscription-00-md.md", "raw/github_doc-specs-methods-usdc-draft-usdc-charge-00-md.md"] confidence: high mpp_snapshot: "2026-08-10" --- ## Overview MPP is payment-method agnostic: each payment rail ships as a plugin implementing one or more of the shared intents (`charge`, `session`, `subscription`) defined by [[concepts/mpp-overview]]. This page is the hub for all 10 payment methods currently specified in the mpp-specs repository, grouped by settlement type (crypto vs. fiat), with each method's intent support so it can be compared and cross-checked at a glance. ## Methods Table ### Crypto-Settled Methods | Method | Settles In | Charge | Session | Subscription | Page | |---|---|:---:|:---:|:---:|---| | EVM | ERC-20 tokens, any EIP-155 chain | Yes | Yes | No | [[entities/method-evm]] | | Solana | Native SOL / SPL tokens | Yes | Yes | No | [[entities/method-solana]] | | Stellar | SEP-41 tokens (Soroban) | Yes | No | No | [[entities/method-stellar]] | | Hedera | HTS tokens | Yes | Yes | No | [[entities/method-hedera]] | | Bitcoin Lightning | Satoshis (BOLT11) | Yes | Yes | No | [[entities/method-lightning]] | | NEAR Intents | Cross-chain (solver-settled) | Yes | No | No | [[entities/method-near-intents]] | | Tempo | TIP-20 tokens (Tempo chain) | Yes | Yes | Yes | [[entities/method-tempo]] | | USDC | USDC across EVM / Solana / Stacks / Gateway | Yes | No | No | [[entities/method-usdc]] | ### Fiat-Settled Methods | Method | Settles In | Charge | Session | Subscription | Page | |---|---|:---:|:---:|:---:|---| | Card | Card networks (Visa, Mastercard, Amex, Discover) | Yes | No | No | [[entities/method-card]] | | Stripe | Fiat via Stripe processing | Yes | No | Yes | [[entities/method-stripe]] | ## Notes on Intent Coverage - **Tempo** is the only method with specs for all three intents (`charge`, `session`, `subscription`) — unsurprising, since Tempo Labs co-authored MPP itself. - **Session** support exists only on methods with on-chain escrow/channel primitives: EVM, Solana, Hedera (deployed on its EVM layer), Lightning (via a prepaid-balance analogue rather than on-chain escrow), and Tempo. Card, Stellar, NEAR Intents, Stripe, and USDC have no session spec. - **Subscription** support exists only on Stripe (via a constrained Stripe Billing profile) and Tempo (via on-chain access-key spending limits). No crypto method besides Tempo defines subscriptions. - **USDC** and **NEAR Intents** are structurally distinct from the other crypto methods: USDC is a cross-chain-family *overlay* that profiles/restricts the EVM and Solana methods (plus Stacks and Circle Gateway) down to a USDC-only surface, while NEAR Intents is a genuinely cross-chain method whose origin and destination legs can be different chains and different assets, settled by a solver network rather than a single ledger. - Every method inherits challenge/credential/receipt structure from the base [[concepts/payment-http-auth-scheme]] and the relevant intent spec in [[concepts/payment-intents]]; each entity page above documents only the method-specific `methodDetails`, credential payload, and verification/settlement procedure. ## Related Entities - [[concepts/mpp-overview]] — the protocol-level overview this catalog supports. - [[concepts/payment-http-auth-scheme]] — the base `Payment` HTTP authentication scheme all methods implement. - [[concepts/payment-intents]] — the shared `charge`/`session`/`subscription` intent definitions each method profiles. - [[entities/method-card]], [[entities/method-evm]], [[entities/method-solana]], [[entities/method-stellar]], [[entities/method-hedera]], [[entities/method-lightning]], [[entities/method-near-intents]], [[entities/method-stripe]], [[entities/method-tempo]], [[entities/method-usdc]] — the 10 method entity pages. # Change Log ## 2026-08-10 — Initial build Built from the MPP spec repo (tempoxyz/mpp-specs, snapshot 2026-08-10) plus the Rust SDK (mpp-rs), the awesome-mpp community registry, and the mpp.dev overview. MPP is an open machine-to-machine payments standard (Tempo + Stripe) that standardizes HTTP 402 via a "Payment" HTTP authentication scheme. **Pages (19):** 8 concepts + 11 entities (10 payment methods + a catalog hub). **Sourcing notes:** - **Early / draft-00**: every spec is an IETF-style draft, actively moving (repo pushed 2026-08-10). Pinned via `mpp_snapshot`. - Core normative surface captured verbatim: headers (`WWW-Authenticate: Payment`, `Authorization: Payment`, `Payment-Receipt`, `Accept-Payment`), challenge params (`id`/`realm`/`method`/`intent`/`request`), status codes (402/401/403), problem-type codes, and the MCP-transport error codes (-32042/-32043) + `_meta` keys. - Method support matrix (charge/session/subscription) recorded per method; session-less/subscription-less methods reflect the absence of such drafts upstream, not a sourcing gap. - **Preserved upstream inconsistency**: the Tempo specs disagree on the default `methodDetails.chainId` (charge/subscription say 42431; session says 4217, and charge examples use 4217) — kept verbatim in method-tempo as a caveat rather than silently resolved. - `ecosystem` is confidence:medium — it rests on the single community-maintained awesome-mpp README (self-reported, x402 overlap noted). - No XL tier yet (draft-stage); per-method deep specs are the natural XL seed once the drafts stabilize.