Skip to content

Conversation

MananTank
Copy link
Member

@MananTank MananTank commented Oct 7, 2025


PR-Codex overview

This PR introduces the authToken parameter across various components and API functions related to payments and webhooks, enhancing authentication handling. It also includes the implementation of new webhook functionalities, improving user interaction with webhook management.

Detailed summary

  • Added authToken prop to multiple components including PayAnalytics, PaymentHistory, and QuickStartSection.
  • Updated API functions to accept authToken for webhooks and payment links.
  • Introduced new webhook management UI components including WebhookCard.
  • Enhanced error handling and loading states for webhook operations.
  • Created new functions for updating and retrieving webhook details.
  • Improved UI for creating and editing webhooks with better user feedback.

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

Summary by CodeRabbit

  • New Features

    • Card-based Webhooks UI with create/edit modal, per-card actions, delete confirmation, webhook detail page, and webhook sends viewer (history, filtering, pagination, resend).
    • Payments area: authenticated payment links CRUD, paginated payments list, and resend/webhook-send actions.
  • Enhancements

    • authToken propagation across webhooks, payments, payment links, and fees to enable authenticated operations.
    • Webhook objects no longer expose secret fields; create/update/delete and resend operations return usable results.
  • Documentation

    • Storybook stories added for webhook sends UI (loading, results, error, resend scenarios).

Copy link

linear bot commented Oct 7, 2025

Copy link

vercel bot commented Oct 7, 2025

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

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

@vercel vercel bot temporarily deployed to Preview – nebula October 7, 2025 18:34 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 7, 2025 18:34 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 7, 2025 18:34 Inactive
Copy link

changeset-bot bot commented Oct 7, 2025

⚠️ No Changeset found

Latest commit: e74aca9

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

@vercel vercel bot temporarily deployed to Preview – wallet-ui October 7, 2025 18:34 Inactive
@github-actions github-actions bot added the Dashboard Involves changes to the Dashboard. label Oct 7, 2025
Copy link
Member Author

MananTank commented Oct 7, 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.

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Walkthrough

Adds authToken propagation across payments and webhooks UIs; expands the universal-bridge developer API to require auth tokens and adds webhook update, sends listing, and resend endpoints. Replaces webhooks table with a card-based CRUD UI and adds a Webhook Sends page/UI with pagination, detail view, and resend. Adds Storybook stories.

Changes

Cohort / File(s) Summary
Universal Bridge Developer API
apps/dashboard/src/@/api/universal-bridge/developer.ts
Refactored public API signatures to accept { authToken, clientId, teamId, ... }; exported Webhook (secret removed); added updateWebhook, getWebhookSends, resendWebhook; added WebhookSend and WebhookSendsResponse types; updated create/get/update/delete/payment/fee functions to use auth header and return parsed objects/booleans.
Payments — Analytics / History
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx, .../PaymentHistory.client.tsx
Added authToken prop; propagated token into PaymentHistory and its getPayments call.
Payment Links — Create / List / Delete
.../payments/links/components/CreatePaymentLinkButton.client.tsx, .../payments/links/components/PaymentLinksTable.client.tsx
Added authToken to component props and dialog content; forwarded authToken to createPaymentLink, getPaymentLinks, getPayments, and deletePaymentLink calls and mutation payloads; updated child prop types.
Payments Page Wiring / Quickstart
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx, .../QuickstartSection.client.tsx
Payments page now passes authToken to CreatePaymentLinkButton, PaymentLinksTable, and QuickStartSection; QuickStart forwards token to create flow.
Payments Settings (Fees)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx, .../settings/payments/page.tsx
Added authToken prop to PayConfig; getFees and updateFee calls now include authToken.
Webhooks — Payments List UI Overhaul
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/components/webhooks.client.tsx, apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
Replaced table with card-based UI and per-card dropdown actions; added WebhookCard, BridgeWebhookModalContent, EditPaymentWebhookButton, DeleteWebhookButton, CreatePaymentWebhookButton; threaded authToken, teamSlug, projectSlug; switched to getWebhooks/createWebhook/updateWebhook/deleteWebhook with authToken.
Webhook Sends Page and UI
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx, .../[id]/webhook-sends.tsx
New page loads auth/project, fetches webhook by id via getWebhookById, and renders WebhookSends. New client UI lists sends with pagination, selection, detail pane/dialog, payload/response formatting, and resendWebhook integration. Exports WebhookSends and WebhookSendsUI.
Storybook for Webhook Sends
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
Added Storybook stories with mock generators covering loading, various result sizes, empty, error, and resend error scenarios; stubs getWebhookSends and resendWebhook behaviors.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant Page as Webhooks Page
  participant API as Developer API
  participant UI as WebhookSends UI

  U->>Page: Navigate to /webhooks/payments/[id]
  Page->>API: fetch auth token & project
  Page->>API: getWebhookById({clientId, teamId, authToken, webhookId})
  API-->>Page: Webhook
  Page-->>UI: Render WebhookSends({webhookId, authToken, projectClientId, teamId})
  UI->>API: getWebhookSends({authToken, projectClientId, teamId, webhookId, limit, offset})
  API-->>UI: {data, pagination}
  U->>UI: Select item → UI shows details
  U->>UI: Click Resend
  UI->>API: resendWebhook({authToken, projectClientId, teamId, paymentId|onrampId})
  API-->>UI: 200 / error
  UI-->>U: show toast
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant List as Webhooks List UI
  participant API as Developer API

  U->>List: Click "Create Webhook"
  List->>List: Open modal (create)
  U->>List: Submit form
  List->>API: createWebhook({clientId, teamId, authToken, ...})
  API-->>List: Webhook
  List->>List: Close modal, refresh list

  U->>List: Edit webhook
  List->>List: Open modal (edit)
  U->>List: Submit updates
  List->>API: updateWebhook({clientId, teamId, webhookId, authToken, body})
  API-->>List: Webhook
  List->>List: Close modal, refresh list

  U->>List: Delete webhook
  List->>API: deleteWebhook({clientId, teamId, webhookId, authToken})
  API-->>List: true
  List->>List: Refresh list
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR encompasses extensive authToken prop propagation and payment link updates across various payment components and API functions, which are not addressed in the linked issue focused on webhook event listing and replay. These payment-related changes fall outside the scope of MNY-239’s objectives. Including them in this PR may complicate review and risk unrelated functionality. Consider isolating authToken and payment component updates into a separate PR or expand the linked issues to cover the introduced payment feature changes to maintain focused scope for each merge request.
Description Check ⚠️ Warning The PR description only contains the commented template and a high-level Codex overview without populating required sections such as the actual title, notes for the reviewer, and testing instructions. It fails to provide context on how to test or any reviewer guidance. This deviates from the repository’s description template. Fill out the PR description by replacing the template comments with a concise title following the repository guidelines, detailed reviewer notes, and clear testing steps including example commands or steps to verify the changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly identifies the issue tag and succinctly conveys the primary change of displaying webhook sends for Bridge webhooks. It aligns with the main objective of the PR by focusing on webhook event visibility. This makes the title clear and informative for team members reviewing the commit history.
Linked Issues Check ✅ Passed The implemented changes add endpoints and UI flows for listing webhook sends and replaying events, including getWebhookSends and resendWebhook functionality, and improve webhook UX through card-based interfaces. These updates directly satisfy the objectives of linked issue MNY-239 to display webhook events and provide a replay capability. They align with the referenced API endpoints and UX improvements specified in the issue.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10-08-_mny-239_payments_webhooks_updates

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.

@MananTank MananTank changed the title [MNY-239] Payments webhooks updates [MNY-239] Payments webhooks updates [WIP] Oct 7, 2025
Copy link

codecov bot commented Oct 7, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.02%. Comparing base (b0cac94) to head (e74aca9).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8213   +/-   ##
=======================================
  Coverage   55.02%   55.02%           
=======================================
  Files         919      919           
  Lines       60583    60583           
  Branches     4127     4127           
=======================================
  Hits        33335    33335           
  Misses      27145    27145           
  Partials      103      103           
Flag Coverage Δ
packages 55.02% <ø> (ø)
🚀 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 Oct 7, 2025

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
thirdweb (esm) 64.51 KB (0%) 1.3 s (0%) 145 ms (+166.42% 🔺) 1.5 s
thirdweb (cjs) 366.04 KB (0%) 7.4 s (0%) 550 ms (+6.79% 🔺) 7.9 s
thirdweb (minimal + tree-shaking) 5.73 KB (0%) 115 ms (0%) 81 ms (+3638.63% 🔺) 195 ms
thirdweb/chains (tree-shaking) 526 B (0%) 11 ms (0%) 41 ms (+3445.3% 🔺) 51 ms
thirdweb/react (minimal + tree-shaking) 19.13 KB (0%) 383 ms (0%) 63 ms (+2064.19% 🔺) 445 ms

@MananTank MananTank force-pushed the 10-08-_mny-239_payments_webhooks_updates branch from 7e188c6 to 5e2b22a Compare October 8, 2025 21:37
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 8, 2025 21:37 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 8, 2025 21:37 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 8, 2025 21:37 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 8, 2025 21:37 Inactive
@MananTank MananTank force-pushed the 10-08-_mny-239_payments_webhooks_updates branch from 5e2b22a to 38947bc Compare October 9, 2025 16:01
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 9, 2025 16:02 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 9, 2025 16:02 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 9, 2025 16:02 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 9, 2025 16:02 Inactive
@MananTank MananTank force-pushed the 10-08-_mny-239_payments_webhooks_updates branch from 38947bc to 6bed18b Compare October 9, 2025 16:07
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 9, 2025 16:07 Inactive
@vercel vercel bot temporarily deployed to Preview – nebula October 9, 2025 16:07 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: 4

Caution

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

⚠️ Outside diff range comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)

338-338: Fix incorrect button label.

The button text reads "Delete Webhook" but this component manages payment links, not webhooks. This appears to be a copy-paste artifact from webhook-related code.

Apply this diff:

-            Delete Webhook
+            Delete Payment
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)

15-37: Add explicit return types to async functions.

Multiple async functions are missing explicit return type annotations, which conflicts with the coding guideline: "Use explicit function declarations and explicit return types in TypeScript."

Apply this diff to add explicit return types:

-export async function getWebhooks(params: {
+export async function getWebhooks(params: {
   clientId: string;
   teamId: string;
   authToken: string;
-}) {
+}): Promise<Array<Webhook>> {

-export async function getWebhookById(params: {
+export async function getWebhookById(params: {
   clientId: string;
   teamId: string;
   authToken: string;
   webhookId: string;
-}) {
+}): Promise<Webhook> {

-export async function createWebhook(params: {
+export async function createWebhook(params: {
   clientId: string;
   teamId: string;
   version?: number;
   url: string;
   label: string;
   secret?: string;
   authToken: string;
-}) {
+}): Promise<Webhook> {

-export async function deleteWebhook(params: {
+export async function deleteWebhook(params: {
   clientId: string;
   teamId: string;
   webhookId: string;
   authToken: string;
-}) {
+}): Promise<boolean> {

-export async function updateWebhook(params: {
+export async function updateWebhook(params: {
   clientId: string;
   teamId: string;
   webhookId: string;
   authToken: string;
   body: {
     version?: number;
     url: string;
     label: string;
   };
-}) {
+}): Promise<Webhook> {

-export async function createPaymentLink(params: {
+export async function createPaymentLink(params: {
   clientId: string;
   teamId: string;
   title: string;
   imageUrl?: string;
   intent: {
     destinationChainId: number;
     destinationTokenAddress: Address;
     receiver: Address;
     amount: bigint;
     purchaseData?: unknown;
   };
   authToken: string;
-}) {
+}): Promise<PaymentLink> {

-export async function deletePaymentLink(params: {
+export async function deletePaymentLink(params: {
   clientId: string;
   teamId: string;
   paymentLinkId: string;
   authToken: string;
-}) {
+}): Promise<boolean> {

-export async function updateFee(params: {
+export async function updateFee(params: {
   clientId: string;
   teamId: string;
   feeRecipient: string;
   feeBps: number;
   authToken: string;
-}) {
+}): Promise<boolean> {

As per coding guidelines.

Also applies to: 39-65, 67-98, 100-125, 127-160, 333-378, 380-405, 438-465

♻️ Duplicate comments (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (2)

385-387: Invalidate with the full query key.

This issue was previously flagged. The query is registered with ["webhooks", props.clientId, props.teamId] at line 85, but this invalidation only uses ["webhooks", props.clientId]. The missing teamId prevents the cache from being invalidated correctly, leaving the UI stale after mutations.

Apply this diff:

     onSuccess: () => {
       return queryClient.invalidateQueries({
-        queryKey: ["webhooks", props.clientId],
+        queryKey: ["webhooks", props.clientId, props.teamId],
       });
     },

Note: This same issue exists at lines 525-527 and 566-568 and must be fixed in all locations.


398-400: Fix error message to reflect both create and edit operations.

This issue was previously flagged. The error toast always displays "Failed to create webhook" even when editing.

Apply this diff:

             onError: (err) => {
-              toast.error("Failed to create webhook", {
+              toast.error(`Failed to ${props.type === "create" ? "create" : "update"} webhook`, {
                 description: err instanceof Error ? err.message : undefined,
               });
             },
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (2)

459-474: Fix null check for onrampId.

The check if (webhookSend.onrampId) returns true for any truthy value, but since onrampId is string | null, this correctly returns "onramp" only when the ID exists. However, for clarity and to align with the bot's prior comment, consider being more explicit.

-  if (webhookSend.onrampId) {
+  if (webhookSend.onrampId !== null) {
     return "onramp";
   }
+  if (webhookSend.transactionId) {
+    return "transaction";
+  }

252-261: Correct the error message to match the checked identifier.

The error message states "No transaction or onramp ID found" but the code checks paymentId, not transactionId.

Apply this diff to fix the error message:

       } else {
-        throw new Error("No transaction or onramp ID found");
+        throw new Error("No paymentId or onrampId found for resend");
       }
🧹 Nitpick comments (8)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)

81-81: Include authToken in React Query keys for proper cache isolation.

The queryKeys at lines 81 and 102-107 omit authToken, which may cause cache collisions if different authenticated users access the same clientId/teamId combination. This could expose data across user sessions or fail to refresh when token changes.

Apply this diff to include authToken in the payment-links query:

-    queryKey: ["payment-links", props.clientId, props.teamId],
+    queryKey: ["payment-links", props.clientId, props.teamId, props.authToken],

Apply this diff to include authToken in the payment-link-usages query:

     queryKey: [
       "payment-link-usages",
       paymentLinksQuery.dataUpdatedAt,
       props.clientId,
       props.teamId,
+      props.authToken,
     ],

As per coding guidelines: "Use descriptive, stable queryKeys for React Query cache hits" and ensure proper cache scoping per authenticated user.

Also applies to: 102-107

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx (1)

13-20: Consider adding className prop for consistency.

Per the coding guidelines for dashboard components: "Expose a className prop on the root element of every component". While this component functions correctly without it, adding className support would improve reusability and allow parent components to adjust spacing or styling if needed.

 export function QuickStartSection(props: {
   teamSlug: string;
   projectSlug: string;
   clientId: string;
   teamId: string;
   projectWalletAddress?: string;
   authToken: string;
+  className?: string;
 }) {
   return (
-    <section>
+    <section className={props.className}>
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (1)

66-72: Consider exposing a className prop for layout flexibility.

The dashboard coding guidelines recommend exposing a className prop on the root element of components. While this component appears to be a page-level component, adding this prop would improve flexibility for future layout adjustments.

As per coding guidelines.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1)

34-36: Align mock success field with responseStatus.

The responseStatus is randomized to include error codes (500, 404), but success is hardcoded to true. This creates unrealistic mock data where failed deliveries (status >= 400) are marked as successful.

Apply this diff to derive success from responseStatus:

   const responseStatus =
     Math.random() > 0.5 ? (Math.random() > 0.5 ? 200 : 500) : 404;

+  const success = responseStatus >= 200 && responseStatus < 300;

Then use the computed value:

-    success: true,
+    success: success,
     responseStatus: responseStatus,

Also applies to: 136-136

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (2)

33-48: Consider exposing a className prop for flexibility.

Per coding guidelines, dashboard components should expose a className prop on their root element for styling flexibility. Both WebhookSends and WebhookSendsUI could benefit from this pattern.

As per coding guidelines.

Add className to the props type and apply it to the root div:

 type WebhookSendsProps = {
   webhookId: string;
   authToken: string;
   projectClientId: string;
   teamId: string;
+  className?: string;
 };

Then apply it to the root element:

   return (
-    <div className="pt-4">
+    <div className={cn("pt-4", props.className)}>

Also applies to: 90-91


66-83: Configure staleTime for optimal caching.

The React Query configuration is missing a staleTime setting. Adding this prevents unnecessary refetches and improves performance.

As per coding guidelines.

   const webhookSendsQuery = useQuery({
     queryKey: ["webhook-sends", props.webhookId, page],
     retry: false,
     refetchOnWindowFocus: false,
+    staleTime: 60_000, // 60 seconds
     queryFn: () =>
apps/dashboard/src/@/api/universal-bridge/developer.ts (2)

177-184: Export WebhookSendsResponse type.

WebhookSendsResponse is returned by getWebhookSends (Line 194) but is not exported. Callers may need this type to properly type the response.

Apply this diff:

-type WebhookSendsResponse = {
+export type WebhookSendsResponse = {
   data: WebhookSend[];
   pagination: {
     limit: number;
     offset: number;
     total: number;
   };
 };

222-225: Standardize error handling across API functions.

getWebhookSends and resendWebhook parse error responses as JSON and access .message (Lines 223-224, 264-265), while other functions use await res.text() (e.g., Lines 31-32). The JSON approach is fragile—it will throw if the error response is not JSON or lacks a message field.

For consistency and resilience, align with the pattern used elsewhere:

   if (!response.ok) {
-    const errorJson = await response.json();
-    throw new Error(errorJson.message);
+    const text = await response.text();
+    throw new Error(text);
   }

Apply this pattern to both getWebhookSends (Lines 222-225) and resendWebhook (Lines 263-266).

Also applies to: 263-266

📜 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 c7ea93d and 8542ebe.

📒 Files selected for processing (14)
  • apps/dashboard/src/@/api/universal-bridge/developer.ts (13 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (9 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (8)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
🧰 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

For new UI components, add Storybook stories (*.stories.tsx) alongside the code

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
apps/{dashboard,playground}/**/*.stories.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Add Storybook stories (*.stories.tsx) alongside new UI components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
🧠 Learnings (7)
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.stories.tsx : Add Storybook stories (`*.stories.tsx`) alongside new UI components

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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 **/*.stories.tsx : For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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/**/components/*.{stories,test}.{tsx,ts} : Provide a Storybook story (`MyComponent.stories.tsx`) or unit test alongside the component.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 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 PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
🧬 Code graph analysis (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1)
  • WebhookSendsUI (50-191)
apps/dashboard/src/@/api/universal-bridge/developer.ts (2)
  • getWebhookSends (186-228)
  • WebhookSend (162-175)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (3)
apps/dashboard/src/@/api/universal-bridge/developer.ts (3)
  • getWebhookSends (186-228)
  • resendWebhook (230-269)
  • WebhookSend (162-175)
apps/dashboard/src/@/components/blocks/pagination-buttons.tsx (1)
  • PaginationButtons (18-221)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
  • getPaymentLinks (290-331)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (4)
apps/dashboard/src/@/api/universal-bridge/developer.ts (4)
  • getWebhooks (15-37)
  • Webhook (6-13)
  • createWebhook (67-98)
  • updateWebhook (127-160)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/@/utils/usedapp-external.ts (1)
  • shortenString (3-7)
apps/dashboard/src/@/components/ui/checkbox.tsx (2)
  • CheckboxWithLabel (36-51)
  • Checkbox (34-34)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST (21-22)
⏰ 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 (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)

43-48: LGTM! AuthToken propagation is correctly implemented.

The authToken flow through the component hierarchy and into API calls follows secure patterns:

  • Props are explicitly typed as string
  • Token is passed via Authorization: Bearer header (confirmed in API code)
  • All mutations and queries properly receive the token

The implementation aligns with the broader PR objective of adding authentication across payment and webhook components.

Also applies to: 67-72, 73-82, 84-108, 137-142, 233-237, 282-288, 292-302

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1)

166-283: Excellent story coverage.

The stories comprehensively cover loading, success (with various result counts), empty, and error states. The intentionally long timeout in the Loading story effectively demonstrates the loading UI.

apps/dashboard/src/@/api/universal-bridge/developer.ts (1)

67-98: Align createWebhook response parsing with other methods.
createWebhook currently returns raw JSON as Webhook, whereas getWebhooks, getWebhookById, and updateWebhook use json.data. Confirm whether POST /v1/developer/webhooks returns a { data: Webhook } envelope; if so, change to return (await res.json()).data as Webhook;.

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: 1

♻️ Duplicate comments (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx (1)

30-30: Avoid exposing authToken in client components.

This client component ("use client") now receives authToken as a prop and passes it directly to API calls. This exposes the token in browser JavaScript, violating the coding guideline: "Keep tokens secret via internal API routes or server actions".

Recommendation: Refactor to use a server action or internal API route that reads the token from secure cookies server-side and performs the authenticated operation.

Based on learnings and coding guidelines.

Also applies to: 52-52

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx (1)

19-19: Avoid exposing authToken in client components.

This client component receives authToken and forwards it to CreatePaymentLinkButton, exposing the token in browser JavaScript. This violates the security guideline: "Keep tokens secret via internal API routes or server actions".

Please refactor to use server actions or internal API routes that handle authentication server-side.

Based on learnings and coding guidelines.

Also applies to: 50-50

🧹 Nitpick comments (4)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)

6-13: Consider documenting the optional version field.

The version field has a TODO comment indicating it should become mandatory after migration. Consider adding a JSDoc comment to clarify the migration timeline or expected behavior when this field is undefined.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1)

459-474: Verify the type extraction logic.

The function attempts to extract the event type from the webhook body. Consider adding a runtime type guard or validation for the type field to ensure type safety, especially since body is typed as unknown.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1)

172-174: Excessive timeout in Loading story.

The timeout of 1000000ms (1000 seconds) is unnecessarily long for a Storybook loading state. Consider reducing it to a more reasonable value like 30000ms (30 seconds) or using an infinite loading state without a timeout if you want to showcase the loading UI indefinitely.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (1)

206-206: Consider explicit date parsing for robustness.

While date-fns can handle ISO date strings, explicitly converting webhook.createdAt to a Date improves type safety and guards against future library version changes that may be stricter about input types.

Apply this diff:

           <p className="text-xs text-muted-foreground">
             Created{" "}
-            {formatDistanceToNow(webhook.createdAt, { addSuffix: true })}
+            {formatDistanceToNow(new Date(webhook.createdAt), { addSuffix: true })}
           </p>
📜 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 8542ebe and 305d0d8.

📒 Files selected for processing (14)
  • apps/dashboard/src/@/api/universal-bridge/developer.ts (13 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (9 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
🧰 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

For new UI components, add Storybook stories (*.stories.tsx) alongside the code

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
apps/{dashboard,playground}/**/*.stories.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Add Storybook stories (*.stories.tsx) alongside new UI components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
🧠 Learnings (11)
📚 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 : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
📚 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/**/api/**/*.{ts,tsx} : Pass the token in the `Authorization: Bearer` header – never embed it in the URL.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
📚 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} : Keep tokens secret via internal API routes or server actions

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.stories.tsx : Add Storybook stories (`*.stories.tsx`) alongside new UI components

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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/**/components/*.{stories,test}.{tsx,ts} : Provide a Storybook story (`MyComponent.stories.tsx`) or unit test alongside the component.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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 **/*.stories.tsx : For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
📚 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 PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 Learning: 2025-05-21T05:17:31.283Z
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
🧬 Code graph analysis (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1)
  • WebhookSendsUI (50-191)
apps/dashboard/src/@/api/universal-bridge/developer.ts (2)
  • getWebhookSends (186-228)
  • WebhookSend (162-175)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (4)
apps/dashboard/src/@/api/universal-bridge/developer.ts (4)
  • getWebhooks (15-37)
  • Webhook (6-13)
  • createWebhook (67-98)
  • updateWebhook (127-160)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/@/utils/usedapp-external.ts (1)
  • shortenString (3-7)
apps/dashboard/src/@/components/ui/checkbox.tsx (2)
  • CheckboxWithLabel (36-51)
  • Checkbox (34-34)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx (1)
  • Page (6-29)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
  • getWebhookById (39-65)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1)
  • WebhookSends (40-48)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (3)
apps/dashboard/src/@/api/universal-bridge/developer.ts (3)
  • getWebhookSends (186-228)
  • resendWebhook (230-269)
  • WebhookSend (162-175)
apps/dashboard/src/@/components/blocks/pagination-buttons.tsx (1)
  • PaginationButtons (18-221)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST (21-22)
⏰ 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). (5)
  • GitHub Check: Size
  • GitHub Check: E2E Tests (pnpm, esbuild)
  • GitHub Check: Unit Tests
  • GitHub Check: Lint Packages
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (10)
apps/dashboard/src/@/api/universal-bridge/developer.ts (2)

162-175: Well-structured type definition.

The WebhookSend type clearly models the webhook event data with appropriate nullable fields and discriminated union-friendly structure.


186-228: Solid implementation of paginated webhook sends.

The getWebhookSends function properly:

  • Uses URL search params for filters
  • Includes authentication headers
  • Handles errors with descriptive messages
  • Returns properly typed response
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (1)

23-23: Proper async handling of params.

Correctly awaits the params Promise as required in Next.js server components.

Based on learnings.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (2)

25-144: Comprehensive mock data generator.

The createMockWebhookSendItem function provides realistic test data covering multiple scenarios (bridge vs onramp, various statuses, JSON vs text responses), which is excellent for testing the UI across different states.


166-283: Excellent story coverage.

The stories cover all important UI states: loading, various data counts, empty state, error state, and resend error. This comprehensive coverage will help catch visual regressions and validate UX across different scenarios.

Based on coding guidelines requiring Storybook stories for new UI components.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx (1)

24-26: LGTM! Props correctly threaded for webhook operations.

The addition of teamSlug, projectSlug, and authToken props enables authenticated webhook API calls and proper routing in the client component, consistent with the broader PR pattern.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (4)

66-72: LGTM! Props properly typed for webhook operations.

The interface updates add the necessary identifiers (teamSlug, projectSlug) and authentication (authToken) required for webhook API calls and navigation throughout the component tree.


74-145: LGTM! Card-based layout improves UX.

The refactor from table to card-based layout with per-webhook actions (via dropdown) provides a modern, intuitive interface. The query correctly passes authToken, and the empty state clearly guides users to create their first webhook.


344-505: LGTM! Unified modal content with type-safe discrimination.

The discriminated union pattern cleanly handles create vs edit flows while sharing common form logic. The secret confirmation workflow (create-only) ensures users securely store credentials before proceeding.


507-581: LGTM! Delete confirmation with proper mutation handling.

The delete flow provides clear confirmation dialog and proper error/success handling with toast notifications.

Comment on lines +33 to +38
type WebhookSendsProps = {
webhookId: string;
authToken: string;
projectClientId: string;
teamId: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid exposing authToken in client components.

This client component receives authToken as a prop and uses it directly in React Query calls (line 73), exposing the token in browser JavaScript. According to coding guidelines: "Keep tokens secret via internal API routes or server actions".

Recommendation: Create a server action or internal API route (/api/...) that reads the token from secure cookies and proxies the getWebhookSends request server-side. The client component should call this API route without handling the token directly.

Based on learnings and coding guidelines.

Also applies to: 73-73

<!--

## title your PR with this format: "[SDK/Dashboard/Portal] Feature/Fix: Concise title for the changes"

If you did not copy the branch name from Linear, paste the issue tag here (format is TEAM-0000):

## Notes for the reviewer

Anything important to call out? Be sure to also clarify these in your comments.

## How to test

Unit tests, playground, etc.

-->

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing the payment and webhook functionalities in the dashboard application by adding `authToken` support across various components and improving the webhook management interface.

### Detailed summary
- Added `authToken` prop to multiple components including `PayAnalytics`, `PaymentHistory`, and `QuickStartSection`.
- Enhanced `getWebhooks`, `createWebhook`, `deleteWebhook`, and `updateWebhook` functions to accept `authToken`.
- Improved the webhook management UI with `WebhookCard` and related functionalities.
- Added dialog components for creating and editing webhooks with validation.
- Updated API calls to include `authToken` for authentication in requests.

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

<!-- end pr-codex -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Card-based webhooks UI with create/edit modal, per-card actions, delete confirmation, webhook detail page, and webhook sends viewer (history, filtering, pagination, resend).
  - Payments area: payment links and payments viewer wired to authenticated CRUD and paginated payments list; resend and webhook-send actions supported.

- **Enhancements**
  - authToken propagated across webhooks, payments, payment links, fees, and related components to enable authenticated operations.
  - Webhook objects no longer expose secret fields; create/update/delete now return usable payloads.

- **Documentation**
  - Storybook stories added for webhook sends UI (loading, results, error, resend scenarios).
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@graphite-app graphite-app bot force-pushed the 10-08-_mny-239_payments_webhooks_updates branch from 305d0d8 to e74aca9 Compare October 13, 2025 21:28
@vercel vercel bot temporarily deployed to Preview – nebula October 13, 2025 21:28 Inactive
@vercel vercel bot temporarily deployed to Preview – docs-v2 October 13, 2025 21:28 Inactive
@vercel vercel bot temporarily deployed to Preview – wallet-ui October 13, 2025 21:28 Inactive
@vercel vercel bot temporarily deployed to Preview – thirdweb_playground October 13, 2025 21:29 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: 5

Caution

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

⚠️ Outside diff range comments (4)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (1)

47-54: Remove authToken from client props; route create via server.

This client component receives and uses authToken for network calls, exposing secrets in browser JS. Replace direct calls to createPaymentLink with:

  • a Next.js server action, or
  • an internal API route that reads the token from secure cookies and proxies the request.

Component should call the server action/route without handling secrets. As per coding guidelines.

Also applies to: 61-67, 73-79, 121-133

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (3)

43-48: Do not expose authToken in client; proxy via server actions/internal routes.

authToken is accepted/passed through and used in client-side fetches/mutations, exposing it in browser JS. Move these calls behind server actions or internal API routes that read the token from cookies. Pass only non-secret params from the client. As per coding guidelines.

Also applies to: 57-63, 67-72, 73-81, 84-95, 137-143, 233-241, 282-289, 292-300


336-341: Fix button label: this deletes a payment link, not a webhook.

Change the button text to avoid user confusion.

Apply this diff:

-            Delete Webhook
+            Delete Payment

205-221: Avoid precision loss in revenue sum; accumulate as BigInt then format once.

Using Number(toTokens(...)) can lose precision for large values. Sum raw wei as BigInt and call toTokens once.

Apply this diff:

-                      ) : (
-                        `${(
-                          paymentLinkUsagesQuery.data
-                            ?.find((x) => x.paymentLink.id === paymentLink.id)
-                            ?.usages?.reduce(
-                              (acc, curr) =>
-                                acc +
-                                Number(
-                                  toTokens(
-                                    BigInt(curr.destinationAmount),
-                                    curr.destinationToken.decimals,
-                                  ),
-                                ),
-                              0,
-                            ) || 0
-                        ).toString()} ${paymentLink.destinationToken.symbol}`
-                      )}
+                      ) : (
+                        (() => {
+                          const totalWei =
+                            paymentLinkUsagesQuery.data
+                              ?.find((x) => x.paymentLink.id === paymentLink.id)
+                              ?.usages?.reduce(
+                                (acc, curr) => acc + BigInt(curr.destinationAmount),
+                                0n,
+                              ) ?? 0n;
+                          const total = toTokens(
+                            totalWei,
+                            paymentLink.destinationToken.decimals,
+                          );
+                          return `${total} ${paymentLink.destinationToken.symbol}`;
+                        })()
+                      )}
♻️ Duplicate comments (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx (1)

19-20: authToken exposure in client component props (duplicate of earlier review).

Passing authToken into this client component and forwarding it exposes the token to the browser. Please follow the prior guidance to use server actions/internal API routes instead.

Also applies to: 46-51

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (4)

177-184: Add aria-label to the dropdown trigger (duplicate of prior review).

The icon-only trigger needs an accessible name.

Apply this diff:

           <Button
             size="icon"
             variant="ghost"
             className="absolute right-4 top-4"
+            aria-label="Webhook actions"
           >

384-388: Invalidate with the full query key (duplicate of prior review).

Include teamId (and any other parts) so mutations refetch the list registered under ["webhooks", clientId, teamId].

Also applies to: 525-527, 566-569


397-401: Use operation-appropriate error message (duplicate of prior review).

Show "Failed to create webhook" vs "Failed to update webhook" based on props.type.


254-264: Add explicit return types to async handlers (duplicate of prior review).

Annotate as Promise to satisfy TS guidelines.

Also applies to: 299-311

🧹 Nitpick comments (6)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (1)

1-1: Mark server component explicitly.

Add the server-only marker at the top to prevent accidental client bundling.

Apply this diff:

+import "server-only";
 import Link from "next/link";

As per coding guidelines.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (1)

94-100: Set a sensible staleTime for queries.

Add staleTime ≥ 60s per guidelines to avoid refetch churn.

Apply this diff:

   const chainsQuery = useQuery({
     queryFn: async () => {
       return await Bridge.chains({ client });
     },
-    queryKey: ["payments-chains"],
+    queryKey: ["payments-chains"],
+    staleTime: 60_000,
   });

As per coding guidelines.

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)

72-83: Add staleTime to queries to reduce refetch churn.

Set staleTime ≥ 60s on both queries.

Apply these diffs:

   const paymentLinksQuery = useQuery({
     queryFn: async () => {
       return getPaymentLinks({
         clientId: props.clientId,
         teamId: props.teamId,
         authToken: props.authToken,
       });
     },
-    queryKey: ["payment-links", props.clientId, props.teamId],
+    queryKey: ["payment-links", props.clientId, props.teamId],
+    staleTime: 60_000,
   });
   const paymentLinkUsagesQuery = useQuery({
     queryFn: async () => {
       const paymentLinks = paymentLinksQuery.data || [];
       return await Promise.all(
         paymentLinks.map(async (paymentLink) => {
           const { data } = await getPayments({
             authToken: props.authToken,
             clientId: props.clientId,
             teamId: props.teamId,
             paymentLinkId: paymentLink.id,
           });
           return {
             paymentLink,
             usages: data,
           };
         }),
       );
     },
     queryKey: [
       "payment-link-usages",
       paymentLinksQuery.dataUpdatedAt,
       props.clientId,
       props.teamId,
     ],
+    staleTime: 60_000,
   });

As per coding guidelines.

Also applies to: 84-108

apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (1)

75-86: Add staleTime to the webhooks list query.

Reduce unnecessary refetches and align with guidelines.

Apply this diff:

   const webhooksQuery = useQuery({
     queryFn: async () => {
       const res = await getWebhooks({
         clientId: props.clientId,
         teamId: props.teamId,
         authToken: props.authToken,
       });
 
       return res;
     },
-    queryKey: ["webhooks", props.clientId, props.teamId],
+    queryKey: ["webhooks", props.clientId, props.teamId],
+    staleTime: 60_000,
   });

As per coding guidelines.

apps/dashboard/src/@/api/universal-bridge/developer.ts (2)

177-184: Export WebhookSendsResponse type.

The WebhookSendsResponse type is returned by getWebhookSends and may be needed by consumers for type-safe usage. Export it for consistency with other public types.

Apply this diff:

-type WebhookSendsResponse = {
+export type WebhookSendsResponse = {
   data: WebhookSend[];
   pagination: {
     limit: number;
     offset: number;
     total: number;
   };
 };

30-33: Consider structured error handling.

All error paths throw new Error(text) without context. Consider creating a structured error class that includes status code, error code, and request details to help consumers distinguish and handle different error types.

Example:

class ApiError extends Error {
  constructor(
    message: string,
    public statusCode: number,
    public errorCode?: string,
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

Also applies to: 58-61, 92-95, 119-122, 152-155, 222-225, 263-266

📜 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 305d0d8 and e74aca9.

📒 Files selected for processing (14)
  • apps/dashboard/src/@/api/universal-bridge/developer.ts (13 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx (4 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (8 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (9 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx (2 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1 hunks)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PayAnalytics.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/PayConfig.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/PaymentHistory.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/settings/payments/page.tsx
🧰 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 local types.ts barrels
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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
Prefer type aliases over interface except for nominal shapes
Avoid any and unknown 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:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Load heavy dependencies inside async paths to keep initial bundle lean (lazy loading)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
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
Use NavLink for internal navigation with automatic active states in dashboard and playground apps
Use Tailwind CSS only – no inline styles or CSS modules
Use cn() 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 with import "server-only";
Client Components (browser): Begin files with 'use client';
Always call getAuthToken() to retrieve JWT from cookies on server side
Use Authorization: Bearer header – never embed tokens in URLs
Return typed results (e.g., Project[], User[]) – avoid any
Wrap client-side data fetching calls in React Query (@tanstack/react-query)
Use descriptive, stable queryKeys for React Query cache hits
Configure staleTime/cacheTime in React Query based on freshness (default ≥ 60s)
Keep tokens secret via internal API routes or server actions
Never import posthog-js in server components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
apps/{dashboard,playground}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

apps/{dashboard,playground}/**/*.{ts,tsx}: Import UI primitives from @/components/ui/_ (e.g., Button, Input, Tabs, Card)
Use NavLink for internal navigation to get active state handling
Use Tailwind CSS for styling; no inline styles
Merge class names with cn() from @/lib/utils for conditional classes
Stick to design tokens (e.g., bg-card, border-border, text-muted-foreground)
Server Components must start with import "server-only"; use next/headers, server‑only env, heavy data fetching, and redirect() where appropriate
Client Components must start with 'use client'; handle interactivity with hooks and browser APIs
Server-side data fetching: call getAuthToken() from cookies, send Authorization: Bearer <token> header, and return typed results (avoid any)
Client-side data fetching: wrap calls in React Query with descriptive, stable queryKeys and set sensible staleTime/cacheTime (≥ 60s default); keep tokens secret via internal routes or server actions
Do not import posthog-js in server components (client-side only)

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/@/api/universal-bridge/developer.ts
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
apps/{dashboard,playground}/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Expose a className prop on the root element of every component

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/CreatePaymentLinkButton.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
**/*.stories.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

For new UI components, add Storybook stories (*.stories.tsx) alongside the code

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
apps/{dashboard,playground}/**/*.stories.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Add Storybook stories (*.stories.tsx) alongside new UI components

Files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
🧠 Learnings (11)
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 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 PR #7888.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 Learning: 2025-05-21T05:17:31.283Z
Learnt from: jnsdls
PR: thirdweb-dev/js#6929
File: apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx:14-19
Timestamp: 2025-05-21T05:17:31.283Z
Learning: In Next.js server components, the `params` object can sometimes be a Promise that needs to be awaited, despite type annotations suggesting otherwise. In apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/insight/webhooks/page.tsx, it's necessary to await the params object before accessing its properties.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
📚 Learning: 2025-08-29T15:37:38.513Z
Learnt from: CR
PR: thirdweb-dev/js#0
File: AGENTS.md:0-0
Timestamp: 2025-08-29T15:37:38.513Z
Learning: Applies to apps/{dashboard,playground}/**/*.stories.tsx : Add Storybook stories (`*.stories.tsx`) alongside new UI components

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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/**/components/*.{stories,test}.{tsx,ts} : Provide a Storybook story (`MyComponent.stories.tsx`) or unit test alongside the component.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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 **/*.stories.tsx : For new UI components, add Storybook stories (`*.stories.tsx`) alongside the code

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx
📚 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 : Prefer API routes or server actions to keep tokens secret; the browser only sees relative paths.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
📚 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/**/api/**/*.{ts,tsx} : Pass the token in the `Authorization: Bearer` header – never embed it in the URL.

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
📚 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} : Keep tokens secret via internal API routes or server actions

Applied to files:

  • apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/components/QuickstartSection.client.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
📚 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/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
🧬 Code graph analysis (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx (3)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/page.tsx (1)
  • Page (6-29)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
  • getWebhookById (39-65)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (2)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/webhook-sends.tsx (1)
  • WebhookSendsUI (50-191)
apps/dashboard/src/@/api/universal-bridge/developer.ts (2)
  • getWebhookSends (186-228)
  • WebhookSend (162-175)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/links/components/PaymentLinksTable.client.tsx (1)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
  • getPaymentLinks (290-331)
apps/dashboard/src/@/api/universal-bridge/developer.ts (1)
apps/dashboard/src/@/constants/public-envs.ts (1)
  • NEXT_PUBLIC_THIRDWEB_BRIDGE_HOST (21-22)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx (4)
apps/dashboard/src/@/api/universal-bridge/developer.ts (4)
  • getWebhooks (15-37)
  • Webhook (6-13)
  • createWebhook (67-98)
  • updateWebhook (127-160)
apps/dashboard/src/@/components/ui/CopyTextButton.tsx (1)
  • CopyTextButton (9-68)
apps/dashboard/src/@/utils/usedapp-external.ts (1)
  • shortenString (3-7)
apps/dashboard/src/@/components/ui/checkbox.tsx (2)
  • CheckboxWithLabel (36-51)
  • Checkbox (34-34)
⏰ 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 (5)
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/WebhookSendsUI.stories.tsx (1)

8-18: Stories look solid.

Good coverage of loading/success/error scenarios with typed mocks.

Also applies to: 166-183

apps/dashboard/src/@/api/universal-bridge/developer.ts (4)

15-37: LGTM: Authentication implementation.

All API functions correctly implement Bearer token authentication with proper header usage (Authorization: Bearer, x-client-id, x-team-id). Tokens are never embedded in URLs, following security best practices.

Also applies to: 39-65, 67-98, 100-125, 127-160, 186-228, 230-269


46-46: LGTM: Path parameter encoding.

All dynamic path parameters are properly encoded using encodeURIComponent, preventing path traversal and handling special characters correctly.

Also applies to: 107-107, 139-139, 387-387


230-254: LGTM: Discriminated union type for resendWebhook.

The discriminated union enforces that callers provide either paymentId or onrampId (but not both) at compile time, which is excellent type safety. The implementation correctly serializes the appropriate field based on the discriminant.


186-228: LGTM: getWebhookSends implementation.

The function correctly uses the URL API for safe query parameter construction, properly handles optional parameters, and includes an explicit return type.

Comment on lines +15 to +19
export async function getWebhooks(params: {
clientId: string;
teamId: string;
authToken: string;
}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add explicit return types to async functions.

Per coding guidelines, all functions must have explicit return types. The following functions are missing return type annotations:

  • getWebhooksPromise<Webhook[]>
  • getWebhookByIdPromise<Webhook>
  • createWebhookPromise<Webhook>
  • deleteWebhookPromise<boolean>
  • updateWebhookPromise<Webhook>
  • resendWebhookPromise<boolean>
  • createPaymentLinkPromise<PaymentLink>
  • deletePaymentLinkPromise<boolean>
  • getFeesPromise<Fee>
  • updateFeePromise<boolean>
  • getPaymentsPromise<PaymentsResponse>

As per coding guidelines.

Example for getWebhooks:

-export async function getWebhooks(params: {
+export async function getWebhooks(params: {
   clientId: string;
   teamId: string;
   authToken: string;
-}) {
+}): Promise<Webhook[]> {

Also applies to: 39-44, 67-75, 100-105, 127-137, 230-243, 333-346, 380-385, 414-418, 438-444, 521-528

🤖 Prompt for AI Agents
In apps/dashboard/src/@/api/universal-bridge/developer.ts around lines 15-19
(and also update the functions at the listed ranges 39-44, 67-75, 100-105,
127-137, 230-243, 333-346, 380-385, 414-418, 438-444, 521-528), add explicit
TypeScript return type annotations to each async function per the coding
guidelines (e.g. getWebhooks: Promise<Webhook[]>, getWebhookById:
Promise<Webhook>, createWebhook: Promise<Webhook>, deleteWebhook:
Promise<boolean>, updateWebhook: Promise<Webhook>, resendWebhook:
Promise<boolean>, createPaymentLink: Promise<PaymentLink>, deletePaymentLink:
Promise<boolean>, getFees: Promise<Fee>, updateFee: Promise<boolean>,
getPayments: Promise<PaymentsResponse>), ensuring the declared return types
match the actual resolved values returned by each function and updating any
imports/types if needed.

Comment on lines 66 to 72
type PayWebhooksPageProps = {
clientId: string;
teamId: string;
teamSlug: string;
authToken: string;
projectSlug: string;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Do not expose authToken in client; move fetches/mutations server-side.

This file accepts and uses authToken in client-side queries/mutations, exposing secrets. Use server actions or internal API routes that read the token from cookies; keep client free of secrets. As per coding guidelines.

Also applies to: 75-85, 186-199, 507-512, 517-523

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
around lines 66-72 (and also affecting lines 75-85, 186-199, 507-512, 517-523):
the component currently accepts and uses authToken in client-side props which
exposes secrets; remove authToken from the client props and stop doing
fetches/mutations with it in the browser. Instead implement server-side handlers
(either Next.js server actions or internal API routes) that read the auth token
from secure cookies/session on the server, move all fetch/mutation logic into
those server endpoints/actions, update the client component to call those
endpoints/actions (passing only non-secret data like IDs or slugs), and update
the component prop types and all call sites to stop passing authToken. Ensure
error handling and types are preserved, and audit the listed line ranges to
remove any remaining direct uses of authToken in client code.

Comment on lines +205 to +207
Created{" "}
{formatDistanceToNow(webhook.createdAt, { addSuffix: true })}
</p>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix type error: pass a Date to formatDistanceToNow.

createdAt is a string; date-fns expects Date | number.

Apply this diff:

-            {formatDistanceToNow(webhook.createdAt, { addSuffix: true })}
+            {formatDistanceToNow(new Date(webhook.createdAt), { addSuffix: true })}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Created{" "}
{formatDistanceToNow(webhook.createdAt, { addSuffix: true })}
</p>
Created{" "}
{formatDistanceToNow(new Date(webhook.createdAt), { addSuffix: true })}
</p>
🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/payments/webhooks/components/webhooks.client.tsx
around lines 205-207, formatDistanceToNow is being passed webhook.createdAt
which is a string; convert it to a Date (or timestamp) before calling
formatDistanceToNow. Update the call to pass new Date(webhook.createdAt) (or
Date.parse(webhook.createdAt)) and optionally guard against invalid dates (e.g.,
check isNaN(date.getTime()) and provide a fallback) so the function receives a
Date | number as required.

Comment on lines +38 to +41
if (!webhook) {
notFound();
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unreachable check for missing webhook.

getWebhookById throws on non-OK responses; this if (!webhook) notFound() never runs. Either:

  • catch and map 404 to notFound here, or
  • change getWebhookById to return null on 404.

Otherwise remove the dead check to avoid confusion.

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
around lines 38-41, the if (!webhook) notFound() check is unreachable because
getWebhookById throws on non-OK responses; either wrap the call in a try/catch
and call notFound() when the caught error indicates a 404, or change
getWebhookById to return null for 404 responses so the existing null-check is
meaningful; remove the dead check if you choose to keep throwing behavior and
handle routing upstream.

Comment on lines +75 to +80
<WebhookSends
webhookId={params.id}
authToken={authToken}
projectClientId={project.publishableKey}
teamId={project.teamId}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Do not pass authToken to client components; proxy via server actions/internal API.

authToken is forwarded to WebhookSends (client), exposing it in browser JS. Move fetches/resend to a server action or an internal API route that reads the token from cookies. Pass only non-secret data/IDs to the client. As per coding guidelines.

🤖 Prompt for AI Agents
In
apps/dashboard/src/app/(app)/team/[team_slug]/[project_slug]/(sidebar)/webhooks/payments/[id]/page.tsx
around lines 75-80, you are passing authToken into the client component
WebhookSends which exposes secrets to browser JS; remove the authToken prop and
instead implement a server-side endpoint or Next.js server action that performs
fetches/resend using the auth token read from cookies/session on the server,
then have WebhookSends call that internal API (or invoke the server action) with
only non-secret identifiers (webhookId, projectClientId, teamId) so all
sensitive operations remain server-side.

@graphite-app graphite-app bot merged commit e74aca9 into main Oct 13, 2025
24 checks passed
@graphite-app graphite-app bot deleted the 10-08-_mny-239_payments_webhooks_updates branch October 13, 2025 21:38
@vercel vercel bot temporarily deployed to Production – thirdweb_playground October 13, 2025 21:38 Inactive
@vercel vercel bot temporarily deployed to Production – wallet-ui October 13, 2025 21:38 Inactive
@vercel vercel bot temporarily deployed to Production – nebula October 13, 2025 21:38 Inactive
@vercel vercel bot temporarily deployed to Production – docs-v2 October 13, 2025 21:38 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dashboard Involves changes to the Dashboard.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants