Skip to content

Conversation

eabdelmoneim
Copy link
Contributor

@eabdelmoneim eabdelmoneim commented Sep 22, 2025

Corrected a typo in the configuration function description.


PR-Codex overview

This PR focuses on enhancing the documentation for the 402 Gated Payments feature, detailing its implementation, benefits, and components for both client and server sides, while improving clarity and terminology.

Detailed summary

  • Changed title from x402 payments to 402 Gated Payments.
  • Updated descriptions for clarity on payment processes.
  • Introduced sections on core concepts, benefits, and payment processors.
  • Added detailed explanations for client-side and server-side components.
  • Included examples for basic usage, error handling, and middleware setup.
  • Specified supported payment networks and tokens.
  • Enhanced configuration options for payment limits and multiple endpoint pricing.

✨ Ask PR-Codex anything about this PR by commenting with /codex {your question}

Summary by CodeRabbit

  • Documentation
    • Renamed and expanded Payments docs to "402 Gated Payments" with a clearer introduction, benefits, and pay-per-request model.
    • Added "How it works", protocol fundamentals, supported networks/tokens, and payment schemes.
    • Expanded client & server guidance with richer examples (React, TypeScript, Next.js), env-based server wallet config, per-endpoint pricing, error/retry handling, and multi-network support.
    • Content-only; no public API changes.

Corrected a typo in the configuration function description.

Signed-off-by: Eiman <[email protected]>
@eabdelmoneim eabdelmoneim requested review from a team as code owners September 22, 2025 14:36
Copy link

vercel bot commented Sep 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-v2 Ready Ready Preview Comment Sep 22, 2025 10:37pm
4 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
nebula Skipped Skipped Sep 22, 2025 10:37pm
thirdweb_playground Skipped Skipped Sep 22, 2025 10:37pm
thirdweb-www Skipped Skipped Sep 22, 2025 10:37pm
wallet-ui Skipped Skipped Sep 22, 2025 10:37pm

Copy link

changeset-bot bot commented Sep 22, 2025

⚠️ No Changeset found

Latest commit: d245b2e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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

Copy link
Contributor

coderabbitai bot commented Sep 22, 2025

Walkthrough

Complete rewrite of the x402 payments doc renamed to "402 Gated Payments", expanding introduction, core concepts, payment protocol fundamentals, supported networks/tokens, detailed client and server implementations (including Next.js), middleware and env-based server wallet configuration, richer TypeScript examples, and per-endpoint pricing configuration.

Changes

Cohort / File(s) Summary
Docs: 402 gated payments full rewrite
apps/portal/src/app/payments/x402/page.mdx
Full content replacement and expansion: title changed to "402 Gated Payments"; new Introduction & Core Concepts; detailed "How it works" pay-per-request flow; "402 Payment Protocol Fundamentals" (processors, schemes — exact); supported networks/tokens and auto-negotiation; expanded client-side components (wrapFetchWithPayment, wallet integration, chain switching, error handling) and server-side components (middleware libraries, payment verification, multi-chain support, automatic settlement, gasless transactions); server wallet documented with env-based SERVER_WALLET_ADDRESS; Basic Usage, Advanced Configuration, Next.js/TypeScript examples, per-endpoint pricing and endpoint matchers; updated sample code and renamed variables to env-driven config. No exported/public API signature changes.

Sequence Diagram(s)

sequenceDiagram
    rect rgba(46,125,50,0.06)
    participant Client
    end
    rect rgba(13,71,161,0.06)
    participant Facilitator as "thirdweb Facilitator / Middleware"
    end
    rect rgba(236,64,122,0.06)
    participant ServerWallet as "Server Wallet (env: SERVER_WALLET_ADDRESS)"
    end
    rect rgba(255,179,0,0.06)
    participant Network as "Blockchain / Token Network"
    end

    Client->>Facilitator: Initial API request
    Facilitator-->>Client: 402 Payment Required (payment params)
    Client->>Client: User wallet signs payment intent
    Client->>Facilitator: Retry request with Payment header + signed intent
    Facilitator->>ServerWallet: Forward/aggregate payment intents (optional)
    ServerWallet->>Network: On-chain settlement / token transfer
    Network-->>ServerWallet: Transaction confirmation
    ServerWallet-->>Facilitator: Settlement result
    Facilitator-->>Client: Final API response (success / error)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description contains a brief summary and a detailed "PR-Codex overview" but does not populate the repository's required template fields: the formatted title line, issue tag, "Notes for the reviewer", and "How to test" are present only as an HTML comment and are not filled in, leaving explicit testing steps and reviewer guidance missing or incomplete. As a result, reviewers may lack clear instructions to validate the changes and clarity about whether this is only a typo fix or a broader documentation update. Please fill the repository PR template in the visible PR body: add the formatted title line, include the issue/Linear tag if applicable, provide "Notes for the reviewer" that call out important changes, and add explicit "How to test" steps (unit tests to run or manual playground/endpoints to exercise); also clarify the intended scope (typo fix versus broad docs changes) and integrate or summarize the PR-Codex content into the main description.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Fix typo in facilitator configuration function" correctly describes a real change present in the PR (a facilitator configuration description correction) but it is narrowly focused and does not reflect the broader documentation edits to the 402 Gated Payments article included in the changeset, which may mislead reviewers about the PR's scope. The title is concise and specific, however it understates the overall set of documentation updates bundled in this branch.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch eabdelmoneim-patch-1

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • TEAM-0000: Entity not found: Issue - Could not find referenced Issue.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

graphite-app bot commented Sep 22, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • hotfix - for urgent hot fixes, skip the queue and merge this PR next

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.

@github-actions github-actions bot added the Portal Involves changes to the Portal (docs) codebase. label Sep 22, 2025
Copy link

codecov bot commented Sep 22, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.34%. Comparing base (b37ed57) to head (d245b2e).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8093   +/-   ##
=======================================
  Coverage   56.34%   56.34%           
=======================================
  Files         906      906           
  Lines       59187    59187           
  Branches     4181     4181           
=======================================
  Hits        33351    33351           
  Misses      25730    25730           
  Partials      106      106           
Flag Coverage Δ
packages 56.34% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

github-actions bot commented Sep 22, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.07 KB (0%) 1.3 s (0%) 1.7 s (-10.58% 🔽) 2.9 s
thirdweb (cjs) 361.6 KB (0%) 7.3 s (0%) 13.3 s (-4.15% 🔽) 20.5 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 171 ms (+177.47% 🔺) 286 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 65 ms (-2.58% 🔽) 76 ms
thirdweb/react (minimal + tree-shaking) 19.14 KB (0%) 383 ms (0%) 126 ms (+0.16% 🔺) 509 ms

@vercel vercel bot temporarily deployed to Preview – wallet-ui September 22, 2025 19:10 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 22, 2025 19:10 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb-www September 22, 2025 19:10 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 22, 2025 19:10 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 22, 2025 19:15 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui September 22, 2025 19:15 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 September 22, 2025 19:15 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 22, 2025 19:15 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/portal/src/app/payments/x402/page.mdx (1)

220-239: Use a single source of truth for server wallet address.

You hard‑code an address (Line 225) but also pass SERVER_WALLET_ADDRESS to facilitator (Line 237). This can drift and cause mis‑settlement.

-export const middleware = paymentMiddleware(
-  "0xdd99b75f095d0c4d5112aCe938e4e6ed962fb024", // Your server wallet address
+const serverWalletAddress = process.env.SERVER_WALLET_ADDRESS as string;
+export const middleware = paymentMiddleware(
+  serverWalletAddress, // Your server wallet address
@@
-  facilitator({
-    client,
-    serverWalletAddress: process.env.SERVER_WALLET_ADDRESS,
-  }),
+  facilitator({ client, serverWalletAddress }),
 );
🧹 Nitpick comments (7)
apps/portal/src/app/payments/x402/page.mdx (7)

6-6: Hyphenate “on‑chain”.

Change “onchain” to “on-chain” for correctness.

-Implement paid API calls using the x402 protocol. Every request is paid for by the user with a micro payment onchain.
+Implement paid API calls using the x402 protocol. Every request is paid for by the user with a micro payment on-chain.

10-13: Use “an x402” (article agreement).

“x402” is pronounced “ex-…”, so use “an”.

- description="Try out a x402 payment in our live playground"
+ description="Try out an x402 payment in our live playground"

124-132: Avoid top‑level await in generic snippets.

Wrap in an async IIFE for portability across bundlers/runtimes.

-const client = createThirdwebClient({ clientId: "your-client-id" });
-const wallet = createWallet("io.metamask"); // or any other wallet
-await wallet.connect({ client })
-
-const fetchWithPay = wrapFetchWithPayment(fetch, client, wallet);
-
-// Make a request that may require payment
-const response = await fetchWithPay('https://api.example.com/paid-endpoint');
+(async () => {
+  const client = createThirdwebClient({ clientId: "your-client-id" });
+  const wallet = createWallet("io.metamask"); // or any other wallet
+  await wallet.connect({ client });
+  const fetchWithPay = wrapFetchWithPayment(fetch, client, wallet);
+  const response = await fetchWithPay("https://api.example.com/paid-endpoint");
+  // use response...
+})();

139-146: Prefer BigInt literals or utility for token units.

Avoid Number→BigInt coercion; use BigInt math or a helper like parseUnits.

-  BigInt(5 * 10 ** 6) // Maximum 5 USDC
+  5n * 10n ** 6n // Maximum 5 USDC (6 decimals)
+  // or: parseUnits("5", 6) if available from your SDK

75-76: “Automatically negotiate the best payment network” needs qualification.

If negotiation requires explicit config or wallet capabilities, clarify to avoid misleading expectations.

-- **Network selection**: Client and server automatically negotiate the best payment network
+- **Network selection**: Client and server select the configured payment network (auto‑prompting wallet switch when required)

91-93: Clarify “Gasless transactions”.

If the facilitator pays gas (sponsor) rather than transactions being gas‑free on-chain, reword to avoid confusion.

-- **Gasless transactions**: Handles all gas costs for payment settlement
+- **Sponsored settlement**: Facilitator covers gas for payment settlement on your behalf

63-71: Link supported networks list to thirdweb's canonical Chainlist / Pay Supported Chains
Replace the hardcoded list in apps/portal/src/app/payments/x402/page.mdx (lines 63–71) with a link to thirdweb’s maintained Chainlist / Pay Supported Chains page — or generate the list from the canonical config at build time to prevent drift.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between a24038f and f0fac5a.

📒 Files selected for processing (1)
  • apps/portal/src/app/payments/x402/page.mdx (5 hunks)
⏰ 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). (2)
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (1)
apps/portal/src/app/payments/x402/page.mdx (1)

209-212: Package names verified — no change needed.
The middleware packages "x402-hono", "x402-next", and "x402-express" are the published npm package names and match the thirdweb x402 x402 facilitator docs.

@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 22, 2025 20:36 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb-www September 22, 2025 20:36 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui September 22, 2025 20:36 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 22, 2025 20:36 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/portal/src/app/payments/x402/page.mdx (2)

220-239: Use one source of truth for server wallet; avoid hard‑coded address

You hard‑code payTo while passing env in facilitator. Make both use the same env var and validate presence.

-import { facilitator } from "thirdweb/x402";
+import { facilitator } from "thirdweb/x402";
@@
-export const middleware = paymentMiddleware(
-  "0xdd99b75f095d0c4d5112aCe938e4e6ed962fb024", // Your server wallet address
+const serverWalletAddress = process.env.SERVER_WALLET_ADDRESS as string;
+if (!serverWalletAddress) {
+  throw new Error("SERVER_WALLET_ADDRESS is not set");
+}
+export const middleware = paymentMiddleware(
+  serverWalletAddress, // Your server wallet address
@@
   facilitator({
     client,
-    serverWalletAddress: process.env.SERVER_WALLET_ADDRESS,
+    serverWalletAddress,
   }), // thirdweb payment processor configuration
 );

119-132: Add required bigint maxValue to wrapFetchWithPayment call

Signature is wrapFetchWithPayment(fetch, client, wallet, maxValue: bigint). The snippet passes only three args — update apps/portal/src/app/payments/x402/page.mdx (lines 119–132) to provide an appropriate bigint (e.g., 0n) or update the example to match the API.

🧹 Nitpick comments (3)
apps/portal/src/app/payments/x402/page.mdx (3)

55-59: Clarify max‑amount units (token smallest unit vs. USD)

Explicitly state that client max limits are specified in the payment token’s smallest unit (e.g., USDC 6 decimals) to avoid misconfiguration.


139-146: Use bigint literals; avoid Number -> BigInt coercion and document decimals

Prefer bigint math to prevent accidental float/precision issues; also annotate 6‑decimals for USDC.

-  BigInt(5 * 10 ** 6) // Maximum 5 USDC
+  5n * 10n ** 6n // Maximum 5 USDC (USDC has 6 decimals)

294-298: Add client‑side env var used in React snippet

Include NEXT_PUBLIC_THIRDWEB_CLIENT_ID to prevent confusion when instantiating the client on the web.

 # .env.local
 THIRDWEB_SECRET_KEY=your_thirdweb_secret_key
 SERVER_WALLET_ADDRESS=0x1234567890123456789012345678901234567890
+NEXT_PUBLIC_THIRDWEB_CLIENT_ID=your_thirdweb_client_id
📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between f0fac5a and de1547f.

📒 Files selected for processing (1)
  • apps/portal/src/app/payments/x402/page.mdx (4 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/portal/src/app/payments/x402/page.mdx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/portal/src/app/payments/x402/page.mdx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Wrap client-side data fetching calls in React Query (`tanstack/react-query`)

Applied to files:

  • apps/portal/src/app/payments/x402/page.mdx
⏰ 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). (3)
  • GitHub Check: Size
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/portal/src/app/payments/x402/page.mdx (7)

4-7: Scope drift: doc rewrite vs. “Fix typo” PR title

This is a substantial docs overhaul, not a typo fix. Please confirm scope and update the PR title/description accordingly or split changes.


8-13: Verify playground link and title consistency

Confirm the playground URL resolves and matches the page’s “402 Gated Payments” terminology across nav/search.


153-171: Don’t match on error.message; switch on structured codes/payload

-} catch (error) {
-  if (error.message.includes("Payment amount exceeds maximum")) {
+} catch (error: unknown) {
+  const err = error as { code?: string; name?: string; message?: string };
+  switch (err?.code) {
+    case "X402_MAX_AMOUNT_EXCEEDED":
       // Handle payment too expensive
-  } else if (error.message.includes("Wallet not connected")) {
+      console.error("Payment required exceeds your limit");
+      break;
+    case "WALLET_NOT_CONNECTED":
       // Handle wallet connection issues
-    console.error("Please connect your wallet");
-  } else if (error.message.includes("Payment already attempted")) {
+      console.error("Please connect your wallet");
+      break;
+    case "X402_ALREADY_ATTEMPTED":
       // Handle retry scenarios
-    console.error("Payment was already processed");
-  } else {
+      console.error("Payment was already processed");
+      break;
+    default: {
       // Handle other errors (user rejected, insufficient funds, etc.)
-    console.error("Payment failed:", error.message);
-  }
+      console.error("Payment failed:", err?.message ?? "Unknown error");
+    }
+  }
 }

178-203: React snippet missing client and wrapFetchWithPayment imports/definition

-import { useActiveWallet } from "thirdweb/react";
+import { useActiveWallet } from "thirdweb/react";
+import { createThirdwebClient } from "thirdweb";
+import { wrapFetchWithPayment } from "thirdweb/x402";
+// If your app provides a client via context, prefer that (e.g., useThirdwebClient)
+// import { useThirdwebClient } from "your/provider";
@@
 function PayableAPICall() {
   const wallet = useActiveWallet();
+  const client = createThirdwebClient({ clientId: process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID! });
@@
       if (!wallet) throw new Error("Wallet not connected");
 
       const fetchWithPay = wrapFetchWithPayment(fetch, client, wallet);

263-288: Undefined serverWalletAddress in multi‑route snippet

-export const middleware = paymentMiddleware(
-  serverWalletAddress,
+const serverWalletAddress = process.env.SERVER_WALLET_ADDRESS as string;
+if (!serverWalletAddress) throw new Error("SERVER_WALLET_ADDRESS is not set");
+export const middleware = paymentMiddleware(
+  serverWalletAddress,
   {
@@
   },
   facilitator({ client, serverWalletAddress }), // thirdweb payment processor
 );

Also verify network identifiers (“base”, “base-sepolia”) match your x402-next version.


249-256: Approve — config example matches thirdweb/x402 docs

Option names client and serverWalletAddress are correct; optional baseUrl and vaultAccessToken are also supported. Keep the example synced with the package README.


60-71: Network support list may be stale — mark as examples or link to the canonical README
x402 / x402-next READMEs use "base-sepolia" and the middleware is configurable for other networks (e.g., "sei"); do not present an exhaustive list — either prefix with "for example" or add a link to the package README/source-of-truth.
File: apps/portal/src/app/payments/x402/page.mdx (lines 60–71)

@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 22, 2025 21:47 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 22, 2025 21:47 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui September 22, 2025 21:47 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb-www September 22, 2025 21:47 Inactive
@thirdweb-dev thirdweb-dev deleted a comment from coderabbitai bot Sep 22, 2025
@thirdweb-dev thirdweb-dev deleted a comment from coderabbitai bot Sep 22, 2025
@thirdweb-dev thirdweb-dev deleted a comment from coderabbitai bot Sep 22, 2025
@vercel vercel bot temporarily deployed to Preview – thirdweb-www September 22, 2025 21:50 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground September 22, 2025 21:50 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula September 22, 2025 21:50 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui September 22, 2025 21:50 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/portal/src/app/payments/x402/page.mdx (1)

210-225: Inconsistent server wallet source — hardcoded address vs env var.

Using a literal address for payTo while passing a different env address to the facilitator risks funds going to the wrong place. Use a single env‑driven variable and fail fast if missing.

-import { createThirdwebClient } from "thirdweb";
+import { createThirdwebClient } from "thirdweb";
 import { facilitator } from "thirdweb/x402";
 import { paymentMiddleware } from "x402-next";

 const client = createThirdwebClient({
   secretKey: process.env.THIRDWEB_SECRET_KEY as string,
 });

+const serverWalletAddress = process.env.SERVER_WALLET_ADDRESS as string;
+if (!serverWalletAddress) {
+  throw new Error("SERVER_WALLET_ADDRESS is not set");
+}
+
 export const middleware = paymentMiddleware(
-  "0xdd99b75f095d0c4d5112aCe938e4e6ed962fb024", // Your server wallet address
+  serverWalletAddress,
   {
     "/api/paid-endpoint": {
       price: "$0.01",
       network: "base-sepolia",
       config: {
         description: "Access to paid content",
       },
     },
   },
   facilitator({
     client,
-    serverWalletAddress: process.env.SERVER_WALLET_ADDRESS,
+    serverWalletAddress,
   }), // thirdweb payment processor configuration
 );
🧹 Nitpick comments (4)
apps/portal/src/app/payments/x402/page.mdx (4)

4-6: PR scope/title/body mismatch — this is more than a typo fix.

Large doc rewrites are included. Please update the PR title/description (or split the PR) so reviewers know the true scope.


74-75: Auto chain switch claim — clarify user prompt.

Most wallets require a user‑approved switch; don’t promise automatic switching.

-- **Chain switching**: Automatically switches to the required payment network
+- **Chain switching**: Prompts the user to switch to the required payment network (or surfaces an actionable error)

49-59: Supported networks/tokens list can drift — confirm and reduce maintenance risk.

Verify the list matches the current processor release; consider replacing with “Examples include …” plus a link to a single source of truth or an include pulled from shared constants to avoid stale docs.

Also applies to: 61-63


87-92: Over‑promising on “multi‑network”, “gasless”, “real‑time” — add constraints.

Clarify that: same EVM address works across EVM chains; gasless depends on facilitator/network; “real‑time” may be subject to chain finality/queueing.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between de1547f and b5965b0.

📒 Files selected for processing (1)
  • apps/portal/src/app/payments/x402/page.mdx (4 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Interactive UI that relies on hooks (`useState`, `useEffect`, React Query, wallet hooks).

Applied to files:

  • apps/portal/src/app/payments/x402/page.mdx
📚 Learning: 2025-07-18T19:20:32.530Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: .cursor/rules/dashboard.mdc:0-0
Timestamp: 2025-07-18T19:20:32.530Z
Learning: Applies to dashboard/**/*client.tsx : Anything that consumes hooks from `tanstack/react-query` or thirdweb SDKs.

Applied to files:

  • apps/portal/src/app/payments/x402/page.mdx
📚 Learning: 2025-07-18T19:19:55.613Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-18T19:19:55.613Z
Learning: Applies to apps/{dashboard,playground-web}/**/*.{ts,tsx} : Wrap client-side data fetching calls in React Query (`tanstack/react-query`)

Applied to files:

  • apps/portal/src/app/payments/x402/page.mdx
⏰ 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). (3)
  • GitHub Check: Lint Packages
  • GitHub Check: Size
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (7)
apps/portal/src/app/payments/x402/page.mdx (7)

61-64: Network negotiation phrasing is misleading — server dictates the network.

Replace “Client and server automatically negotiate the best payment network” with server‑led wording.

-**Network selection**: Client and server automatically negotiate the best payment network
+ - Network selection: Server advertises accepted network(s) in the 402 response; the client will build/send the payment on an advertised network if the connected wallet supports it.

83-84: Unconditional “gasless” statements — make conditional and note limits.

Gas sponsorship depends on the facilitator, token/network, and quotas. Soften both bullets.

-- **Automatic settlement**: Executes token transfers to your server wallet
-- **Gasless transactions**: thirdweb covers all gas costs for payment processing
+- **Automatic settlement**: Executes token transfers to your server wallet
+- **Gasless transactions (when supported)**: Settlement can be sponsored by a facilitator so buyers pay no gas; availability depends on the facilitator, supported token/network, and any quotas/plan limits.

@@
-- **Gasless payments**: Payment transfers are performed in gasless fashion to reduce friction
+- **Gasless payments (when supported)**: Transfers may be sponsored by the facilitator; availability varies by facilitator and network/token.

Also applies to: 90-91


125-131: Max payment units — confirm default and denomination.

You state default is 1 USDC and pass BigInt(5 * 10 ** 6) for 5 USDC (USDC 6 decimals). Verify the helper indeed expects 6‑decimals amount and that the default is 1 USDC in the current SDK version.


139-157: Don’t match on error.message — use codes/payload.

Switch to typed/narrow checks (error code/response payload) instead of substring matching.

-} catch (error) {
-  if (error.message.includes("Payment amount exceeds maximum")) {
+} catch (error: unknown) {
+  const err = error as { code?: string; message?: string; response?: Response };
+  // Try protocol/server payload first
+  let code: string | undefined = err?.code;
+  if (!code && err?.response) {
+    try {
+      const body = await err.response.clone().json();
+      code = body?.code ?? body?.error?.code;
+    } catch {}
+  }
+  if (code === "X402_MAX_AMOUNT_EXCEEDED") {
     // Handle payment too expensive
-  } else if (error.message.includes("Wallet not connected")) {
+  } else if (code === "WALLET_NOT_CONNECTED") {
     // Handle wallet connection issues
-  } else if (error.message.includes("Payment already attempted")) {
+  } else if (code === "X402_ALREADY_ATTEMPTED") {
     // Handle retry scenarios
-  } else {
+  } else if (err?.message) {
     // Handle other errors (user rejected, insufficient funds, etc.)
-    console.error("Payment failed:", error.message);
+    console.error("Payment failed:", err.message);
   }
 }

164-189: React snippet: missing client/imports; potential undefined identifiers.

Import/create a client (or use a provider hook) and import wrapFetchWithPayment.

+import { createThirdwebClient } from "thirdweb";
+import { wrapFetchWithPayment } from "thirdweb/x402";
+// If the app provides a client via context, prefer that hook (e.g., useThirdwebClient)
 import { useActiveWallet } from "thirdweb/react";
 import { useMutation } from "@tanstack/react-query";

 function PayableAPICall() {
   const wallet = useActiveWallet();
+  const client = createThirdwebClient({ clientId: "your-client-id" });

   const paidApiCall = useMutation({
     mutationFn: async () => {
       if (!wallet) throw new Error("Wallet not connected");

-      const fetchWithPay = wrapFetchWithPayment(fetch, client, wallet);
+      const fetchWithPay = wrapFetchWithPayment(fetch, client, wallet);
       const response = await fetchWithPay('/api/paid-endpoint');
       return response.json();
     },
   });

249-270: serverWalletAddress is referenced but not declared in this snippet.

Declare it (env‑based) and reuse the same variable across examples to avoid drift.

+const serverWalletAddress = process.env.SERVER_WALLET_ADDRESS as string;
+if (!serverWalletAddress) throw new Error("SERVER_WALLET_ADDRESS is not set");
 export const middleware = paymentMiddleware(
   serverWalletAddress,
   {
     "/api/basic-data": {
       price: "$0.01",
       network: "base-sepolia",
       config: { description: "Basic data access" },

201-205: Package name import — confirm accuracy for your version.

Ensure paymentMiddleware import path is correct (e.g., "x402-next" vs scoped variants) for the version used in this repo.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/portal/src/app/payments/x402/page.mdx (1)

179-193: Use a single source of truth for server wallet address; avoid hardcoding

Literal address at Line 179 conflicts with env at Lines 191–193. Use env everywhere and validate presence.

Apply this diff:

-import { createThirdwebClient } from "thirdweb";
+import { createThirdwebClient } from "thirdweb";
 import { facilitator } from "thirdweb/x402";
 import { paymentMiddleware } from "x402-next";

 const client = createThirdwebClient({
   secretKey: process.env.THIRDWEB_SECRET_KEY as string,
 });

+const serverWalletAddress = process.env.SERVER_WALLET_ADDRESS as string;
+if (!serverWalletAddress) {
+  throw new Error("SERVER_WALLET_ADDRESS is not set");
+}
+
 export const middleware = paymentMiddleware(
-  "0xdd99b75f095d0c4d5112aCe938e4e6ed962fb024", // Your server wallet address
+  serverWalletAddress, // Your server wallet address
   {
     "/api/paid-endpoint": {
       price: "$0.01",
       network: "base-sepolia",
       config: {
         description: "Access to paid content",
       },
     },
   },
   facilitator({
     client,
-    serverWalletAddress: process.env.SERVER_WALLET_ADDRESS,
+    serverWalletAddress,
   }), // thirdweb payment processor configuration
 );
🧹 Nitpick comments (4)
apps/portal/src/app/payments/x402/page.mdx (4)

74-74: Avoid implying silent chain switches

Most wallets require prompting/consent; say “prompts” instead of “automatically switches.”

Apply this diff:

-- **Chain switching**: Automatically switches to the required payment network
+- **Chain switching**: Prompts users to switch to the required payment network when needed

91-91: Tone down “Real‑time settlement”

Settlement depends on facilitator processing and chain finality.

Apply this diff:

-- **Real-time settlement**: Payments arrive in your wallet immediately after validation
+- **Near‑real‑time settlement**: Payments are submitted for settlement after validation; timing depends on facilitator processing and chain finality.

139-156: Prefer typed error handling over string includes

If the SDK exposes structured error types/codes, show that pattern to avoid brittle string checks.

Apply this diff if applicable:

-} catch (error) {
-  if (error.message.includes("Payment amount exceeds maximum")) {
+} catch (error) {
+  if (error.code === "X402_MAX_EXCEEDED") {
     // Handle payment too expensive
-  } else if (error.message.includes("Wallet not connected")) {
+  } else if (error.code === "WALLET_NOT_CONNECTED") {
     // Handle wallet connection issues
-  } else if (error.message.includes("Payment already attempted")) {
+  } else if (error.code === "X402_ALREADY_ATTEMPTED") {
     // Handle retry scenarios
   } else {
     // Handle other errors (user rejected, insufficient funds, etc.)
   }

If no typed errors exist, keep string checks but note they’re subject to change.


217-237: Define serverWalletAddress in multi‑endpoint example

serverWalletAddress is used but not defined in this snippet.

Apply this diff:

 export const middleware = paymentMiddleware(
-  serverWalletAddress,
+  process.env.SERVER_WALLET_ADDRESS as string,
   {
     "/api/basic-data": {
       price: "$0.01",
       network: "base-sepolia",
       config: { description: "Basic data access" },
     },
     "/api/premium-analytics": {
       price: "$0.05",
       network: "base", // Use mainnet for higher-value endpoints
       config: { description: "Premium analytics data" },
     },
     "/api/ai-processing": {
       price: "$0.10",
       network: "base",
       config: { description: "AI-powered data processing" },
     },
   },
-  facilitator({ client, serverWalletAddress }), // thirdweb payment processor
+  facilitator({ client, serverWalletAddress: process.env.SERVER_WALLET_ADDRESS as string }), // thirdweb payment processor
 );

Optionally hoist the env into a const and validate as shown above.

📜 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.

📥 Commits

Reviewing files that changed from the base of the PR and between b5965b0 and d245b2e.

📒 Files selected for processing (1)
  • apps/portal/src/app/payments/x402/page.mdx (4 hunks)
🔇 Additional comments (7)
apps/portal/src/app/payments/x402/page.mdx (7)

63-64: Replace “automatic negotiation” — server advertises; client follows

Reword to avoid implying client‑led negotiation.

Apply this diff:

-- **Network selection**: Client and server automatically negotiate the best payment network
+- **Network selection**: Server advertises accepted network(s) in the 402 response; the client will build/send the payment on an advertised network if the connected wallet supports it.

205-210: Facilitator options typo fix LGTM

Options naming (client, serverWalletAddress) looks correct.

If this PR’s goal is solely the typo fix, confirm no other wording needs updating elsewhere in the page referencing these options.


83-84: Make gasless claims conditional and facilitator‑specific

Unqualified “gasless” is misleading; support depends on facilitator, token/network, and limits.

Apply this diff:

-- **Gasless transactions**: thirdweb covers all gas costs for payment processing
+- **Gasless transactions (when supported)**: A facilitator can sponsor gas so buyers pay no gas; availability and quotas depend on the facilitator, network/token support (e.g., EIP‑3009), and any plan limits.

- **Gasless payments**: Payment transfers are performed in gasless fashion to reduce friction
+ **Gasless payments (when supported)**: Transfers may be sponsored by the facilitator on supported networks/tokens.

Also applies to: 90-90


171-173: Imports verified — no changes needed

Confirmed that the npm package x402-next exports paymentMiddleware; the import in apps/portal/src/app/payments/x402/page.mdx (lines 171–173) is correct.


181-187: Config types confirmed — example is correct

price accepts USD strings like "$0.01" (implied USDC) or a TokenAmount for custom tokens; network accepts x402 network slugs such as "base-sepolia".


125-132: Confirmed: wrapFetchWithPayment signature & default max — add doc clarification

Verified: signature is wrapFetchWithPayment(fetch, client, wallet, maxValue: bigint) and omitting the 4th arg defaults to 1 USDC (6 decimals / base units).

Add a one-line clarification after the snippet in apps/portal/src/app/payments/x402/page.mdx (around lines 125–132):

"The 4th argument is the maximum payment in the token's smallest units (USDC has 6 decimals); omitting it defaults to 1 USDC. e.g. BigInt(5 * 10 ** 6) = 5 USDC."


49-59: Replace static supported networks/tokens with the canonical support matrix (or add an “as of” date)

Supported chains/tokens drift — either link to thirdweb’s live support pages or add “as of September 22, 2025” and confirm accuracy.

Location: apps/portal/src/app/payments/x402/page.mdx — lines 49–59 (also 61–62)

Canonical sources to link: thirdweb x402 facilitator docs; x402.wrapFetchWithPayment docs; thirdweb Universal Bridge (networks/tokens); thirdweb Supported Chains page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Portal Involves changes to the Portal (docs) codebase.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant