feat(payments-next): Move subscription creation after SetupIntent validation#20523
Open
david1alvarez wants to merge 1 commit intomainfrom
Open
feat(payments-next): Move subscription creation after SetupIntent validation#20523david1alvarez wants to merge 1 commit intomainfrom
david1alvarez wants to merge 1 commit intomainfrom
Conversation
…idation Because: * Currently if a SetupIntent fails, the subscription has been created in Stripe already. When the SetupIntent fails, we cancel the created subscription. This causes the creation and cancellation Stripe webhooks to fire, which triggers unexpected emails for the customer. This commit: * In the case of creating a subscription via a SetupIntent, the subscription creation is processed once the SetupIntent has been confirmed. Closes #PAY-3675
Contributor
There was a problem hiding this comment.
Pull request overview
This PR changes the zero-initial Stripe checkout flow in payments-next so subscriptions are created only after a SetupIntent has been validated, aiming to avoid create/cancel webhook churn and the customer emails that follow from failed SetupIntents.
Changes:
- Adds a setup-intent-first Stripe path for free-trial and zero-amount checkouts, with a follow-up finalize step after
submitNeedsInput. - Threads attribution and request metadata through the needs-input action so deferred subscription creation still has checkout context.
- Refactors shared attribution extraction and updates tests/error handling around the new flow.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
libs/payments/ui/src/lib/utils/getAttributionFromSearchParams.ts |
Adds a shared helper to normalize attribution fields from Next.js search params. |
libs/payments/ui/src/lib/nestapp/validators/SubmitNeedsInputActionArgs.ts |
Expands action validation to accept attribution and request metadata. |
libs/payments/ui/src/lib/nestapp/nextjs-actions.service.ts |
Forwards the new submit-needs-input payload to cart service. |
libs/payments/ui/src/lib/client/components/PaymentInputHandler/index.tsx |
Keeps the needs-input client flow calling the redirect action after Stripe next-action handling. |
libs/payments/ui/src/lib/client/components/CheckoutForm/index.tsx |
Reuses the shared attribution helper in checkout form submission paths. |
libs/payments/ui/src/lib/actions/submitNeedsInputAndRedirect.ts |
Sends attribution/request context when completing needs-input and redirecting. |
libs/payments/ui/src/index.ts |
Re-exports the new attribution helper. |
libs/payments/cart/src/lib/checkout.service.ts |
Introduces deferred subscription creation for zero-initial Stripe checkouts and helper methods around SetupIntent finalization. |
libs/payments/cart/src/lib/checkout.service.spec.ts |
Adds tests for zero-initial Stripe flows and deferred setup-intent finalization. |
libs/payments/cart/src/lib/checkout.error.ts |
Adds a new checkout error for missing SetupIntent responses. |
libs/payments/cart/src/lib/cart.service.ts |
Updates needs-input handling to finalize subscription creation after a successful SetupIntent when no subscription exists yet. |
libs/payments/cart/src/lib/cart.service.spec.ts |
Adds coverage for setup-intent cleanup and the new submit-needs-input branch. |
libs/payments/cart/src/lib/cart.error.ts |
Removes the obsolete “missing subscription id” cart error for submit-needs-input. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+834
to
+836
| await this.cartManager.updateProcessingCart(cart.id, version, { | ||
| stripeSubscriptionId: subscription.id, | ||
| }); |
Comment on lines
+2206
to
+2217
| it('retrieves setup intent and creates subscription', async () => { | ||
| await checkoutService.finalizeSetupIntentAndCreateSubscription( | ||
| mockCart, | ||
| mockAttributionData, | ||
| mockRequestArgs | ||
| ); | ||
|
|
||
| expect(setupIntentManager.retrieve).toHaveBeenCalledWith( | ||
| mockCart.stripeIntentId | ||
| ); | ||
| expect(subscriptionManager.create).toHaveBeenCalled(); | ||
| expect(checkoutService.postPaySteps).toHaveBeenCalled(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Because:
This commit:
Closes #PAY-3675
Checklist
Put an
xin the boxes that apply