-
Notifications
You must be signed in to change notification settings - Fork 589
[SDK] Rename verifyPayment() to processPayment() for x402 payments #8105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[SDK] Rename verifyPayment() to processPayment() for x402 payments #8105
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Name | Type |
---|---|
thirdweb | Minor |
@thirdweb-dev/nebula | Patch |
@thirdweb-dev/wagmi-adapter | Patch |
Click here to learn what changesets are, and how to add one.
Click here if you're a maintainer who wants to add a changeset to this PR
WalkthroughThe codebase replaces x402 payment verification with a new processing API. Imports, calls, and types switch from verifyPayment to processPayment, adding parameters (payTo, network, price, routeConfig, facilitator). Public exports are updated, a new types module is introduced, and docs/middleware/examples reflect the new function and signatures. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client as Client
participant MW as Next.js Middleware
participant X402 as thirdweb/x402.processPayment
participant Fac as Facilitator
participant Settler as Settlement Service
Client->>MW: HTTP request (resourceUrl, method, paymentData)
MW->>X402: processPayment({ resourceUrl, method, paymentData, payTo, network, price, routeConfig, facilitator })
X402->>Fac: Prepare settlement context
X402->>Settler: Settle payment
alt Success (200)
Settler-->>X402: paymentReceipt, headers
X402-->>MW: { status: 200, paymentReceipt, headers }
MW-->>Client: 200 OK with headers
else Payment required (402)
Settler-->>X402: 402 details (accepts, error, payer?)
X402-->>MW: { status: 402, responseBody, responseHeaders }
MW-->>Client: 402 PaymentRequired with body/headers
end
note over X402,Settler: Flow uses expanded args (payTo, network, price, routeConfig, facilitator)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
2c42ac2
to
7e3341b
Compare
size-limit report 📦
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
packages/thirdweb/src/x402/facilitator.ts (1)
104-116
: Add timeouts to all facilitator fetch callsNetwork calls lack timeouts; a stalled upstream can hang request threads. Use AbortController with a sensible default (e.g., 10s) and make it configurable.
- const res = await fetch(`${url}/verify`, { + const ac = new AbortController(); + const to = setTimeout(() => ac.abort(), 10_000); + const res = await fetch(`${url}/verify`, { method: "POST", - headers, + headers, + signal: ac.signal, body: stringify({ x402Version: payload.x402Version, paymentPayload: payload, paymentRequirements: paymentRequirements, }), }); + clearTimeout(to);- const res = await fetch(`${url}/settle`, { + const ac = new AbortController(); + const to = setTimeout(() => ac.abort(), 10_000); + const res = await fetch(`${url}/settle`, { method: "POST", - headers, - body: JSON.stringify({ + headers, + signal: ac.signal, + body: stringify({ x402Version: payload.x402Version, paymentPayload: payload, paymentRequirements: paymentRequirements, }), }); + clearTimeout(to);- const res = await fetch(`${url}/supported`, { headers }); + const ac = new AbortController(); + const to = setTimeout(() => ac.abort(), 10_000); + const res = await fetch(`${url}/supported`, { headers, signal: ac.signal }); + clearTimeout(to);Also applies to: 140-152, 175-181
packages/thirdweb/src/x402/types.ts (1)
59-75
: Add @beta and an @example to ProcessPaymentResultSame doc requirements apply to this exported type.
/** * The result of a payment verification or processing operation. * - * @public + * @public + * @beta + * @example + * ```ts + * import { type ProcessPaymentResult } from "thirdweb/x402"; + * function handle(r: ProcessPaymentResult) { + * if (r.status === 200) { + * console.log(r.paymentReceipt.success); + * } else { + * console.warn(r.responseBody.error); + * } + * } + * ``` */apps/playground-web/src/middleware.ts (1)
11-21
: Validate required env vars and avoid unsafe type assertionsFail fast if secrets are missing; avoid
as string
on possibly undefined envs.-const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string; -const ENGINE_VAULT_ACCESS_TOKEN = process.env - .ENGINE_VAULT_ACCESS_TOKEN as string; -const API_URL = `https://${process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"}`; +const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET; +if (!BACKEND_WALLET_ADDRESS) throw new Error("ENGINE_BACKEND_WALLET is required"); +const ENGINE_VAULT_ACCESS_TOKEN = process.env.ENGINE_VAULT_ACCESS_TOKEN; +const rawApiHost = process.env.NEXT_PUBLIC_API_URL || "api.thirdweb.com"; +const API_URL = rawApiHost.startsWith("http") + ? rawApiHost + : `https://${rawApiHost}`;packages/thirdweb/src/x402/process-payment.ts (1)
340-357
: Avoid float math for money → atomic units conversionMultiplying JS floats by 10**decimals can produce incorrect non-integer strings (precision loss). Use exact decimal-to-units conversion.
- if (typeof price === "string" || typeof price === "number") { - // USDC amount in dollars - const parsedAmount = moneySchema.safeParse(price); - if (!parsedAmount.success) { - return { - error: `Invalid price (price: ${price}). Must be in the form "$3.10", 0.10, "0.001", ${parsedAmount.error}`, - }; - } - const parsedUsdAmount = parsedAmount.data; - const defaultAsset = await getDefaultAsset(network, facilitator); - if (!defaultAsset) { - return { - error: `Unable to get default asset on ${network}. Please specify an asset in the payment requirements.`, - }; - } - asset = defaultAsset; - maxAmountRequired = (parsedUsdAmount * 10 ** asset.decimals).toString(); - } else { + if (typeof price === "string" || typeof price === "number") { + const parsedAmount = moneySchema.safeParse(price); + if (!parsedAmount.success) { + return { + error: `Invalid price (price: ${price}). Must be in the form "$3.10", 0.10, "0.001", ${parsedAmount.error}`, + }; + } + const defaultAsset = await getDefaultAsset(network, facilitator); + if (!defaultAsset) { + return { + error: `Unable to get default asset on ${network}. Please specify an asset in the payment requirements.`, + }; + } + asset = defaultAsset; + // Convert a decimal string (e.g. "$0.01" | "0.01" | 0.01) to atomic units exactly + const raw = (typeof price === "string" ? price.replace(/^\$/,'') : String(price)).trim(); + maxAmountRequired = decimalToUnits(raw, asset.decimals); + } else {Add this helper in the same file (below) or a shared util:
+function decimalToUnits(value: string, decimals: number): string { + if (!/^\d*(\.\d*)?$/.test(value)) throw new Error(`Invalid decimal: ${value}`); + const [ints, frac = ""] = value.split("."); + const fracPadded = (frac + "0".repeat(decimals)).slice(0, decimals); + const intPart = BigInt(ints || "0"); + const fracPart = BigInt(fracPadded || "0"); + const base = 10n ** BigInt(decimals); + return (intPart * base + fracPart).toString(); +}
🧹 Nitpick comments (4)
packages/thirdweb/src/x402/facilitator.ts (1)
147-151
: Use a single JSON serializer consistentlyverify() uses stringify() while settle() uses JSON.stringify(). Prefer one (stringify) for consistency and stable formatting.
- body: JSON.stringify({ + body: stringify({ x402Version: payload.x402Version, paymentPayload: payload, paymentRequirements: paymentRequirements, }),apps/portal/src/app/payments/x402/page.mdx (1)
46-47
: Microcopy: fix grammar“Use the facilitator configuration function settle transactions…” → “to settle transactions…”
-Use the `facilitator` configuration function settle transactions with your thirdweb server wallet gaslessly and pass it to the `processPayment` function. +Use the `facilitator` configuration function to settle transactions with your thirdweb server wallet gaslessly and pass it to the `processPayment` function.apps/playground-web/src/middleware.ts (1)
26-27
: Include querystring in resourceUrlParity with other examples and clearer provenance.
- const resourceUrl = `${request.nextUrl.protocol}//${request.nextUrl.host}${pathname}`; + const resourceUrl = request.nextUrl.toString();packages/thirdweb/src/x402/process-payment.ts (1)
1-7
: Consider extracting helpers to satisfy “one function per file” guidanceprocessPriceToAtomicAmount and getDefaultAsset could live in a local utility (e.g., ./price.ts) to keep this file single‑responsibility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
.changeset/some-moons-burn.md
(1 hunks)apps/playground-web/src/app/payments/x402/page.tsx
(2 hunks)apps/playground-web/src/middleware.ts
(2 hunks)apps/portal/src/app/payments/x402/page.mdx
(2 hunks)packages/thirdweb/src/exports/x402.ts
(1 hunks)packages/thirdweb/src/x402/facilitator.ts
(1 hunks)packages/thirdweb/src/x402/process-payment.ts
(6 hunks)packages/thirdweb/src/x402/types.ts
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}
: Write idiomatic TypeScript with explicit function declarations and return types
Limit each file to one stateless, single-responsibility function for clarity
Re-use shared types from@/types
or localtypes.ts
barrels
Prefer type aliases over interface except for nominal shapes
Avoidany
andunknown
unless unavoidable; narrow generics when possible
Choose composition over inheritance; leverage utility types (Partial
,Pick
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
**/*.{ts,tsx}
: Use explicit function declarations and explicit return types in TypeScript
Limit each file to one stateless, single‑responsibility function
Re‑use shared types from@/types
where applicable
Prefertype
aliases overinterface
except for nominal shapes
Avoidany
andunknown
unless unavoidable; narrow generics when possible
Prefer composition over inheritance; use utility types (Partial, Pick, etc.)
Lazy‑import optional features and avoid top‑level side‑effects to reduce bundle size
Files:
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/middleware.ts
packages/thirdweb/src/exports/x402.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/process-payment.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)
Files:
packages/thirdweb/src/x402/facilitator.ts
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/middleware.ts
packages/thirdweb/src/exports/x402.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/process-payment.ts
packages/thirdweb/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
packages/thirdweb/**/*.{ts,tsx}
: Every public symbol must have comprehensive TSDoc with at least one compiling@example
and a custom tag (@beta
,@internal
,@experimental
, etc.)
Comment only ambiguous logic; avoid restating TypeScript in prose
Lazy‑load heavy dependencies inside async paths (e.g.,const { jsPDF } = await import("jspdf")
)
Files:
packages/thirdweb/src/x402/facilitator.ts
packages/thirdweb/src/exports/x402.ts
packages/thirdweb/src/x402/types.ts
packages/thirdweb/src/x402/process-payment.ts
.changeset/*.md
📄 CodeRabbit inference engine (AGENTS.md)
.changeset/*.md
: Each change inpackages/*
must include a changeset for the appropriate package
Version bump rules: patch for non‑API changes; minor for new/modified public API
Files:
.changeset/some-moons-burn.md
apps/{dashboard,playground-web}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/{dashboard,playground-web}/**/*.{ts,tsx}
: Import UI primitives from@/components/ui/*
(Button, Input, Select, Tabs, Card, Sidebar, Badge, Separator) in dashboard and playground apps
UseNavLink
for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Usecn()
from@/lib/utils
for conditional class logic
Use design system tokens (e.g.,bg-card
,border-border
,text-muted-foreground
)
Server Components (Node edge): Start files withimport "server-only";
Client Components (browser): Begin files with'use client';
Always callgetAuthToken()
to retrieve JWT from cookies on server side
UseAuthorization: Bearer
header – never embed tokens in URLs
Return typed results (e.g.,Project[]
,User[]
) – avoidany
Wrap client-side data fetching calls in React Query (@tanstack/react-query
)
Use descriptive, stablequeryKeys
for React Query cache hits
ConfigurestaleTime
/cacheTime
in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never importposthog-js
in server components
Files:
apps/playground-web/src/app/payments/x402/page.tsx
apps/playground-web/src/middleware.ts
packages/thirdweb/src/exports/**
📄 CodeRabbit inference engine (CLAUDE.md)
packages/thirdweb/src/exports/**
: Export everything viaexports/
directory, grouped by feature in the SDK public API
Every public symbol must have comprehensive TSDoc with at least one@example
block that compiles and custom annotation tags (@beta
,@internal
,@experimental
)
Files:
packages/thirdweb/src/exports/x402.ts
**/types.ts
📄 CodeRabbit inference engine (AGENTS.md)
Provide and re‑use local type barrels in a
types.ts
file
Files:
packages/thirdweb/src/x402/types.ts
🧠 Learnings (1)
📚 Learning: 2025-08-20T10:35:18.543Z
Learnt from: jnsdls
PR: thirdweb-dev/js#7888
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx:77-81
Timestamp: 2025-08-20T10:35:18.543Z
Learning: The webhooks/payments route exists at apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx and was added as part of the unified project layout changes.
Applied to files:
apps/playground-web/src/app/payments/x402/page.tsx
🧬 Code graph analysis (3)
apps/playground-web/src/middleware.ts (2)
packages/thirdweb/src/exports/x402.ts (1)
processPayment
(7-7)packages/thirdweb/src/x402/process-payment.ts (1)
processPayment
(132-319)
packages/thirdweb/src/x402/types.ts (2)
packages/thirdweb/src/exports/utils.ts (1)
Address
(144-144)packages/thirdweb/src/x402/schemas.ts (3)
FacilitatorNetwork
(26-26)RequestedPaymentRequirements
(47-49)FacilitatorSettleResponse
(54-56)
packages/thirdweb/src/x402/process-payment.ts (1)
packages/thirdweb/src/x402/types.ts (2)
PaymentArgs
(22-39)ProcessPaymentResult
(64-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Size
- GitHub Check: E2E Tests (pnpm, esbuild)
- GitHub Check: Build Packages
- GitHub Check: Lint Packages
- GitHub Check: Unit Tests
- GitHub Check: Analyze (javascript)
🔇 Additional comments (9)
packages/thirdweb/src/x402/facilitator.ts (1)
22-22
: Docs alignment with new API name looks goodReference switched to processPayment. No runtime impact.
.changeset/some-moons-burn.md (1)
2-6
: Correct release note and bump levelMinor bump matches the public API rename and broader surface change.
apps/playground-web/src/app/payments/x402/page.tsx (1)
60-86
: Example updated to processPayment — looks goodImport and call-site changes align with the new API and arguments.
packages/thirdweb/src/x402/types.ts (1)
15-16
: Clarify visibility of x402VersionIf not intended for public consumption, mark as @internal to avoid surfacing it implicitly.
- export const x402Version = 1; + /** + * X402 protocol version used internally. + * @internal + */ + export const x402Version = 1;apps/portal/src/app/payments/x402/page.mdx (1)
65-76
: Docs example aligns with new APIGood coverage showing headers echo-back.
apps/playground-web/src/middleware.ts (2)
29-41
: Middleware usage matches new APIArgs and header propagation look correct.
1-61
: Sweep for stale verifyPayment references across the repoEnsure no dead imports/usages remain.
packages/thirdweb/src/x402/process-payment.ts (1)
24-79
: TSDoc is strong and includes examplesPublic API surface is well documented with @beta and @bridge tags.
packages/thirdweb/src/exports/x402.ts (1)
7-8
: Re-exports look correct; ensure public TSDoc originates at sourceprocessPayment and types are exposed via the exports barrel. Confirm that their declarations carry comprehensive TSDoc with a compiling @example and a custom tag (e.g., @beta), per packages/thirdweb guidelines.
/** | ||
* Configuration object for verifying or processing X402 payments. | ||
* | ||
* @public | ||
*/ | ||
export type PaymentArgs = { | ||
/** The URL of the resource being protected by the payment */ | ||
resourceUrl: string; | ||
/** The HTTP method used to access the resource */ | ||
method: "GET" | "POST" | ({} & string); | ||
/** The payment data/proof provided by the client, typically from the X-PAYMENT header */ | ||
paymentData?: string | null; | ||
/** The wallet address that should receive the payment */ | ||
payTo: Address; | ||
/** The blockchain network where the payment should be processed */ | ||
network: FacilitatorNetwork; | ||
/** The price for accessing the resource - either a USD amount (e.g., "$0.10") or a specific token amount */ | ||
price: Money | ERC20TokenAmount; | ||
/** The payment facilitator instance used to verify and settle payments */ | ||
facilitator: ReturnType<typeof facilitatorType>; | ||
/** Optional configuration for the payment middleware route */ | ||
routeConfig?: PaymentMiddlewareConfig; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add @beta and a minimal compiling @example to PaymentArgs
Public symbols in packages/thirdweb require a compiling @example and a custom tag. Add both to PaymentArgs.
/**
* Configuration object for verifying or processing X402 payments.
*
- * @public
+ * @public
+ * @beta
+ * @example
+ * ```ts
+ * import { type PaymentArgs } from "thirdweb/x402";
+ * const args: PaymentArgs = {
+ * resourceUrl: "https://api.example.com/paid",
+ * method: "GET",
+ * paymentData: null,
+ * payTo: "0x1234567890123456789012345678901234567890",
+ * network: "eip155:8453",
+ * price: "$0.01",
+ * facilitator: someFacilitator,
+ * };
+ * ```
*/
🤖 Prompt for AI Agents
In packages/thirdweb/src/x402/types.ts around lines 17 to 39, the PaymentArgs
type is missing the required @beta tag and a compiling @example for public
symbols; add a JSDoc @beta annotation above the type and append a minimal,
compiling @example that imports the type from "thirdweb/x402" and shows a valid
PaymentArgs object (including resourceUrl, method, paymentData, payTo, network,
price, and facilitator) so the example compiles — use realistic placeholder
values for address and network and a placeholder facilitator value typed
appropriately to satisfy the compiler.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8105 +/- ##
==========================================
- Coverage 56.32% 56.32% -0.01%
==========================================
Files 906 906
Lines 59197 59197
Branches 4176 4176
==========================================
- Hits 33345 33340 -5
- Misses 25746 25751 +5
Partials 106 106
🚀 New features to boost your workflow:
|
PR-Codex overview
This PR focuses on renaming and refactoring the payment verification process in the
thirdweb
library, transitioning fromverifyPayment
toprocessPayment
. This change includes updates to types, function exports, and documentation to reflect the new naming convention.Detailed summary
verifyPayment
toprocessPayment
in several files.packages/thirdweb/src/exports/x402.ts
.processPayment
.apps/playground-web/src/app/payments/x402/page.tsx
andapps/portal/src/app/payments/x402/page.mdx
.PaymentArgs
andProcessPaymentResult
inpackages/thirdweb/src/x402/types.ts
.packages/thirdweb/src/x402/process-payment.ts
.Summary by CodeRabbit
New Features
Documentation
Refactor
Chores