docs(agentic-payments): production patterns for x402 + MPP - #97
Conversation
|
🤖 Automated message from Kaan's Automated Triage Bot. 👀 Picked this up — a review will follow shortly. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds practical documentation for configuring paid routes with x402 and for running MPP Charge/Session together in production without crashing on missing/mis-set secrets.
Changes:
- Document
paymentMiddlewareFromConfigfor pricing multiple x402 routes with per-route prices. - Add “Production patterns” guidance for MPP (fail-open recipient resolution, optional dual-intent setup, and an
/infodiscovery endpoint).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| skills/agentic-payments/x402.md | Adds multi-route pricing example using paymentMiddlewareFromConfig and guidance to fail open when recipient config is missing. |
| skills/agentic-payments/mpp.md | Adds production-ready patterns and example code for resilient configuration and runtime discovery. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| ## Pricing multiple routes with `paymentMiddlewareFromConfig` | ||
|
|
||
| The seller example above prices a single route through `paymentMiddleware` + |
| **Env vars (server):** `CHANNEL_CONTRACT`, `COMMITMENT_PUBKEY`, `MPP_SECRET_KEY`, `FEE_PAYER_SECRET` | ||
| **Env vars (client):** `COMMITMENT_SECRET` |
| process.env.MPP_CHANNEL_CONTRACT && | ||
| process.env.MPP_COMMITMENT_KEY && | ||
| RECIPIENT && | ||
| process.env.MPP_SECRET_KEY | ||
| ) | ||
| ? Mppx.create({ methods: [stellarChannel.channel({ channel: process.env.MPP_CHANNEL_CONTRACT, /* ... */ })] }) |
| const chargeMppx = (RECIPIENT && process.env.MPP_SECRET_KEY) | ||
| ? Mppx.create({ methods: [stellar.charge({ recipient: RECIPIENT, /* ... */ })] }) | ||
| : null; | ||
|
|
||
| const sessionMppx = ( | ||
| process.env.MPP_CHANNEL_CONTRACT && | ||
| process.env.MPP_COMMITMENT_KEY && | ||
| RECIPIENT && | ||
| process.env.MPP_SECRET_KEY | ||
| ) | ||
| ? Mppx.create({ methods: [stellarChannel.channel({ channel: process.env.MPP_CHANNEL_CONTRACT, /* ... */ })] }) | ||
| : null; |
- x402.md: drop a stray "+" line-join artifact in the multi-route pricing intro. - mpp.md: align the pre-existing server env var names to what the service actually reads (MPP_CHANNEL_CONTRACT / MPP_COMMITMENT_KEY, verified against packages/agent/src/middleware/mpp.ts) instead of weakening the new examples to match the wrong CHANNEL_CONTRACT / COMMITMENT_PUBKEY names already in the doc. - mpp.md: add the missing imports to the dual-intent snippet, and note why Channel's server adapter needs an alias (`stellarChannel`) — both it and Charge's export their namespace as `stellar`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Addressed Copilot's 4 review comments:
|
Adds three patterns verified against a service that has been billing real USDC over MPP Charge and x402 in production: - Multi-route pricing with paymentMiddlewareFromConfig (x402.md) - Recipient resolution that fails open instead of crashing on missing or misconfigured STELLAR_RECIPIENT, including recovery when a secret key lands in the public-key env var (mpp.md) - Optional dual-intent server: Charge and Session gated independently by their own env vars, each middleware no-op'ing rather than throwing when its intent isn't configured (mpp.md) - A runtime-accurate /info discovery endpoint reporting which intents are actually live, not a static capability list (mpp.md) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- x402.md: drop a stray "+" line-join artifact in the multi-route pricing intro. - mpp.md: align the pre-existing server env var names to what the service actually reads (MPP_CHANNEL_CONTRACT / MPP_COMMITMENT_KEY, verified against packages/agent/src/middleware/mpp.ts) instead of weakening the new examples to match the wrong CHANNEL_CONTRACT / COMMITMENT_PUBKEY names already in the doc. - mpp.md: add the missing imports to the dual-intent snippet, and note why Channel's server adapter needs an alias (`stellarChannel`) — both it and Charge's export their namespace as `stellar`. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
cdf7caa to
16c2d92
Compare
|
@kaankacar the merge conflict on this one is resolved — rebased onto current Separately, #103 is small and unrelated — a real bug, not a docs addition: 27 of 28 Whenever you get to either, no rush on my end. |
Fresh proposal per Kaan's note closing #14: that PR targeted files removed in the #17 restructure, so it couldn't be rebased. He confirmed the current
skills/agentic-payments/SKILL.mddoesn't yet cover four of the patterns from the old PR, and invited a fresh PR proposing them individually. This is that — re-verified against a service that's been running x402 and MPP Charge in production, not copied from the old diff.Landing against
x402.mdandmpp.md(the detail filesSKILL.mdroutes to), notSKILL.mditself, since it's a decision table and these are implementation patterns.What changed and why each one still holds up (re-checked today, not assumed from the old PR):
Multi-route pricing with
paymentMiddlewareFromConfig(x402.md) — the seller example in the skill prices a single route. This documents the config-object form for pricing several routes behind one middleware call, with the route-keyed shape and scheme/facilitator wiring spelled out. Matches what's running behind a production endpoint pricing three routes at three different amounts, cited with its first on-chain settlement.Recipient resolution that fails open (
mpp.md) — a server that throws at import time becauseSTELLAR_RECIPIENTis unset breaks CI and any environment without secrets provisioned yet. Included is a specific recovery case worth calling out on its own: a secret key (S...) landing in the public-key env var, which a platform's env UI can make easy to do by accident — recovered with a loud warning instead of a cryptic downstream throw.Optional dual-intent server (
mpp.md) — reframed from the old PR, not copied. The old version implied running Charge and Session together in production; that's not accurate today. What is true and worth documenting: each intent gets its own SDK instance, gated independently by its own env vars, with route middleware no-op'ing (not throwing) when its instance isnull. That's a real, useful pattern regardless of which intents a given deployment actually turns on./infodiscovery endpoint (mpp.md) — reports which intents are actually live by reading the same runtime state the middleware checks (e.g.!!chargeInstance), so it doubles as a health check instead of a static claim that can drift from reality.Verified:
pnpm lint:ts,pnpm lint,pnpm sync:skills, andpnpm generate:llms-txtall pass clean against the new content.Happy to split this into separate PRs per pattern if that's easier to review — bundled them here since the recipient-resolution section is referenced from the pricing section via anchor link, but they don't otherwise depend on each other.
Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com