# Save a customer's payment method without making a payment Learn how to save a payment method and charge it later. # Checkout Sessions API The [Checkout Sessions API in `setup` mode](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode) lets you save a customer’s payment details without an initial payment. This is helpful if you want to onboard customers now, set them up for payments, and charge them using the Payment Intents API in the future—when they’re offline. Use this integration to set up recurring payments or to create one-time payments with a final amount determined later, often after the customer receives your service. > #### Card-present transactions > > Card-present transactions, such as [collecting card details through Stripe Terminal](https://docs.stripe.com/terminal/features/saving-payment-details/save-directly.md), use a different process for saving the payment method. ## Compliance You’re responsible for your compliance with all applicable laws, regulations, and network rules when saving a customer’s payment details. These requirements generally apply if you want to save your customer’s payment method 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. Add terms to your website or app that state how you plan to save payment method details and allow customers to opt in. When you save a payment method, you can only use it for the specific usage you’ve included in your terms. To charge a payment method when a customer is offline and save it as an option for future purchases, make sure that you explicitly collect consent from the customer for this specific use. For example, include a “Save my payment method for future use” checkbox to collect consent. To charge a customer when they’re offline, make sure your terms include the following: - The customer’s agreement to your initiating 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. Make sure you keep a record of your customer’s written agreement to these terms. > If you need to use manual server-side confirmation or your integration requires presenting payment methods separately, see our [alternative guide](https://docs.stripe.com/payments/save-and-reuse-cards-only.md). ## Set up Stripe [Server-side] First, [create a Stripe account](https://dashboard.stripe.com/register) or [sign in](https://dashboard.stripe.com/login). Use our official libraries to access the Stripe API from your application: #### Ruby ```bash # Available as a gem sudo gem install stripe ``` ```ruby # If you use bundler, you can add this line to your Gemfile gem 'stripe' ``` ## Create a customer [Server-side] To set up a payment method for future payments, you must attach it to an object that represents your customer. When your customer creates an account or has their first transaction with your business, create either a customer-configured [Account](https://docs.stripe.com/api/v2/core/accounts/create.md) object with the Accounts v2 API or a [Customer](https://docs.stripe.com/api/customers/create.md) object with the Customers API. > #### 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 ```curl curl -X POST https://api.stripe.com/v2/core/accounts \ -H "Authorization: Bearer <>" \ -H "Stripe-Version: 2026-05-27.preview" ``` #### Customers v1 ```curl curl -X POST https://api.stripe.com/v1/customers \ -u "<>:" ``` ## Use setup mode [Server-side] Create a Checkout Session with [mode=setup](https://docs.stripe.com/api/checkout/sessions/create.md#create_checkout_session-mode). ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d mode=setup \ -d ui_mode=elements \ -d currency=usd ``` ## Attach the payment method to a customer [Server-side] If you didn’t create the Checkout Session with an existing customer, use the ID of the *PaymentMethod* (PaymentMethods represent your customer's payment instruments, used with the Payment Intents or Setup Intents APIs) to [attach](https://docs.stripe.com/api/payment_methods/attach.md) the payment method to a customer. Otherwise, the payment method automatically attaches to the customer you provided when creating the Checkout Session. #### Accounts v2 ```curl curl https://api.stripe.com/v1/payment_methods/{{PAYMENTMETHOD_ID}}/attach \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/payment_methods/{{PAYMENTMETHOD_ID}}/attach \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" ``` ## Retrieve the payment method [Server-side] After a customer successfully completes their Checkout Session, handle the [checkout.session.completed](https://docs.stripe.com/api/events/types.md#event_types-checkout.session.completed) webhook. Retrieve the Session object in the webhook, and then do the following: - Get the value of the [setup_intent](https://docs.stripe.com/api/checkout/sessions/object.md#checkout_session_object-setup_intent) key, which is the SetupIntent ID created during the Checkout Session. - Use the SetupIntent ID to [retrieve](https://docs.stripe.com/api/setup_intents/retrieve.md) the SetupIntent object. The returned object contains a [payment_method](https://docs.stripe.com/api/setup_intents/object.md#setup_intent_object-payment_method) ID that you can attach to a customer in the next step. Learn more about [setting up webhooks](https://docs.stripe.com/webhooks.md). ## Charge the payment method later [Server-side] After you attach the PaymentMethod to a customer, you can make an *off-session* (A payment is described as off-session if it occurs without the direct involvement of the customer, using previously-collected payment information) payment using a [PaymentIntent](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method): - Set either [customer_account](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer_account) to the `Account` ID or [customer](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-customer) to the `Customer` ID, and set [payment_method](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-payment_method) to the `PaymentMethod` ID. - Set [off_session](https://docs.stripe.com/api/payment_intents/confirm.md#confirm_payment_intent-off_session) to `true` to indicate that the customer isn’t in your checkout flow during a payment attempt and can’t fulfill an authentication request made by a partner, such as a card issuer, bank, or other payment institution. If, during your checkout flow, a partner requests authentication, Stripe requests exemptions using customer information from a previous *on-session* (A payment is described as on-session if it occurs while the customer is actively in your checkout flow and able to authenticate the payment method) transaction. If the conditions for exemption aren’t met, the PaymentIntent might result in an error. - Set the value of the PaymentIntent’s [confirm](https://docs.stripe.com/api/payment_intents/create.md#create_payment_intent-confirm) property to `true`, which causes confirmation to occur immediately when you create the PaymentIntent. #### Accounts v2 ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "payment_method={{PAYMENTMETHOD_ID}}" \ -d off_session=true \ -d confirm=true ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/payment_intents \ -u "<>:" \ -d amount=1099 \ -d currency=usd \ -d "customer={{CUSTOMER_ID}}" \ -d "payment_method={{PAYMENTMETHOD_ID}}" \ -d off_session=true \ -d confirm=true ``` If a payment attempt fails, the request also fails with a 402 HTTP status code, and the PaymentIntent status is *requires\_payment\_method* (This status appears as "requires_source" in API versions before 2019-02-11). Notify your customer to return to your application (for example, by sending an email or in-app notification) and direct your customer to a new Checkout Session to select another payment method. #### Accounts v2 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "customer_account={{CUSTOMERACCOUNT_ID}}" \ -d "line_items[0][price_data][currency]=usd" \ -d "line_items[0][price_data][product_data][name]=T-shirt" \ -d "line_items[0][price_data][unit_amount]=1099" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=elements \ --data-urlencode "return_url=https://example.com/return" ``` #### Customers v1 ```curl curl https://api.stripe.com/v1/checkout/sessions \ -u "<>:" \ -d "customer={{CUSTOMER_ID}}" \ -d "line_items[0][price_data][currency]=usd" \ -d "line_items[0][price_data][product_data][name]=T-shirt" \ -d "line_items[0][price_data][unit_amount]=1099" \ -d "line_items[0][quantity]=1" \ -d mode=payment \ -d ui_mode=elements \ --data-urlencode "return_url=https://example.com/return" ```