-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Retry stripe payouts after account verification #3166
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughThe account-updated Stripe webhook now integrates QStash queue messaging to handle pending payouts. When payout updates occur, the system checks for pending "sent" internal payouts and enqueues balance availability processing. A test retry interval is increased from 300ms to 600ms. Changes
Sequence Diagram(s)sequenceDiagram
participant Stripe
participant Webhook as account-updated webhook
participant QStash
participant CronAPI as /api/cron/payouts/balance-available
Stripe->>Webhook: POST payout update event
Webhook->>Webhook: Process payout updates
Webhook->>Webhook: Query pending payouts (status="sent", mode="internal")
alt Pending payouts exist
Webhook->>QStash: Enqueue balance-available request<br/>(deduplicationId: Stripe event ID)
QStash->>CronAPI: Trigger payout processing
CronAPI->>CronAPI: Handle pending payouts
end
Webhook->>Stripe: Return success
Estimated code review effortπ― 3 (Moderate) | β±οΈ ~20 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touchesβ Failed checks (1 warning)
β Passed checks (2 passed)
β¨ Finishing touches
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
π§Ή Nitpick comments (1)
apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts (1)
134-134: Consider adding non-null assertion for consistency.Line 51 uses
partner.stripeConnectId!but this line omits it. While the value is guaranteed to exist (since the partner was found by this field), adding the assertion would be consistent with the rest of the file.body: { - stripeAccount: partner.stripeConnectId, + stripeAccount: partner.stripeConnectId!, },
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (2)
apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts(2 hunks)apps/web/tests/fraud/index.test.ts(1 hunks)
π§° Additional context used
π§ Learnings (4)
π Common learnings
Learnt from: steven-tey
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-06-19T01:46:45.723Z
Learning: PayPal webhook verification in the Dub codebase is handled at the route level in `apps/web/app/(ee)/api/paypal/webhook/route.ts` using the `verifySignature` function. Individual webhook handlers like `payoutsItemFailed` don't need to re-verify signatures since they're only called after successful verification.
Learnt from: devkiran
Repo: dubinc/dub PR: 2635
File: packages/prisma/schema/payout.prisma:24-25
Timestamp: 2025-07-11T16:28:55.693Z
Learning: In the Dub codebase, multiple payout records can now share the same stripeTransferId because payouts are grouped by partner and processed as single Stripe transfers. This is why the unique constraint was removed from the stripeTransferId field in the Payout model - a single transfer can include multiple payouts for the same partner.
Learnt from: steven-tey
Repo: dubinc/dub PR: 0
File: :0-0
Timestamp: 2025-06-25T21:20:59.837Z
Learning: In the Dub codebase, payout limit validation uses a two-stage pattern: server actions perform quick sanity checks (payoutsUsage > payoutsLimit) for immediate user feedback, while the cron job (/cron/payouts) performs authoritative validation (payoutsUsage + payoutAmount > payoutsLimit) with actual calculated amounts before processing. This design provides fast user feedback while ensuring accurate limit enforcement at transaction time.
π Learning: 2025-11-24T09:10:12.536Z
Learnt from: devkiran
Repo: dubinc/dub PR: 3089
File: apps/web/lib/api/fraud/fraud-rules-registry.ts:17-25
Timestamp: 2025-11-24T09:10:12.536Z
Learning: In apps/web/lib/api/fraud/fraud-rules-registry.ts, the fraud rules `partnerCrossProgramBan` and `partnerDuplicatePayoutMethod` intentionally have stub implementations that return `{ triggered: false }` because they are partner-scoped rules handled separately during partner application/onboarding flows (e.g., in detect-record-fraud-application.ts), rather than being evaluated per conversion event like other rules in the registry. The stubs exist only to satisfy the `Record<FraudRuleType, ...>` type constraint.
Applied to files:
apps/web/tests/fraud/index.test.ts
π Learning: 2025-08-25T21:41:06.073Z
Learnt from: steven-tey
Repo: dubinc/dub PR: 2758
File: apps/web/app/(ee)/api/cron/payouts/balance-available/route.ts:43-45
Timestamp: 2025-08-25T21:41:06.073Z
Learning: For Stripe API calls on connected accounts, the stripeAccount parameter should be passed in the first parameter object (e.g., stripe.balance.retrieve({ stripeAccount })), not as request options in the second parameter.
Applied to files:
apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts
π Learning: 2025-07-11T16:28:55.693Z
Learnt from: devkiran
Repo: dubinc/dub PR: 2635
File: packages/prisma/schema/payout.prisma:24-25
Timestamp: 2025-07-11T16:28:55.693Z
Learning: In the Dub codebase, multiple payout records can now share the same stripeTransferId because payouts are grouped by partner and processed as single Stripe transfers. This is why the unique constraint was removed from the stripeTransferId field in the Payout model - a single transfer can include multiple payouts for the same partner.
Applied to files:
apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts
𧬠Code graph analysis (1)
apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts (1)
packages/prisma/index.ts (1)
prisma(3-9)
β° 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). (1)
- GitHub Check: build
π Additional comments (3)
apps/web/tests/fraud/index.test.ts (1)
257-257: Reasonable timing adjustment.Doubling the retry interval from 300ms to 600ms (total max wait from 3s to 6s) should help reduce test flakiness, especially with the new async queue-based payout processing introduced in this PR.
apps/web/app/(ee)/api/stripe/connect/webhook/account-updated.ts (2)
8-10: LGTM!Module-level queue initialization is appropriate for reuse across webhook invocations.
118-137: Solid implementation for retrying stuck payouts.The logic correctly:
- Only triggers when there are pending payouts (
status: "sent",mode: "internal")- Uses
event.idasdeduplicationIdfor idempotency, preventing duplicate queue entries on webhook retriesLetting queue failures propagate (rather than catching them) is reasonable here since Stripe will retry the webhook, and the deduplicationId ensures no duplicates on success.
Summary by CodeRabbit
βοΈ Tip: You can customize this high-level summary in your review settings.