Skip to content

fix: stripe routes#1346

Merged
MODSetter merged 2 commits intomainfrom
fix/stripe-routes
May 5, 2026
Merged

fix: stripe routes#1346
MODSetter merged 2 commits intomainfrom
fix/stripe-routes

Conversation

@MODSetter
Copy link
Copy Markdown
Owner

@MODSetter MODSetter commented May 5, 2026

Description

Motivation and Context

FIX #

Screenshots

API Changes

  • This PR includes API changes

Change Type

  • Bug fix
  • New feature
  • Performance improvement
  • Refactoring
  • Documentation
  • Dependency/Build system
  • Breaking change
  • Other (specify):

Testing Performed

  • Tested locally
  • Manual/QA verification

Checklist

  • Follows project coding standards and conventions
  • Documentation updated as needed
  • Dependencies updated as needed
  • No lint/build errors or new warnings
  • All relevant tests are passing

High-level PR Summary

This PR fixes a race condition in the Stripe checkout flow where users would land on the purchase-success page before the checkout.session.completed webhook was delivered. The solution introduces a new /stripe/finalize-checkout endpoint that allows the frontend to synchronously fulfill purchases by retrieving the session from Stripe's API on page load. The backend now appends session_id={{CHECKOUT_SESSION_ID}} to success URLs so the frontend can call this endpoint immediately. The implementation includes idempotency guarantees, authorization checks (verifying client_reference_id matches the authenticated user), and proper handling of concurrent webhook and finalize-checkout calls. The frontend now polls the finalize endpoint until the purchase is completed or displays appropriate fallback messages for async payment methods. Additionally, the code standardizes purchase type metadata from premium_credit to premium_tokens while maintaining backward compatibility for in-flight sessions.

⏱️ Estimated Review Time: 30-90 minutes

💡 Review Order Suggestion
Order File Path
1 surfsense_backend/app/schemas/stripe.py
2 surfsense_web/contracts/types/stripe.types.ts
3 surfsense_backend/app/routes/stripe_routes.py
4 surfsense_web/lib/apis/stripe-api.service.ts
5 surfsense_web/app/dashboard/[search_space_id]/purchase-success/page.tsx

Need help? Join our Discord

Summary by CodeRabbit

Release Notes

  • New Features
    • Purchase success page now polls for real-time checkout completion status with improved error handling and feedback.
    • Displays updated balance information immediately after successful purchase.
    • Enhanced consistency in purchase type processing across checkout flows.

MODSetter added 2 commits May 5, 2026 01:01
…s handling

- Added a new endpoint `/stripe/finalize-checkout` to synchronously fulfill a checkout session, addressing the webhook-vs-redirect race condition.
- Updated the `PurchaseSuccessPage` component to handle various states of the checkout process, including loading, completed, pending, and failed states.
- Introduced a new response model `FinalizeCheckoutResponse` to provide immediate feedback on the purchase status.
- Enhanced the Stripe API service to include the new finalize checkout functionality.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

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

Project Deployment Actions Updated (UTC)
surf-sense-frontend Building Building Preview, Comment May 5, 2026 8:02am

Request Review

@MODSetter MODSetter merged commit 3c0f318 into main May 5, 2026
4 of 8 checks passed
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 5, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6c336793-c3d9-4151-bfec-75b417c5c956

📥 Commits

Reviewing files that changed from the base of the PR and between 3edefb9 and 0bd3281.

📒 Files selected for processing (5)
  • surfsense_backend/app/routes/stripe_routes.py
  • surfsense_backend/app/schemas/stripe.py
  • surfsense_web/app/dashboard/[search_space_id]/purchase-success/page.tsx
  • surfsense_web/contracts/types/stripe.types.ts
  • surfsense_web/lib/apis/stripe-api.service.ts

📝 Walkthrough

Walkthrough

This PR adds a new /stripe/finalize-checkout endpoint to synchronize checkout completion after Stripe redirects. The backend endpoint retrieves the session, verifies ownership, and fulfills purchases. The frontend purchase-success page polls this endpoint until completion, displaying dynamic status. Both backend and frontend types are updated to define the response contract.

Changes

Checkout Finalization Flow

Layer / File(s) Summary
Data Shape & Contracts
surfsense_backend/app/schemas/stripe.py, surfsense_web/contracts/types/stripe.types.ts
FinalizeCheckoutResponse schema defined with purchase_type, status, and optional page/token limit fields on both backend and frontend.
Backend Endpoint & Metadata Classification
surfsense_backend/app/routes/stripe_routes.py
New finalize_checkout GET endpoint retrieves Stripe session, verifies client_reference_id ownership, and fulfills purchase. Introduces _PURCHASE_TYPE_TOKEN_VALUES constant and _is_token_purchase(metadata) helper for canonical token-purchase classification. Webhook routing updated to use metadata classification instead of direct string matching. Success URLs for both page and token flows appended with ?session_id={CHECKOUT_SESSION_ID}. Token purchase metadata changed from "premium_credit" to "premium_tokens".
Frontend API Service
surfsense_web/lib/apis/stripe-api.service.ts
finalizeCheckout(sessionId) method added to StripeApiService, performing GET request to /api/v1/stripe/finalize-checkout?session_id=... and returning typed FinalizeCheckoutResponse.
Frontend Purchase Confirmation UI
surfsense_web/app/dashboard/[search_space_id]/purchase-success/page.tsx
Purchase-success page refactored from static confirmation to polling state machine. Reads session_id from URL, polls endpoint on interval up to max attempts, renders dynamic status/spinner/alerts based on state, and displays formatted balances on completion. Added formatNumber() and formatCredit() helpers.

Sequence Diagram

sequenceDiagram
    participant Client as Frontend Client
    participant API as Backend API
    participant Stripe as Stripe API
    participant DB as Database

    Client->>Client: Extract session_id from redirect URL
    Client->>Client: Initialize polling state machine
    loop Poll until success or max attempts
        Client->>API: GET /stripe/finalize-checkout?session_id={id}
        activate API
        API->>Stripe: Retrieve checkout session
        activate Stripe
        Stripe-->>API: Session + payment_status
        deactivate Stripe
        API->>API: Verify client_reference_id matches user.id
        alt Payment succeeded
            API->>DB: Fulfill purchase (pages or tokens)
            API->>DB: Refresh user state
        else Payment failed/incomplete
            API->>DB: Mark purchase as failed
            API->>DB: Refresh user state
        end
        API-->>Client: FinalizeCheckoutResponse (status, limits, usage)
        deactivate API
        Client->>Client: Update polling state (completed/failed/pending)
    end
    Client->>Client: Render completion UI with balance/error
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly Related PRs

  • MODSetter/SurfSense#1345: Both PRs modify stripe_routes.py webhook handling and purchase-type metadata extraction; this PR adds the new finalize endpoint and canonical metadata classification.

Poem

🐰 A checkout that dances with Stripe's redirect,
No more guessing if payment is set,
Poll till it lands, then show the good news,
Credits and pages—a shopper can't lose!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/stripe-routes

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.

❤️ Share

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant