# Payments for existing customers Learn how to charge an existing payment method while a customer is on-session. # Custom flow The Payment Element allows buyers to enter their payment details. If the buyer is an existing customer or account, you can configure a Customer Session in the Payment Element display the customer’s or account’s [existing payment methods](https://docs.stripe.com/payments/save-and-reuse.md?platform=web&ui=elements). ![Payment Element with one saved card](https://b.stripecdn.com/docs-statics-srv/assets/saved_card.9ae121fe039c6d963f3c9831eb92172f.png) The Payment Element can only display the following saved payment method types: - `card` - `link` - `us_bank_account` - `acss_debit` - `sepa_debit` - `bacs_debit` - `au_becs_debit` - `nz_bank_account` - `ideal` - `sofort` - `bancontact` ## Create PaymentIntent and CustomerSession [Server-side] Create a [PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md) and a [CustomerSession](https://docs.stripe.com/api/customer_sessions/create.md). Make sure to pass the existing `Customer` or `Account` ID and enable the `payment_method_redisplay` feature. > #### Use the Accounts v2 API to represent customers > > The Accounts v2 API is generally available for Connect users, and in public preview for other Stripe users. If you’re part of the Accounts v2 preview, you need to specify a [specify a preview version](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning) in your code. > > To request access to the Accounts v2 preview, > > For most use cases, we recommend [modeling your customers as customer-configured Account objects](https://docs.stripe.com/accounts-v2/use-accounts-as-customers.md) instead of using [Customer](https://docs.stripe.com/api/customers.md) objects. #### Accounts v2 #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = Stripe::StripeClient.new('<>') post '/create-intent-and-customer-session' do intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', automatic_payment_methods: {enabled: true}, customer_account: {{CUSTOMER_ACCOUNT_ID}}, }) customer_session = client.v1.customer_sessions.create({ customer_account: {{CUSTOMER_ACCOUNT_ID}}, components: { payment_element: { enabled: true, features: { payment_method_redisplay: 'enabled', }, }, }, }) { client_secret: intent.client_secret, customer_session_client_secret: customer_session.client_secret }.to_json end ``` #### Customers v1 #### Ruby ```ruby # Don't put any keys in code. See https://docs.stripe.com/keys-best-practices. # Find your keys at https://dashboard.stripe.com/apikeys. client = Stripe::StripeClient.new('<>') post '/create-intent-and-customer-session' do intent = client.v1.payment_intents.create({ amount: 1099, currency: 'usd', # In the latest version of the API, specifying the `automatic_payment_methods` parameter # is optional because Stripe enables its functionality by default. automatic_payment_methods: {enabled: true}, customer: {{CUSTOMER_ID}}, }) customer_session = client.v1.customer_sessions.create({ customer: {{CUSTOMER_ID}}, components: { payment_element: { enabled: true, features: { payment_method_redisplay: 'enabled', }, }, }, }) { client_secret: intent.client_secret, customer_session_client_secret: customer_session.client_secret }.to_json end ``` ## Optional: Display additional saved payment methods [Server-side] > #### Compliance > > You’re responsible for your compliance with all applicable laws, regulations, and network rules when saving a customer’s payment details. When rendering past payment methods to a customer for future purchases, make sure you’ve collected consent to save the payment method details for this specific future use. By default, we only show payment methods set to [always allow redisplay](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay). You can’t reuse Apple Pay and Google Pay during a Checkout Session, so these payment methods don’t appear in the list of saved options. You must display the Google Pay and Apple Pay UI, and the payment request button UI, each time the Checkout Session is active. You can display other previously saved payment methods by including other redisplay values in the Checkout Session, or by updating a payment method’s `allow_redisplay` setting to `always`. - Use the `payment_method_allow_redisplay_filters` [parameter](https://docs.stripe.com/api/customer_sessions/create.md#create_customer_session-components-payment_element-features-payment_method_allow_redisplay_filters) to specify which saved payment methods to show in the Payment Element. You can set any of the valid values: `limited`, `unspecified` and `always`. #### Accounts v2 ```curl curl https://api.stripe.com/v1/customer_sessions \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "components[payment_element][enabled]=true" \ -d "components[payment_element][features][payment_method_redisplay]=enabled" \ -d "components[payment_element][features][payment_method_allow_redisplay_filters][]=always" \ -d "components[payment_element][features][payment_method_allow_redisplay_filters][]=limited" \ -d "components[payment_element][features][payment_method_allow_redisplay_filters][]=unspecified" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/customer_sessions \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d "components[payment_element][enabled]=true" \ -d "components[payment_element][features][payment_method_redisplay]=enabled" \ -d "components[payment_element][features][payment_method_allow_redisplay_filters][]=always" \ -d "components[payment_element][features][payment_method_allow_redisplay_filters][]=limited" \ -d "components[payment_element][features][payment_method_allow_redisplay_filters][]=unspecified" ``` - [Update the Payment Method](https://docs.stripe.com/api/payment_methods/update.md) to set the `allow_redisplay` value on individual payment methods. ```curl curl https://api.stripe.com/v1/payment_methods/{{PAYMENTMETHOD_ID}} \ -u "<>:" \ -d allow_redisplay=always ``` ## Display the Payment Element [Client-side] #### HTML + JS ### Set up Stripe.js Include the Stripe.js script on your checkout page by adding it to the `head` of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself. ```html Checkout ``` Create an instance of Stripe with the following JavaScript on your checkout page: ```javascript // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/apikeys const stripe = Stripe('<>'); ``` ### Add the Payment Element to your payment page The Payment Element needs a place to live on your payment page. Create an empty DOM node (container) with a unique ID in your payment form: ```html
``` Fetch the two `clients_secret` from the previous step to initialize the Element. Then create and mount the Payment Element. ```javascript // Fetch the two `client_secret` const response = await fetch('/create-intent-and-customer-session', { method: "POST" }); const { client_secret, customer_session_client_secret } = await response.json(); // Initialize Elements const elements = stripe.elements({ clientSecret: client_secret, customerSessionClientSecret: customer_session_client_secret, }); // Create and mount the Payment Element const paymentElementOptions = { layout: 'accordion'}; const paymentElement = elements.create('payment', paymentElementOptions); paymentElement.mount('#payment-element'); ``` #### React ### Set up Stripe.js Install [React Stripe.js](https://www.npmjs.com/package/@stripe/react-stripe-js) and the [Stripe.js loader](https://www.npmjs.com/package/@stripe/stripe-js) from the npm public registry: ```bash npm install --save @stripe/react-stripe-js @stripe/stripe-js ``` ### Add and configure the Elements provider to your payment page Fetch the two `clients_secret` from the previous step to initialize the [Elements provider](https://docs.stripe.com/sdks/stripejs-react.md#elements-provider). Then render the CheckoutForm component that contains the payment form. ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import {Elements} from '@stripe/react-stripe-js'; import {loadStripe} from '@stripe/stripe-js'; import CheckoutForm from './CheckoutForm'; // Make sure to call `loadStripe` outside of a component's render to avoid // recreating the `Stripe` object on every render. const stripePromise = loadStripe('<>'); function App() { const [clientSecret, setClientSecret] = useState(""); const [customerSessionClientSecret, setCustomerSessionClientSecret] = useState(""); // Fetch the two `client_secret` useEffect(() => { fetch("/create-intent-and-customer-session", { method: "POST" }) .then((res) => res.json()) .then((data) => { setClientSecret(data.client_secret); setCustomerSessionClientSecret(data.customer_session_client_secret); }); }, []); // Initialize the Element provider once we we received the two `client_secret` // And render the CheckoutForm return (
{clientSecret && customerSessionClientSecret && ( )}
); }; ReactDOM.render(, document.getElementById('root')); ``` ### Add the Payment Element component Use the `PaymentElement` component to display the payment form. ```jsx import React from 'react'; import {PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { return (
); }; export default CheckoutForm; ``` ## Submit the payment to Stripe [Client-side] Use [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) to complete the payment using details from the Payment Element. Provide a [return_url](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-return_url) to this function to indicate where Stripe should redirect the user after they complete the payment. Your user may be first redirected to an intermediate site, like a bank authorization page, before being redirected to the `return_url`. Card payments immediately redirect to the `return_url` when a payment is successful. If you don’t want to redirect for card payments after payment completion, you can set [redirect](https://docs.stripe.com/js/payment_intents/confirm_payment#confirm_payment_intent-options-redirect) to `if_required`. This only redirects customers that check out with redirect-based payment methods. #### HTML + JS ```javascript const form = document.getElementById('payment-form'); form.addEventListener('submit', async (event) => { event.preventDefault(); const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) const messageContainer = document.querySelector('#error-message'); messageContainer.textContent = error.message; } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }); ``` #### React To call [stripe.confirmPayment](https://docs.stripe.com/js/payment_intents/confirm_payment) from your payment form component, use the [useStripe](https://docs.stripe.com/sdks/stripejs-react.md#usestripe-hook) and [useElements](https://docs.stripe.com/sdks/stripejs-react.md#useelements-hook) hooks. If you prefer traditional class components over hooks, you can instead use an [ElementsConsumer](https://docs.stripe.com/sdks/stripejs-react.md#elements-consumer). ```jsx import React, {useState} from 'react'; import {useStripe, useElements, PaymentElement} from '@stripe/react-stripe-js'; const CheckoutForm = () => { const stripe = useStripe(); const elements = useElements(); const [errorMessage, setErrorMessage] = useState(null); const handleSubmit = async (event) => { // We don't want to let default form submission happen here, // which would refresh the page. event.preventDefault(); if (!stripe || !elements) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } const {error} = await stripe.confirmPayment({ //`Elements` instance that was used to create the Payment Element elements, confirmParams: { return_url: 'https://example.com/order/123/complete', }, }); if (error) { // This point will only be reached if there is an immediate error when // confirming the payment. Show error to your customer (for example, payment // details incomplete) setErrorMessage(error.message); } else { // Your customer will be redirected to your `return_url`. For some payment // methods like iDEAL, your customer will be redirected to an intermediate // site first to authorize the payment, then redirected to the `return_url`. } }; return (
{/* Show error message to your customers */} {errorMessage &&
{errorMessage}
} ); }; export default CheckoutForm; ``` Make sure the `return_url` corresponds to a page on your website that provides the status of the payment. When Stripe redirects the customer to the `return_url`, we provide the following URL query parameters: | Parameter | Description | | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | | `payment_intent` | The unique identifier for the `PaymentIntent`. | | `payment_intent_client_secret` | The [client secret](https://docs.stripe.com/api/payment_intents/object.md#payment_intent_object-client_secret) of the `PaymentIntent` object. | > If you have tooling that tracks the customer’s browser session, you might need to add the `stripe.com` domain to the referrer exclude list. Redirects cause some tools to create new sessions, which prevents you from tracking the complete session. Use one of the query parameters to retrieve the PaymentIntent. Inspect the [status of the PaymentIntent](https://docs.stripe.com/payments/paymentintents/lifecycle.md) to decide what to show your customers. You can also append your own query parameters when providing the `return_url`, which persist through the redirect process. #### HTML + JS ```javascript // Initialize Stripe.js using your publishable key const stripe = Stripe('<>'); // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe.retrievePaymentIntent(clientSecret).then(({paymentIntent}) => { const message = document.querySelector('#message') // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': message.innerText = 'Success! Payment received.'; break; case 'processing': message.innerText = "Payment processing. We'll update you when payment is received."; break; case 'requires_payment_method': message.innerText = 'Payment failed. Please try another payment method.'; // Redirect your user back to your payment page to attempt collecting // payment again break; default: message.innerText = 'Something went wrong.'; break; } }); ``` #### React ```jsx import React, {useState, useEffect} from 'react'; import {useStripe} from '@stripe/react-stripe-js'; const PaymentStatus = () => { const stripe = useStripe(); const [message, setMessage] = useState(null); useEffect(() => { if (!stripe) { return; } // Retrieve the "payment_intent_client_secret" query parameter appended to // your return_url by Stripe.js const clientSecret = new URLSearchParams(window.location.search).get( 'payment_intent_client_secret' ); // Retrieve the PaymentIntent stripe .retrievePaymentIntent(clientSecret) .then(({paymentIntent}) => { // Inspect the PaymentIntent `status` to indicate the status of the payment // to your customer. // // Some payment methods will [immediately succeed or fail][0] upon // confirmation, while others will first enter a `processing` state. // // [0]: https://stripe.com/docs/payments/payment-methods#payment-notification switch (paymentIntent.status) { case 'succeeded': setMessage('Success! Payment received.'); break; case 'processing': setMessage("Payment processing. We'll update you when payment is received."); break; case 'requires_payment_method': // Redirect your user back to your payment page to attempt collecting // payment again setMessage('Payment failed. Please try another payment method.'); break; default: setMessage('Something went wrong.'); break; } }); }, [stripe]); return message; }; export default PaymentStatus; ``` ## Handle post-payment events [Server-side] Stripe sends a [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md#event_types-payment_intent.succeeded) event when the payment completes. Use the [Dashboard webhook tool](https://dashboard.stripe.com/webhooks) or follow the [webhook guide](https://docs.stripe.com/webhooks/quickstart.md) to receive these events and run actions, such as sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow. Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events is what enables you to accept [different types of payment methods](https://stripe.com/payments/payment-methods-guide) with a single integration. In addition to handling the `payment_intent.succeeded` event, we recommend handling these other events when collecting payments with the Payment Element: | Event | Description | Action | | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [payment_intent.succeeded](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.succeeded) | Sent when a customer successfully completes a payment. | Send the customer an order confirmation and *fulfill* (Fulfillment is the process of providing the goods or services purchased by a customer, typically after payment is collected) their order. | | [payment_intent.processing](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.processing) | Sent when a customer successfully initiates a payment, but the payment has yet to complete. This event is most commonly sent when the customer initiates a bank debit. It’s followed by either a `payment_intent.succeeded` or `payment_intent.payment_failed` event in the future. | Send the customer an order confirmation that indicates their payment is pending. For digital goods, you might want to fulfill the order before waiting for payment to complete. | | [payment_intent.payment_failed](https://docs.stripe.com/api/events/types.md?lang=php#event_types-payment_intent.payment_failed) | Sent when a customer attempts a payment, but the payment fails. | If a payment transitions from `processing` to `payment_failed`, offer the customer another attempt to pay. |