Skip to content

Commit 5bfb1ac

Browse files
committed
docs: update mppx hooks documentation
1 parent 7140c5f commit 5bfb1ac

8 files changed

Lines changed: 314 additions & 41 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"@stripe/stripe-js": "^9.3.1",
2626
"@vercel/blob": "^2.3.3",
2727
"mermaid": "^11.14.0",
28-
"mppx": "0.6.17",
28+
"mppx": "0.6.24",
2929
"react": "^19",
3030
"react-dom": "^19",
3131
"stripe": "^22.1.0",

pnpm-lock.yaml

Lines changed: 16 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/pages/blog/index.mdx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@ imageDescription: "Updates on the Machine Payments Protocol"
1515
import { BlogPostList } from "../../components/BlogPostList";
1616

1717
<BlogPostList posts={[
18+
{
19+
date: "May 18, 2026",
20+
title: "Payment hooks",
21+
description: <>SDKs now expose typed payment hooks for logging, monitoring, and request context.</>,
22+
to: "/blog/payment-hooks",
23+
},
24+
{
25+
date: "May 12, 2026",
26+
title: "Subscriptions",
27+
description: <>Enabling recurring access for paid plans, memberships, and API tiers.</>,
28+
to: "/blog/subscriptions",
29+
},
1830
{
1931
date: "Apr 28, 2026",
2032
title: "Multi-method discovery",

src/pages/blog/payment-hooks.mdx

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
layout: minimal
3+
outline: false
4+
showAskAi: false
5+
showFeedback: false
6+
showSearch: false
7+
description: "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' }}>May 18, 2026</p>
16+
17+
# Payment hooks [Observe MPP requests with typed lifecycle events]
18+
19+
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+
Hooks are useful when payment telemetry belongs next to the rest of your application telemetry: logs, metrics, traces, audit records, support dashboards, or local debugging context.
22+
23+
## What changed
24+
25+
Client hooks observe Challenge selection, Credential creation, retry responses, and failures. Use typed helpers for common events, canonical strings for direct event names, or `*` for a single catch-all handler:
26+
27+
```ts twoslash [client.ts]
28+
import { Mppx, tempo } from 'mppx/client'
29+
import { privateKeyToAccount } from 'viem/accounts'
30+
31+
const account = privateKeyToAccount(process.env.MPP_PRIVATE_KEY as `0x${string}`)
32+
33+
const mppx = Mppx.create({
34+
methods: [tempo({ account })],
35+
polyfill: false,
36+
})
37+
38+
const log = (event: string, data: Record<string, unknown>) => {
39+
console.log(event, data)
40+
}
41+
42+
mppx.onChallengeReceived(({ challenge }) => {
43+
// Observe the selected Challenge before the SDK creates a Credential.
44+
log('payment.challenge.received', {
45+
challengeId: challenge.id,
46+
intent: challenge.intent,
47+
method: challenge.method,
48+
})
49+
return undefined
50+
})
51+
52+
mppx.on('payment.response', ({ challenge, response }) => {
53+
// Use canonical event names when you want to share event wiring.
54+
log('payment.response', {
55+
challengeId: challenge.id,
56+
status: response.status,
57+
})
58+
})
59+
60+
mppx.on('*', ({ name, payload }) => {
61+
// Use `*` to send all payment events through one telemetry path.
62+
log('payment.event', {
63+
hasChallenge: 'challenge' in payload,
64+
name,
65+
})
66+
})
67+
68+
mppx.onPaymentFailed(({ error, input }) => {
69+
// Capture failures from Challenge parsing, Credential creation, or retry handling.
70+
log('payment.failed', {
71+
error: error instanceof Error ? error.message : String(error),
72+
input: String(input),
73+
})
74+
})
75+
76+
const response = await mppx.fetch('https://api.example.com/report')
77+
```
78+
79+
Server hooks observe issued Challenges, successful payments, and rejected Credentials:
80+
81+
```ts twoslash [server.ts]
82+
import { Mppx, tempo } from 'mppx/server'
83+
84+
const payment = Mppx.create({
85+
methods: [tempo.charge()],
86+
})
87+
88+
const log = (event: string, data: Record<string, unknown>) => {
89+
console.log(event, data)
90+
}
91+
92+
payment.onChallengeCreated(({ challenge, request }) => {
93+
// Observe each `402` Challenge before it is returned to the client.
94+
log('payment.challenge.created', {
95+
amount: request.amount,
96+
challengeId: challenge.id,
97+
currency: request.currency,
98+
})
99+
})
100+
101+
payment.on('payment.success', ({ receipt, request }) => {
102+
// Use canonical event names when you want to share event wiring.
103+
log('payment.success', {
104+
amount: request.amount,
105+
currency: request.currency,
106+
reference: receipt.reference,
107+
status: receipt.status,
108+
})
109+
})
110+
111+
payment.on('*', ({ name, payload }) => {
112+
// Use `*` to send all payment events through one telemetry path.
113+
log('payment.event', {
114+
challengeId: payload.challenge.id,
115+
intent: payload.method.intent,
116+
name,
117+
})
118+
})
119+
120+
payment.onPaymentFailed(({ challenge, error, request }) => {
121+
// Record failed Credential verification with request and Challenge context.
122+
log('payment.failed', {
123+
amount: request.amount,
124+
challengeId: challenge.id,
125+
error: error.name,
126+
})
127+
})
128+
```
129+
130+
## Why hooks matter
131+
132+
MPP keeps the payment flow close to the request flow. That makes integration simple, but production systems still need visibility.
133+
134+
Hooks give you a typed place to attach that visibility:
135+
136+
- **Monitoring and observability**: Count Challenges, successful payments, failed Credentials, and paid retry responses, then attach Challenge IDs, method names, intents, amounts, currencies, and Receipt references to traces.
137+
- **Logging**: Record enough context to debug a failed payment without logging secrets.
138+
- **Support**: Connect a user-facing request to the payment attempt that authorized it.
139+
140+
## Use hooks carefully
141+
142+
Client observation hooks don't change payment handling. If a client observation hook throws, `mppx` ignores the error and continues the payment flow.
143+
144+
`onChallengeReceived` is the one client hook that can affect handling: return a non-empty Credential string to use it for the retry. This lets advanced clients create Credentials with custom context before falling back to `onChallenge` or the default flow.
145+
146+
Server hooks run inline on the payment request path. Keep them short, or hand work to your logger, metrics client, or queue. `mppx` ignores thrown server hook errors so observability code doesn't block payment verification, but slow hooks still delay the response.
147+
148+
## What's next
149+
150+
This release starts with core lifecycle events. If there is an event or payload field you need, leave feedback on [GitHub](https://github.com/wevm/mppx/issues).
151+
152+
</div>

src/pages/sdk/typescript/client/Fetch.from.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ type ReturnType = (
5757
5858
- **Type:** `AcceptPayment.Resolved<methods>`
5959
60-
Resolved `Accept-Payment` header and preference data. Most callers should use `methods` and `paymentPreferences` on `Mppx.create` instead.
60+
Resolved `Accept-Payment` header and preference data. Most callers use `methods` and `paymentPreferences` on `Mppx.create` instead.
6161
6262
### acceptPaymentPolicy (optional)
6363
@@ -68,6 +68,12 @@ Controls when `Accept-Payment` is injected.
6868
6969
Use `'same-origin'` in browsers when you only want same-origin payment discovery. Use `{ origins }` when paid APIs live on specific origins. Origin patterns support `*.` subdomain wildcards.
7070
71+
### eventDispatcher (optional)
72+
73+
- **Type:** `ClientEventDispatcher<methods>`
74+
75+
Advanced shared event dispatcher. `challenge.received` handlers run before `onChallenge`; the first non-empty Credential string skips `onChallenge`.
76+
7177
### fetch (optional)
7278
7379
- **Type:** `typeof globalThis.fetch`

src/pages/sdk/typescript/client/Fetch.polyfill.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ Resolved `Accept-Payment` header and preference data.
6363
6464
Controls when `Accept-Payment` is injected.
6565
66+
### eventDispatcher (optional)
67+
68+
- **Type:** `ClientEventDispatcher<methods>`
69+
70+
Advanced shared event dispatcher. `challenge.received` handlers run before `onChallenge`; the first non-empty Credential string skips `onChallenge`.
71+
6672
### fetch (optional)
6773
6874
- **Type:** `typeof globalThis.fetch`

0 commit comments

Comments
 (0)