Repository navigation
fix(api): surface Stripe card errors as 402 - #3354
Conversation
Card errors (incorrect CVC, expired card, insufficient funds, plain declines) during a dev/chat plan tier change or Reset Pass purchase were falling through to a generic 500 "Failed to change dev plan tier" logged as a fatal error. Map any StripeCardError to a 402 carrying Stripe's own user-facing message so the billing UI toast tells the user what to fix, and log it at warn instead of error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
WalkthroughStripe card errors now return specific user-facing messages with HTTP 402 responses for chat-plan changes, DevPass tier changes, and Reset Pass purchases. A shared helper provides validation and fallback handling. Tests cover declined DevPass upgrades and state cleanup. ChangesStripe card error handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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.
Pull request overview
Improves billing-related UX in the API by correctly classifying Stripe card failures (e.g., incorrect CVC, declines) as user-actionable payment errors rather than server faults, so clients can display Stripe’s customer-facing message.
Changes:
- Added a shared helper to extract Stripe card-error messages (
StripeCardError) for safe client display. - Updated DevPass and Chat plan tier-change routes to return 402 with Stripe’s message (plus actionable guidance) and log at warn.
- Updated Reset Pass purchase flow to propagate the specific card-error message (still 402) instead of a generic decline message; added unit coverage for DevPass tier change.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| apps/api/src/lib/stripe-card-error.ts | New helper to detect StripeCardError and return a user-facing message. |
| apps/api/src/routes/dev-plans.ts | Maps Stripe card errors to 402 with actionable messaging in tier change + Reset Pass purchase. |
| apps/api/src/routes/dev-plans.spec.ts | Adds unit test ensuring tier-change card errors surface as 402 without mutating org state. |
| apps/api/src/routes/chat-plans.ts | Applies the same 402 + Stripe-message handling for chat plan tier changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Problem
A Stripe card error during a DevPass tier change (e.g.
incorrect_cvc, seen in production as a 500 onPOST /dev-plans/change-tier) fell through to the generic catch: the API returned 500 "Failed to change dev plan tier", logged it as a fatal error, and the billing UI showed only a generic failure toast — the user never learned their CVC was wrong.Fix
getStripeCardErrorMessage()helper (apps/api/src/lib/stripe-card-error.ts): detectsStripeCardError(any code — incorrect CVC, expired card, insufficient funds, plain decline) and returns Stripe's own user-facingmessage, which is designed to be shown to customers.POST /dev-plans/change-tierandPOST /chat-plans/change-tiernow map any card error to a 402 whose message is Stripe's explanation plus an actionable hint (e.g. "Your card's security code is incorrect. Update your payment method and try again."), logged at warn instead of error. The previous branch only caught thecard_declinedcode.The billing UI already renders the API error
messagein the toast description, so no frontend change was needed.Testing
StripeCardError(incorrect_cvc) → 402 with the exact message, org/tier/credits untouched, upgrade lease released, no transaction row. All 20dev-plans.spec.tstests pass.stripe listenwebhook forwarding against Stripe test mode:pm_card_chargeCustomerFail(attaches OK, fails at charge time — same code path as the productionincorrect_cvc): "Pay and upgrade" in the dashboard → API returned 402"Your card was declined. Update your payment method and try again.", toast showed that message, API logged a single WARN, plan/lease/credits unchanged.dev_plan_upgradetransaction recorded,invoice.payment_succeededwebhook delivered and processed).pnpm formatand fullpnpm buildpass.🤖 Generated with Claude Code
Summary by CodeRabbit