#kenny_code
1 messages ยท Page 1 of 1 (latest)
๐ Welcome to your new thread!
โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.
โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.
๐ This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1344781092573679727
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
// Prepare session options with proper typing
const sessionOptions: Stripe.Checkout.SessionCreateParams = {
ui_mode: "custom",
line_items: lineItems.map((item) => ({
price: item.price,
quantity: item.quantity, // Already validated as a number by Zod
})),
mode: "payment",
return_url:
`${domain}/${teamSlug}/payments/return?session_id={CHECKOUT_SESSION_ID}`,
automatic_tax: { enabled: false },
invoice_creation: { enabled: true },
payment_intent_data: {
setup_future_usage: "off_session",
},
};
// If we have an existing customer, use customer ID
// Otherwise use customer_email for new customers
if (billingStatus?.billing_customer_id) {
sessionOptions.customer = billingStatus.billing_customer_id;
} else {
sessionOptions.customer_email = user.email;
}
const session = await stripeClient.checkout.sessions.create(sessionOptions);
"use client";
import { stripePromise } from "@/lib/stripe/client";
import { CheckoutProvider } from "@stripe/react-stripe-js";
import CheckoutForm from "./checkout-form";
export default function Checkout(props: {
clientSecret: string;
creditQuantity: number;
amountTotal: number;
}) {
return (
<CheckoutProvider
stripe={stripePromise}
options={{
clientSecret: props.clientSecret,
elementsOptions: {
fonts: [{ cssSrc: "https://fonts.googleapis.com/css?family=Inter" }],
appearance: {
theme: "night",
variables: {
fontFamily: "Inter",
colorPrimary: "#EA580C",
colorBackground: "#09090B",
colorText: "white",
},
},
},
}}
>
<CheckoutForm
creditQuantity={props.creditQuantity}
amountTotal={props.amountTotal}
/>
</CheckoutProvider>
);
}
Hello, we do have functionality for this, finding the doc
Here we go, this parameter lets you define behavior around redisplaying saved payment methods in Checkout https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-saved_payment_method_options
Complete reference documentation for the Stripe API. Includes code snippets and examples for our Python, Java, PHP, Node.js, Go, Ruby, and .NET libraries.
If you retrieve the PaymentIntent in the API, what does it say for its allow_redisplay parameter
Also your example code would need to set saved_payment_method_options.allow_redisplay_filters which your example code does not have currently
const sessionOptions: Stripe.Checkout.SessionCreateParams = {
ui_mode: "custom",
line_items: lineItems.map((item) => ({
price: item.price,
quantity: item.quantity,
})),
mode: "payment",
return_url:
`${domain}/${teamSlug}/payments/return?session_id={CHECKOUT_SESSION_ID}`,
automatic_tax: { enabled: false },
invoice_creation: { enabled: true },
payment_intent_data: {
setup_future_usage: "off_session",
},
saved_payment_method_options: {
allow_redisplay_filters: ['always', 'limited', 'unspecified']
}
};
& the customer id is in fact passed in, just at a later step
// If we have an existing customer, use customer ID
// Otherwise use customer_email for new customers
if (billingStatus?.billing_customer_id) {
sessionOptions.customer = billingStatus.billing_customer_id;
} else {
sessionOptions.customer_email = user.email;
}
i have confirmed that the correct customer id is being passed in
Can you send the ID of the customer, payment method, and a checkout session that doesn't show the saved PM here? I am not immediately spotting anything in your code that would cause this
Also does this still happen if you turn on payment_method_save in saved_payment_method_options and run through another session to save a PM?
Hello! I'm taking over and catching up...
customer id: cus_RqsB4iPssFXjHm
payment method: pm_1QxARXB20I6m6e8n2pz2byqN
Thanks! Looking...
checkout session id: cs_test_a1nir3IPMb9xLVva4RdhKMInLfAaDNqdJr77gPCWQl4Y7ZAGcCSj7C308t
Thanks
Ah, you're using the Custom Checkout public preview. I'm not sure this is supported with that approach. Let me see if I can find confirmation for that...
Oh, okay, looks like it is supported, but it seems to only allow Payment Methods with allow_redisplay set to always, which isn't the case with the Payment Method you provided: https://docs.stripe.com/payments/checkout/save-during-payment?payment-ui=embedded-components#render-saved-payment-methods
how do I set it to always?
Once you have the customer's consent you can update the Payment Method: https://docs.stripe.com/api/payment_methods/update#update_payment_method-allow_redisplay
Also note that you'll need to implement that other code at the link I shared above.
This isn't built-in to an existing UI component.
Yep!
You'll also probably want to do something like, when that saved payment method is selected, hide the Payment Element.
But the basics are working now, so you can do whatever works best for your payment form from here.
Super, thanks for your help
No problem! All credit to @sage rover, actually, who found that docs link behind the scenes when we were talking about this. ๐
Thanks @sage rover !
One last question before I lose you guys. I only want the user to have one payment method active at a time. How do you suggest that I handle this upsert operation so that a customer never has more than one payment method?
Or is there a way to set the used payment method to have a "default" tag that I can access from the backend so I don't actually have to remove any payment methods.
I think the latter would be even better
You can do either.
For the former, you can detach the previous Payment Method when adding a new one. Detached Payment Methods can never be used again.
For the latter, you can add metadata to either the Customer or Payment Method (or both) to determine a default (or anything else you want).
There's also a third option: Customers have an invoice_settings.default_payment_method property where you can set the current default Payment Method for Invoices for that Customer. You can decide to use that as the default for your custom integration as well.