# Save a customer's payment method when they use it for a payment

Learn how to save your customer's payment details for future purchases when they make a payment.

# Checkout Sessions API


Use the [Checkout Sessions API](https://docs.stripe.com/api/checkout/sessions.md) to save payment details during a purchase. This is useful for situations such as:

- Charging a customer for an e-commerce order and storing the payment details for future purchases.
- Initiating the first payment in a series of recurring payments.
- Charging a deposit and storing the payment details to charge the full amount later.

## Compliance

You’re responsible for your compliance with all applicable laws, regulations, and network rules when saving a customer’s payment details for future use, such as displaying a customer’s payment method to them in the checkout flow for a future purchase or charging them when they’re not actively using your website or app. Before saving or charging a customer’s payment method, make sure you:

- Add terms to your website or app that state how you plan to save payment method details, such as:
  - The customer’s agreement allowing you to initiate a payment or a series of payments on their behalf for specified transactions.
  - The anticipated timing and frequency of payments (for example, if the charges are for scheduled installments, subscription payments, or unscheduled top-ups).
  - How you determine the payment amount.
  - Your cancellation policy, if the payment method is for a subscription service.
- Use a saved payment method for only the purpose stated in your terms.
- Collect explicit consent from the customer for this specific use. For example, include a "Save my payment method for future checkbox.
- Keep a record of your customer’s written agreement to your terms.

There are also some payment method restrictions to be aware of.

> When using Elements with the Checkout Sessions API, only cards and ACH Direct Debit are supported for saved payment methods. You can’t save other payment methods, such as bank accounts.

## Prerequisites

1. Follow the Checkout guide to [accept a payment](https://docs.stripe.com/payments/accept-a-payment.md?payment-ui=checkout&ui=stripe-hosted).
2. Follow this guide to save the payment method used during a payment so you can retrieve it for use in future payments by the same customer.

## Enable saved payment methods

> Global privacy laws are complicated and nuanced. Before implementing the ability to store customer payment method details, work with your legal team to make sure that it complies with your privacy and compliance framework.

To allow a customer to save their payment method for future use, specify the [saved_payment_method_options.payment_method_save](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-saved_payment_method_options-payment_method_save) parameter when creating the Checkout Session.

> #### 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 [preview version](https://docs.stripe.com/api-v2-overview.md#sdk-and-api-versioning) in your code.
> 
> To join the Accounts v2 preview, go to [Account previews and features](https://dashboard.stripe.com/settings/previews) in your Dashboard and enable **Reusable payment methods for Global Payouts**.
> 
> 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.

Saving a payment method requires an object that represents your customer. This object can be a customer-configured [Account](https://docs.stripe.com/api/v2/core/accounts/object.md) if you use the Accounts v2 API, or a [Customer](https://docs.stripe.com/api/customers/object.md) if you use the Customers API. Pass an existing customer or create a new one by setting [customer_creation](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-customer_creation) to `always` on the Checkout Session.

```curl
curl https://api.stripe.com/v1/checkout/sessions \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "line_items[0][price]={{PRICE_ID}}" \
  -d "line_items[0][quantity]=2" \
  -d mode=payment \
  -d ui_mode=elements \
  -d customer_creation=always \
  -d "saved_payment_method_options[payment_method_save]=enabled"
```

After you create the Checkout Session, use the [client secret](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-client_secret) returned in the response to [build your checkout page](https://docs.stripe.com/payments/quickstart.md).

> In the latest version of Stripe.js, specifying `enableSave` to `auto` is optional because that’s the default value when saved payment methods are enabled on the Checkout Session.

#### HTML + JS

The Payment Element automatically displays a consent collection checkbox when saved payment methods are enabled on the Checkout Session. You can explicitly configure this behavior using [elementsOptions](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions) on `initCheckoutElementsSdk`.

```javascript
const checkout = stripe.initCheckoutElementsSdk({
  clientSecret,
  elementsOptions: {
    savedPaymentMethod: {
      // Default is 'auto' in the latest version of Stripe.js - this configuration is optional
      enableSave: 'auto',
    }
  }
});
```

#### React

The Payment Element automatically displays a consent collection checkbox when saved payment methods are enabled on the Checkout Session. You can explicitly configure this behavior using [elementsOptions](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions) on the `CheckoutElementsProvider`.

```jsx
import React from 'react';
import {CheckoutElementsProvider} from '@stripe/react-stripe-js/checkout';
import CheckoutForm from './CheckoutForm';

const App = () => {
  const clientSecret = fetch('/create-checkout-session', {method: 'POST'})
    .then((response) => response.json())
    .then((json) => json.checkoutSessionClientSecret);

  return (
    <CheckoutElementsProvider
      stripe={stripe}
      options={{
        clientSecret,
        elementsOptions: {
          savedPaymentMethod: {
            // Default is 'auto' in the latest version of Stripe.js - this configuration is optional
            enableSave: 'auto',
          },
        },
      }}
    >
      <CheckoutForm />
    </CheckoutElementsProvider>
  );
};

export default App;
```

## Reuse a previously saved payment method

Each saved payment method is linked to an object that represents your customer. This object can be a customer-configured [Account](https://docs.stripe.com/api/v2/core/accounts/object.md) if you use the Accounts v2 API, or a [Customer](https://docs.stripe.com/api/customers/object.md) if you use the Customers API. Before creating the Checkout Session, authenticate your customer, and pass the corresponding object ID to the Checkout Session.

> In the latest version of Stripe.js, `enableRedisplay` defaults to `auto` when saved payment methods are enabled on the Checkout Session.

The Payment Element automatically redisplays previously saved payment methods for your customer to use during checkout when saved payment methods are enabled on the Checkout Session.

#### Accounts v2

```curl
curl https://api.stripe.com/v1/checkout/sessions \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "line_items[0][price]={{PRICE_ID}}" \
  -d "line_items[0][quantity]=2" \
  -d mode=payment \
  -d ui_mode=elements \
  -d "customer_account={{CUSTOMERACCOUNT_ID}}"
```

#### Customers v1

```curl
curl https://api.stripe.com/v1/checkout/sessions \
  -u "<<YOUR_SECRET_KEY>>:" \
  -d "line_items[0][price]={{PRICE_ID}}" \
  -d "line_items[0][quantity]=2" \
  -d mode=payment \
  -d ui_mode=elements \
  -d "customer={{CUSTOMER_ID}}"
```

#### HTML + JS

You can explicitly configure the redisplay behavior using [elementsOptions](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions) on `initCheckoutElementsSdk`.

```javascript
const checkout = stripe.initCheckoutElementsSdk({
  clientSecret,
  elementsOptions: {
    savedPaymentMethod: {
      // Default is 'auto' in the latest version of Stripe.js - this configuration is optional
      enableSave: 'auto',
      // Default is 'auto' in the latest version of Stripe.js - this configuration is optional
      enableRedisplay: 'auto',
    }
  }
});
```

#### React

You can explicitly configure the redisplay behavior using [elementsOptions](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions) on the `CheckoutElementsProvider`.

```jsx
import React from 'react';
import {CheckoutElementsProvider} from '@stripe/react-stripe-js/checkout';
import CheckoutForm from './CheckoutForm';

const App = () => {
  const clientSecret = fetch('/create-checkout-session', {method: 'POST'})
    .then((response) => response.json())
    .then((json) => json.checkoutSessionClientSecret)

  return (
    <CheckoutElementsProvider
      stripe={stripe}
      options={{
        clientSecret,
        elementsOptions: {
          savedPaymentMethod: {
            // Default is 'auto' in the latest version of Stripe.js - this configuration is optional
            enableSave: 'auto',
            // Default is 'auto' in the latest version of Stripe.js - this configuration is optional
            enableRedisplay: 'auto',
          }
        },
      }}
    >
      <CheckoutForm />
    </CheckoutElementsProvider>
  );
};

export default App;
```

## Optional: Build a saved payment method UI

#### HTML + JS

You can build your own saved payment method UI instead of using the built-in UI provided by the Payment Element.

To prevent the Payment Element from handling consent collection and displaying the previously saved payment methods, pass in additional [elementsOptions](https://docs.stripe.com/js/custom_checkout/init#custom_checkout_init-options-elementsOptions) on `initCheckoutElementsSdk`.

```javascript
const checkout = stripe.initCheckoutElementsSdk({
  clientSecret,
  elementsOptions: {
    savedPaymentMethod: {
      enableSave: 'never',
      enableRedisplay: 'never',
    },
  }
});
```

#### React

You can build your own saved payment method UI instead of using the built-in UI provided by the Payment Element. To prevent the Payment Element from handling consent collection and displaying the previously saved payment methods, pass in additional [elementsOptions](https://docs.stripe.com/js/react_stripe_js/checkout/checkout_provider#react_checkout_provider-options-elementsOptions) on the `CheckoutElementsProvider`.

```jsx
import React from 'react';
import {CheckoutElementsProvider} from '@stripe/react-stripe-js/checkout';
import CheckoutForm from './CheckoutForm';

const App = () => {
  const clientSecret = fetch('/create-checkout-session', {method: 'POST'})
    .then((response) => response.json())
    .then((json) => json.checkoutSessionClientSecret)

  return (
    <CheckoutElementsProvider
      stripe={stripe}
      options={{
        clientSecret,
        elementsOptions: {
          savedPaymentMethod: {
            enableSave: 'never',
            enableRedisplay: 'never',
          },
        },
      }}
    >
      <CheckoutForm />
    </CheckoutElementsProvider>
  );
};

export default App;
```

### Collect consent

> Global privacy laws are complicated and nuanced. Before implementing the ability to store customer payment method details, work with your legal team to make sure that it complies with your privacy and compliance framework.

In most cases, you must collect a customer’s consent before you save their payment method details. The following example shows how to obtain consent using a checkbox.

#### HTML + JS

```html
<label>
  <input type="checkbox" id="save-payment-method-checkbox" />
  Save my payment information for future purchases
</label>
<button id="pay-button">Pay</button>
<div id="confirm-errors"></div>
```

#### React

```jsx
import React from 'react';

type Props = {
  savePaymentMethod: boolean;
  onSavePaymentMethodChange: (save: boolean) => void;
}
const ConsentCollection = (props: Props) => {
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    props.onSavePaymentMethodChange(e.target.checked);
  };
  return (
    <label>
      <input
        type="checkbox"
        checked={props.savePaymentMethod}
        onChange={handleChange}
      />
      Save my payment information for future purchases
    </label>
  );
};

export default ConsentCollection;
```

When you call [confirm](https://docs.stripe.com/js/custom_checkout/confirm), you can indicate to Stripe that your customer has provided consent by passing the `savePaymentMethod` parameter. When you save a customer’s payment details, you’re responsible for complying with all applicable laws, regulations, and network rules.

#### HTML + JS

```js
const checkout = stripe.initCheckoutElementsSdk({clientSecret});
const button = document.getElementById('pay-button');
const errors = document.getElementById('confirm-errors');
const checkbox = document.getElementById('save-payment-method-checkbox');
const loadActionsResult = await checkout.loadActions();
if (loadActionsResult.type === 'success') {
  const {actions} = loadActionsResult;
  button.addEventListener('click', () => {
    // Clear any validation errors
    errors.textContent = '';

    const savePaymentMethod = checkbox.checked;
    actions.confirm({savePaymentMethod}).then((result) => {
      if (result.type === 'error') {
        errors.textContent = result.error.message;
      }
    });
  });
}
```

#### React

```jsx
import React from 'react';
import {useCheckoutElements} from '@stripe/react-stripe-js/checkout';

type Props = {
  savePaymentMethod: boolean;
}
const PayButton = (props: Props) => {
  const checkoutState = useCheckoutElements();
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState(null);

  if (checkoutState.type === 'loading') {
    return (
      <div>Loading...</div>
    );
  } else if (checkoutState.type === 'error') {
    return (
      <div>Error: {checkoutState.error.message}</div>
    );
  }
  const {confirm} = checkoutState.checkout;
  const handleClick = () => {
    setLoading(true);
    confirm({savePaymentMethod: props.savePaymentMethod}).then((result) => {
      if (result.type === 'error') {
        setError(result.error)
      }
      setLoading(false);
    })
  };

  return (
    <div>
      <button disabled={!loading} onClick={handleClick}>
        Pay
      </button>
      {error && <div>{error.message}</div>}
    </div>
  )
};

export default PayButton;
```

### Render saved payment methods

Use the [savedPaymentMethods](https://docs.stripe.com/js/custom_checkout/session_object#custom_checkout_session_object-savedPaymentMethods) array on the front end to render the customer’s available payment methods.

> The `savedPaymentMethods` array includes only the payment methods that have [allow_redisplay](https://docs.stripe.com/api/payment_methods/object.md#payment_method_object-allow_redisplay) set to `always`. Follow the steps for [collecting consent](https://docs.stripe.com/payments/save-during-payment.md#collect-consent) from your customer and make sure to properly set the `allow_redisplay` parameter.

#### HTML + JS

```html
<div id="saved-payment-methods"></div>
```

```js
const checkout = stripe.initCheckoutElementsSdk({clientSecret});
const loadActionsResult = await checkout.loadActions();
if (loadActionsResult.type === 'success') {
  const container = document.getElementById('saved-payment-methods');
  const {actions} = loadActionsResult;
  actions.getSession().savedPaymentMethods.forEach((pm) => {
    const label = document.createElement('label');
    const radio = document.createElement('input');

    radio.type = 'radio';
    radio.value = pm.id;

    label.appendChild(radio);
    label.appendChild(document.createTextNode(`Card ending in ${pm.card.last4}`));
    container.appendChild(label);
  });
}
```

#### React

```jsx
import React from 'react';
import {useCheckoutElements} from '@stripe/react-stripe-js/checkout';

type Props = {
  selectedPaymentMethod: string | null;
  onSelectPaymentMethod: (paymentMethod: string) => void;
};
const PaymentMethods = (props: Props) => {
  const checkoutState = useCheckoutElements();

  if (checkoutState.type === 'loading') {
    return (
      <div>Loading...</div>
    );
  } else if (checkoutState.type === 'error') {
    return (
      <div>Error: {checkoutState.error.message}</div>
    );
  }
  const {savedPaymentMethods} = checkoutState.checkout;

  const handleOptionChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    props.onSelectPaymentMethod(e.target.value);
  };

  return (
    <div>
      {savedPaymentMethods.map((pm) => (
        <label key={pm.id}>
          <input
            type="radio"
            value={pm.id}
            checked={props.selectedPaymentMethod === pm.id}
            onChange={handleOptionChange}
          />
          Card ending in {pm.card.last4}
        </label>
      ))}
    </div>
  );
};

export default PaymentMethods;
```

### Confirm with a saved payment method

When your customer selects a saved payment method and is ready to complete checkout, call [confirm](https://docs.stripe.com/js/custom_checkout/confirm) and pass in the [paymentMethod](https://docs.stripe.com/js/custom_checkout/confirm#custom_checkout_session_confirm-options-paymentMethod) ID.

#### HTML + JS

```html
<button id="pay-button">Pay</button>
```

```js
const checkout = stripe.initCheckoutElementsSdk({clientSecret});
const loadActionsResult = await checkout.loadActions();
if (loadActionsResult.type === 'success') {
  const button = document.getElementById('pay-button');
  const {actions} = loadActionsResult;
  button.addEventListener('click', () => {
    const selectedPaymentMethod = document.querySelector('input[type="radio"]:checked')?.value;
    actions.confirm({paymentMethod: selectedPaymentMethod}).then((result) => {
      if (result.error) {
        // Confirmation failed. Display the error message.
      }
    });
  });
}
```

#### React

```jsx
import React from 'react';
import {useCheckoutElements} from '@stripe/react-stripe-js/checkout';

type Props = {
  selectedPaymentMethod: string | null;
}
const PayButton = (props: Props) => {
  const checkoutState = useCheckoutElements();
  const [loading, setLoading] = React.useState(false);

  if (checkoutState.type === 'loading') {
    return (
      <div>Loading...</div>
    );
  } else if (checkoutState.type === 'error') {
    return (
      <div>Error: {checkoutState.error.message}</div>
    );
  }
  const {confirm} = checkoutState.checkout;

  const handleClick = () => {
    setLoading(true);
    confirm({paymentMethod: props.selectedPaymentMethod}).then((result) => {
      if (result.error) {
        // Confirmation failed. Display the error message.
      }
      setLoading(false);
    })
  };

  return (
    <button disabled={loading} onClick={handleClick}>
      Pay
    </button>
  )
};

export default PayButton;
```

