From f3a41bf01afc37b420763856d2c094002445637c Mon Sep 17 00:00:00 2001 From: John Mizerek Date: Mon, 2 Mar 2026 18:06:09 -0800 Subject: [PATCH] fix: validate Stripe customer before using, handle mode mismatch If a user has a live-mode StripeCustomerId but the API is running in test mode (or vice versa), the PI creation fails. Now validates the customer with Stripe first and creates a new one if invalid. Co-Authored-By: Claude Opus 4.6 --- api/stripe/createPaymentIntent.cfm | 19 +++++++++++++++++-- api/tabs/open.cfm | 17 +++++++++++++++-- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/api/stripe/createPaymentIntent.cfm b/api/stripe/createPaymentIntent.cfm index 34aa7d0..a7a7752 100644 --- a/api/stripe/createPaymentIntent.cfm +++ b/api/stripe/createPaymentIntent.cfm @@ -233,8 +233,23 @@ try { if (orderUserID > 0) { stripeCustomerId = qOrder.StripeCustomerId ?: ""; - // Create Stripe Customer if user doesn't have one - if (len(trim(stripeCustomerId)) == 0) { + // Validate existing customer (catches live/test mode mismatch) + needNewCustomer = (len(trim(stripeCustomerId)) == 0); + if (!needNewCustomer) { + validateService = new http(); + validateService.setMethod("GET"); + validateService.setUrl("https://api.stripe.com/v1/customers/#stripeCustomerId#"); + validateService.setUsername(stripeSecretKey); + validateService.setPassword(""); + validateResult = validateService.send().getPrefix(); + validateData = deserializeJSON(validateResult.fileContent); + if (structKeyExists(validateData, "error") || !structKeyExists(validateData, "id")) { + needNewCustomer = true; + } + } + + // Create Stripe Customer if needed + if (needNewCustomer) { customerService = new http(); customerService.setMethod("POST"); customerService.setUrl("https://api.stripe.com/v1/customers"); diff --git a/api/tabs/open.cfm b/api/tabs/open.cfm index 91b9a48..bc8107f 100644 --- a/api/tabs/open.cfm +++ b/api/tabs/open.cfm @@ -82,8 +82,21 @@ try { if (qUser.recordCount == 0) apiAbort({ "OK": false, "ERROR": "user_not_found" }); stripeCustomerId = qUser.StripeCustomerId; - if (!len(trim(stripeCustomerId))) { - // Create Stripe Customer + + // Validate existing customer with Stripe (catches live/test mode mismatch) + needNewCustomer = true; + if (len(trim(stripeCustomerId))) { + cfhttp(method="GET", url="https://api.stripe.com/v1/customers/#stripeCustomerId#", result="checkResp") { + cfhttpparam(type="header", name="Authorization", value="Bearer #application.stripeSecretKey#"); + } + checkData = deserializeJSON(checkResp.fileContent); + if (structKeyExists(checkData, "id") && !structKeyExists(checkData, "error")) { + needNewCustomer = false; + } + } + + if (needNewCustomer) { + // Create Stripe Customer (or replace invalid one) cfhttp(method="POST", url="https://api.stripe.com/v1/customers", result="custResp") { cfhttpparam(type="header", name="Authorization", value="Bearer #application.stripeSecretKey#"); cfhttpparam(type="formfield", name="name", value="#qUser.FirstName# #qUser.LastName#");