|
| 1 | +--- |
| 2 | +layout: minimal |
| 3 | +outline: false |
| 4 | +showAskAi: false |
| 5 | +showFeedback: false |
| 6 | +showSearch: false |
| 7 | +description: "Core SDKs now expose typed payment hooks for logging, monitoring, and request context." |
| 8 | +imageDescription: "Monitor request status with SDK hooks" |
| 9 | +--- |
| 10 | + |
| 11 | +<div className="blog-narrow"> |
| 12 | + |
| 13 | +<a href="/blog" className="blog-back">Blog</a> |
| 14 | + |
| 15 | +<p className="blog-date" style={{ color: 'var(--vocs-color_text3)', fontSize: '14px' }}>Thursday, May 21, 2026</p> |
| 16 | + |
| 17 | +# Payment hooks [Observe MPP requests with typed lifecycle events] |
| 18 | + |
| 19 | +MPP's core SDKs now expose typed payment hooks for client and server payment flows. Use them to record what happened around an MPP request without rewriting your payment handler. |
| 20 | + |
| 21 | +## Why hooks matter |
| 22 | + |
| 23 | +MPP puts the payment flow close to the request flow in REST APIs and MCP servers. That makes basic integration simple, but becomes fragile when used in production applications and existing tech stacks. |
| 24 | + |
| 25 | +Hooks give you a typed place to attach that visibility: |
| 26 | + |
| 27 | +- **Monitoring and observability**: Count `Challenge`s, successful payments, failed `Credential`s, and paid retry responses, then attach `Challenge` IDs, method names, intents, amounts, currencies, and `Receipt` references to traces. |
| 28 | +- **Logging**: Record enough context to debug a failed payment without logging secrets. |
| 29 | +- **Support**: Connect a user-facing request to the payment attempt that authorized it. |
| 30 | + |
| 31 | +## What changed |
| 32 | + |
| 33 | +Server hooks observe issued Challenges, successful payments, and rejected Credentials. Use typed helpers for common events, canonical strings for direct event names, or `*` for a single catch-all handler: |
| 34 | + |
| 35 | +```ts twoslash [server.ts] |
| 36 | +import { Mppx, tempo } from 'mppx/server' |
| 37 | + |
| 38 | +const payment = Mppx.create({ |
| 39 | + methods: [tempo.charge()], |
| 40 | +}) |
| 41 | + |
| 42 | +const log = (event: string, data: Record<string, unknown>) => { |
| 43 | + console.log(event, data) |
| 44 | +} |
| 45 | + |
| 46 | +payment.onChallengeCreated(({ challenge, request }) => { // [!code hl] |
| 47 | + log('payment.challenge.created', { |
| 48 | + amount: request.amount, |
| 49 | + challengeId: challenge.id, |
| 50 | + }) |
| 51 | +}) |
| 52 | + |
| 53 | +payment.on('payment.success', ({ receipt, request }) => { // [!code hl] |
| 54 | + log('payment.success', { |
| 55 | + amount: request.amount, |
| 56 | + reference: receipt.reference, |
| 57 | + }) |
| 58 | +}) |
| 59 | + |
| 60 | +payment.onPaymentFailed(({ challenge, error, request }) => { // [!code hl] |
| 61 | + log('payment.failed', { |
| 62 | + amount: request.amount, |
| 63 | + challengeId: challenge.id, |
| 64 | + error: error.name, |
| 65 | + }) |
| 66 | +}) |
| 67 | +``` |
| 68 | + |
| 69 | +## What's next |
| 70 | + |
| 71 | +This release starts with core lifecycle events of the MPP request flow. If there is an event or payload field which you would like to monitor, please leave feedback on [GitHub](https://github.com/wevm/mppx/issues). |
| 72 | + |
| 73 | +</div> |
0 commit comments