From e811db6fefcbac8f130f9e54f3cf3e502030c64a Mon Sep 17 00:00:00 2001 From: Sarthak2 Date: Sat, 19 Jul 2025 20:51:20 +0530 Subject: [PATCH 1/3] fix: stripe checkout session error --- .../add-product/handleCreateCheckout.ts | 74 +++++++++++++++---- .../customers/attach/handleSetupPayment.ts | 70 +++++++++++++++--- 2 files changed, 119 insertions(+), 25 deletions(-) diff --git a/server/src/internal/customers/add-product/handleCreateCheckout.ts b/server/src/internal/customers/add-product/handleCreateCheckout.ts index 2e14122b9..10caa513e 100644 --- a/server/src/internal/customers/add-product/handleCreateCheckout.ts +++ b/server/src/internal/customers/add-product/handleCreateCheckout.ts @@ -13,7 +13,6 @@ import { getNextStartOfMonthUnix } from "@/internal/products/prices/billingInter import { APIVersion } from "@autumn/shared"; import { SuccessCode } from "@autumn/shared"; import { notNullish } from "@/utils/genUtils.js"; -import { getEntityInvoiceDescription } from "@/internal/entities/entityUtils/entityInvoiceUtils.js"; import Stripe from "stripe"; export const handleCreateCheckout = async ({ @@ -67,7 +66,7 @@ export const handleCreateCheckout = async ({ if (attachParams.billingAnchor) { billingCycleAnchorUnixSeconds = Math.floor( - attachParams.billingAnchor / 1000, + attachParams.billingAnchor / 1000 ); } @@ -88,7 +87,10 @@ export const handleCreateCheckout = async ({ ? undefined : checkoutParams.allow_promotion_codes || true; - const checkout = await stripeCli.checkout.sessions.create({ + const hasUserSpecifiedPaymentMethods = + checkoutParams.payment_method_types !== undefined; + + const sessionParams = { customer: customer.processor.id, line_items: items, subscription_data: subscriptionData, @@ -100,20 +102,60 @@ export const handleCreateCheckout = async ({ ...(attachParams.metadata ? attachParams.metadata : {}), }, allow_promotion_codes: allowPromotionCodes, - invoice_creation: !isRecurring - ? { - enabled: true, - } - : undefined, - - saved_payment_method_options: { - payment_method_save: "enabled", - }, - + invoice_creation: !isRecurring ? { enabled: true } : undefined, + saved_payment_method_options: { payment_method_save: "enabled" }, ...(attachParams.checkoutSessionParams || {}), - }); + }; - logger.info(`✅ Successfully created checkout for customer ${customer.id}`); + let checkout; + + try { + checkout = await stripeCli.checkout.sessions.create(sessionParams); + logger.info(`✅ Successfully created checkout for customer ${customer.id}`); + } catch (error: any) { + if ( + error.message && + (error.message.includes("payment method") || + error.message.includes("No valid payment")) + ) { + logger.warn("Stripe checkout session creation failed", { + customerId: customer.id || customer.internal_id, + error: error.message, + }); + + if (hasUserSpecifiedPaymentMethods) { + throw error; + } + + try { + checkout = await stripeCli.checkout.sessions.create({ + ...sessionParams, + payment_method_types: ["card"], + }); + + logger.info( + `✅ Created checkout with card payment method for customer ${customer.id}` + ); + } catch (fallbackError: any) { + logger.error( + "Failed to create checkout session even with card payment method", + { + customerId: customer.id || customer.internal_id, + error: fallbackError.message, + } + ); + + throw new RecaseError({ + code: ErrCode.InvalidRequest, + message: + "Unable to create checkout session. Please ensure you have activated card payment method in your Stripe dashboard.", + statusCode: 400, + }); + } + } else { + throw error; + } + } if (returnCheckout) { return checkout; @@ -130,7 +172,7 @@ export const handleCreateCheckout = async ({ }, product(s) ${attachParams.products.map((p) => p.name).join(", ")}`, product_ids: attachParams.products.map((p) => p.id), customer_id: customer.id || customer.internal_id, - }), + }) ); } else { res.status(200).json({ diff --git a/server/src/internal/customers/attach/handleSetupPayment.ts b/server/src/internal/customers/attach/handleSetupPayment.ts index cd9380fb0..3d45bbcf7 100644 --- a/server/src/internal/customers/attach/handleSetupPayment.ts +++ b/server/src/internal/customers/attach/handleSetupPayment.ts @@ -1,8 +1,10 @@ import { routeHandler } from "@/utils/routerUtils.js"; import { getOrCreateCustomer } from "../cusUtils/getOrCreateCustomer.js"; -import { ExtendedRequest, ExtendedResponse } from "@/utils/models/Request.js"; +import { ExtendedRequest } from "@/utils/models/Request.js"; import { createStripeCusIfNotExists } from "@/external/stripe/stripeCusUtils.js"; import { createStripeCli } from "@/external/stripe/utils.js"; +import RecaseError from "@/utils/errorUtils.js"; +import { ErrCode } from "@/errors/errCodes.js"; export const handleSetupPayment = async (req: any, res: any) => routeHandler({ @@ -10,8 +12,8 @@ export const handleSetupPayment = async (req: any, res: any) => res, action: "setup_payment", handler: async (req: ExtendedRequest, res: any) => { - // 1. Get the customer const { db, env, org } = req; + const logger = req.logger; let { customer_id, customer_data, success_url, checkout_session_params } = req.body; @@ -27,21 +29,71 @@ export const handleSetupPayment = async (req: any, res: any) => org, env, customer, - logger: req.logger, + logger, }); const stripeCli = createStripeCli({ org, env }); - const session = await stripeCli.checkout.sessions.create({ + + const hasUserSpecifiedPaymentMethods = + checkout_session_params && checkout_session_params.payment_method_types; + + const sessionParams = { customer: customer.processor?.id, mode: "setup", success_url: success_url || org.stripe_config?.success_url, currency: org.default_currency || "usd", ...(checkout_session_params as any), - }); + }; - return res.json({ - customer_id: customer.id, - url: session.url, - }); + try { + const session = await stripeCli.checkout.sessions.create(sessionParams); + return res.json({ + customer_id: customer.id, + url: session.url, + }); + } catch (error: any) { + if (error.message && + (error.message.includes("payment method") || + error.message.includes("No valid payment"))) { + + logger.warn("Stripe checkout session creation failed", { + customerId: customer.id, + error: error.message, + }); + + if (hasUserSpecifiedPaymentMethods) { + throw error; + } + + try { + const fallbackSession = await stripeCli.checkout.sessions.create({ + ...sessionParams, + payment_method_types: ["card"], + }); + + logger.info("Created checkout session with card payment method", { + customerId: customer.id, + }); + + return res.json({ + customer_id: customer.id, + url: fallbackSession.url, + }); + } catch (fallbackError: any) { + logger.error("Failed to create checkout session even with card payment method", { + customerId: customer.id, + error: fallbackError.message, + }); + + throw new RecaseError({ + code: ErrCode.InvalidRequest, + message: "Unable to create checkout session. Please ensure you have activated card payment method in your Stripe dashboard.", + statusCode: 400, + }); + } + } + + throw error; + } }, }); From 89c3cdd437b8368e007167db26d784f5d962cdd5 Mon Sep 17 00:00:00 2001 From: Sarthak2 Date: Sat, 19 Jul 2025 21:08:10 +0530 Subject: [PATCH 2/3] chore: minor changes --- .../customers/add-product/handleCreateCheckout.ts | 10 +++++++--- .../internal/customers/attach/handleSetupPayment.ts | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/server/src/internal/customers/add-product/handleCreateCheckout.ts b/server/src/internal/customers/add-product/handleCreateCheckout.ts index 10caa513e..f2b50ee82 100644 --- a/server/src/internal/customers/add-product/handleCreateCheckout.ts +++ b/server/src/internal/customers/add-product/handleCreateCheckout.ts @@ -47,7 +47,6 @@ export const handleCreateCheckout = async ({ }); } - // Handle first item set const { items } = itemSets[0]; attachParams.itemSets = itemSets; @@ -66,7 +65,7 @@ export const handleCreateCheckout = async ({ if (attachParams.billingAnchor) { billingCycleAnchorUnixSeconds = Math.floor( - attachParams.billingAnchor / 1000 + attachParams.billingAnchor / 1000, ); } @@ -90,6 +89,7 @@ export const handleCreateCheckout = async ({ const hasUserSpecifiedPaymentMethods = checkoutParams.payment_method_types !== undefined; + // Prepare checkout session parameters const sessionParams = { customer: customer.processor.id, line_items: items, @@ -110,9 +110,11 @@ export const handleCreateCheckout = async ({ let checkout; try { + // let stripe automatically determine payment methods checkout = await stripeCli.checkout.sessions.create(sessionParams); logger.info(`✅ Successfully created checkout for customer ${customer.id}`); } catch (error: any) { + // payment method errors if ( error.message && (error.message.includes("payment method") || @@ -128,6 +130,7 @@ export const handleCreateCheckout = async ({ } try { + // card payment method fallback checkout = await stripeCli.checkout.sessions.create({ ...sessionParams, payment_method_types: ["card"], @@ -153,10 +156,11 @@ export const handleCreateCheckout = async ({ }); } } else { + // Re-throw errors throw error; } } - + if (returnCheckout) { return checkout; } diff --git a/server/src/internal/customers/attach/handleSetupPayment.ts b/server/src/internal/customers/attach/handleSetupPayment.ts index 3d45bbcf7..a66cc2c50 100644 --- a/server/src/internal/customers/attach/handleSetupPayment.ts +++ b/server/src/internal/customers/attach/handleSetupPayment.ts @@ -29,11 +29,12 @@ export const handleSetupPayment = async (req: any, res: any) => org, env, customer, - logger, + logger: req.logger, }); const stripeCli = createStripeCli({ org, env }); + // check if user already specified payment methods in their request const hasUserSpecifiedPaymentMethods = checkout_session_params && checkout_session_params.payment_method_types; @@ -46,12 +47,14 @@ export const handleSetupPayment = async (req: any, res: any) => }; try { + // let stripe automatically determine payment methods const session = await stripeCli.checkout.sessions.create(sessionParams); return res.json({ customer_id: customer.id, url: session.url, }); } catch (error: any) { + // payment method errors if (error.message && (error.message.includes("payment method") || error.message.includes("No valid payment"))) { @@ -66,6 +69,7 @@ export const handleSetupPayment = async (req: any, res: any) => } try { + // card payment method fallback const fallbackSession = await stripeCli.checkout.sessions.create({ ...sessionParams, payment_method_types: ["card"], @@ -80,6 +84,7 @@ export const handleSetupPayment = async (req: any, res: any) => url: fallbackSession.url, }); } catch (fallbackError: any) { + // if fallback failed logger.error("Failed to create checkout session even with card payment method", { customerId: customer.id, error: fallbackError.message, @@ -93,6 +98,7 @@ export const handleSetupPayment = async (req: any, res: any) => } } + // Re-throw errors throw error; } }, From 85d420eae4a6865f026c44ede5b7f93353d7ad3f Mon Sep 17 00:00:00 2001 From: John Yeo Date: Fri, 25 Jul 2025 15:30:44 +0100 Subject: [PATCH 3/3] editted code slightly for fallback checkout session --- .../add-product/handleCreateCheckout.ts | 65 ++++++------------- 1 file changed, 19 insertions(+), 46 deletions(-) diff --git a/server/src/internal/customers/add-product/handleCreateCheckout.ts b/server/src/internal/customers/add-product/handleCreateCheckout.ts index 5f1f384c6..6900aa9d5 100644 --- a/server/src/internal/customers/add-product/handleCreateCheckout.ts +++ b/server/src/internal/customers/add-product/handleCreateCheckout.ts @@ -95,10 +95,13 @@ export const handleCreateCheckout = async ({ }; } - const hasUserSpecifiedPaymentMethods = - checkoutParams.payment_method_types !== undefined; - // Prepare checkout session parameters + let checkout; + + let paymentMethodSet = + notNullish(checkoutParams.payment_method_types) || + notNullish(checkoutParams.payment_method_configuration); + const sessionParams = { customer: customer.processor.id, line_items: items, @@ -114,60 +117,30 @@ export const handleCreateCheckout = async ({ invoice_creation: !isRecurring ? { enabled: true } : undefined, saved_payment_method_options: { payment_method_save: "enabled" }, ...rewardData, - ...(attachParams.checkoutSessionParams || {}), }; - let checkout; - try { - // let stripe automatically determine payment methods checkout = await stripeCli.checkout.sessions.create(sessionParams); - logger.info(`✅ Successfully created checkout for customer ${customer.id}`); + logger.info( + `✅ Successfully created checkout for customer ${customer.id || customer.internal_id}` + ); } catch (error: any) { - // payment method errors + let msg = error.message; if ( - error.message && - (error.message.includes("payment method") || - error.message.includes("No valid payment")) + msg && + msg.includes("No valid payment method types") && + !paymentMethodSet ) { - logger.warn("Stripe checkout session creation failed", { - customerId: customer.id || customer.internal_id, - error: error.message, + checkout = await stripeCli.checkout.sessions.create({ + ...sessionParams, + payment_method_types: ["card"], }); - if (hasUserSpecifiedPaymentMethods) { - throw error; - } - - try { - // card payment method fallback - checkout = await stripeCli.checkout.sessions.create({ - ...sessionParams, - payment_method_types: ["card"], - }); - - logger.info( - `✅ Created checkout with card payment method for customer ${customer.id}` - ); - } catch (fallbackError: any) { - logger.error( - "Failed to create checkout session even with card payment method", - { - customerId: customer.id || customer.internal_id, - error: fallbackError.message, - } - ); - - throw new RecaseError({ - code: ErrCode.InvalidRequest, - message: - "Unable to create checkout session. Please ensure you have activated card payment method in your Stripe dashboard.", - statusCode: 400, - }); - } + logger.info( + `✅ Created fallback checkout session with card payment method for customer ${customer.id || customer.internal_id}` + ); } else { - // Re-throw errors throw error; } }