From ce648a51a3c5fa97f309910375be0ab22149c166 Mon Sep 17 00:00:00 2001 From: rrader2890 Date: Tue, 16 Jun 2026 20:44:22 -0400 Subject: [PATCH] fix(white-label): own no-login success page after Stripe (not the in-app billing page) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The org's Stripe provider success_redirect_url points at app.thinkfleet.ai/ platform/setup/billing/success — an in-app, login-required page. A no-login white-label signer landed there after paying. Now the gate builds its own setup-mode Stripe Checkout Session with success_url = /white-label/done (a public "you're all set" page); the existing setup_intent.succeeded webhook still attaches the card and activates the subscription. Provider-level setting is left untouched so the normal in-app billing flow is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/controllers/white_label_controller.rb | 45 ++++++++++++++++++++--- config/routes.rb | 1 + 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/app/controllers/white_label_controller.rb b/app/controllers/white_label_controller.rb index 142e37dbbe94..0921a269d39e 100644 --- a/app/controllers/white_label_controller.rb +++ b/app/controllers/white_label_controller.rb @@ -54,6 +54,14 @@ def accept proceed_to_payment(agreement) end + # No-login landing page after the Stripe payment-method setup completes. + def done + body = "

You’re all set

" \ + '

Thank you — your agreement is signed and your payment method is on file. ' \ + "Your subscription is now active. You can close this window.

" + render html: layout(body).html_safe + end + private def render_gate(agreement, error: nil) @@ -99,12 +107,37 @@ def render_status(agreement) def proceed_to_payment(agreement) ensure_provider_customer(agreement.customer) - checkout = ::Customers::GenerateCheckoutUrlService.call(customer: agreement.customer) - if checkout.success? && checkout.checkout_url.present? - redirect_to checkout.checkout_url, allow_other_host: true - else - redirect_to_portal(agreement.customer) - end + url = white_label_checkout_url(agreement) + return redirect_to(url, allow_other_host: true) if url.present? + + redirect_to_portal(agreement.customer) + end + + # Build a Stripe setup-mode Checkout Session with OUR own no-login success page + # (the org's provider-level success_redirect_url points at an in-app, login- + # required page — wrong for a no-login signer). The existing + # setup_intent.succeeded webhook still attaches the card and activates the sub. + def white_label_checkout_url(agreement) + customer = agreement.customer + provider = payment_provider(customer) + pc = payment_provider_customer(customer) + return if provider.nil? || pc&.provider_customer_id.blank? + + base = WhiteLabelAgreement.gate_base_url + session = ::Stripe::Checkout::Session.create( + { + mode: "setup", + customer: pc.provider_customer_id, + payment_method_types: ["card"], + success_url: "#{base}/white-label/done", + cancel_url: agreement.signing_url + }, + {api_key: provider.secret_key} + ) + session.url + rescue => e + Rails.logger.error("[white-label] checkout session failed: #{e.message}") + nil end # Lago records *which* provider to use at customer-create but may not create diff --git a/config/routes.rb b/config/routes.rb index 41e694094d53..d7f635bda05e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,6 +17,7 @@ get "/ready", to: "application#ready" # Public, login-less white-label / SDK MSA acceptance gate (token-authenticated) + get "/white-label/done", to: "white_label#done" get "/white-label/:token", to: "white_label#show", as: :white_label_gate post "/white-label/:token/accept", to: "white_label#accept"