Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support
Overview
Overview
How cards work
Quickstart
Accept a payment
Share payment links
Faster checkout with Link
More payment scenarios
U.S. and Canadian cards
Save cards without authentication
Upgrade to handle authentication
Testing
No-code options
Payments
·
HomePaymentsOnline paymentsU.S. and Canadian cards

Save a card without bank authentication

Learn how to save card details and charge your customers later.

​​Stripe allows you to collect card details and charge your customer at a later time. ​​In some regions, banks require a second form of authentication such as entering a code sent to a phone. ​​The extra step decreases conversion if your customer isn’t actively using your website or application because they aren’t available to authenticate the purchase.

​​If you primarily do business in the U.S. and Canada, banks don’t require authentication, so you can follow this simpler integration. Building this integration means that expanding to other countries or adding other payment methods will require significant changes. Learn how to save cards that require authentication.

Collect card details
Client-side

Before starting this guide, you need a Stripe account. Register now.

Build a checkout page to collect your customer’s card details. Use Stripe Elements, a UI library that helps you build custom payment forms. To get started with Elements, include the Stripe.js library with the following script on your checkout page.

<script src="https://js.stripe.com/v3/"></script>

Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Do not include the script in a bundle or host a copy of it yourself.

To best leverage Stripe’s advanced fraud functionality, include this script on every page on your site, not just the checkout page. Including the script on every page allows Stripe to detect suspicious behavior that may indicate fraud when users browse your website.

Add Elements to your page

To securely collect card details from your customers, Elements creates UI components for you that are hosted by Stripe. They are then placed into your payment form, rather than you creating them directly. To determine where to insert these components, create empty DOM elements (containers) with unique IDs within your payment form.

index.html
<input id="cardholder-name" type="text"> <!-- placeholder for Elements --> <div id="card-element"></div> <div id="card-result"></div> <button id="card-button">Save Card</button>

Elements examples

See example payment forms created with Elements on GitHub.

Next, create an instance of the Stripe object, providing your publishable API key as the first parameter. After, create an instance of the Elements object and use it to mount a card element in the DOM.

The card Element simplifies the payment form and minimizes the number of required fields by inserting a single, flexible input field that securely collects all necessary card details.

Otherwise, combine cardNumber, cardExpiry, and cardCvc Elements for a flexible, multi-input card form.

Always collect a postal code to increase card acceptance rates and reduce fraud

The single input card Element automatically collects and sends the customer’s postal code to Stripe. If you build your payment form with multi-input card Elements (cardNumber, cardExpiry, cardCvc), add a separate input field for the customer’s postal code.

client.js
var stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); var elements = stripe.elements(); var cardElement = elements.create('card'); cardElement.mount('#card-element');

A Stripe Element contains an iframe that securely sends the payment information to Stripe over an HTTPS connection. The checkout page address must also start with https:// rather than http:// for your integration to work.

You can test your integration without using HTTPS. Enable it when you’re ready to accept live payments.

client.js
var cardholderName = document.getElementById('cardholder-name'); var cardButton = document.getElementById('card-button'); var resultContainer = document.getElementById('card-result'); cardButton.addEventListener('click', function(ev) { stripe.createPaymentMethod({ type: 'card', card: cardElement, billing_details: { name: cardholderName.value, }, } ).then(function(result) { if (result.error) { // Display error.message in your UI resultContainer.textContent = result.error.message; } else { // You have successfully created a new PaymentMethod resultContainer.textContent = "Created payment method: " + result.paymentMethod.id; } }); });

Send the resulting PaymentMethod ID to your server.

Set up Stripe
Server-side

Use our official libraries for access to the Stripe API from your application:

Terminal
# For detailed setup, see our quickstarts at https://stripe.com/docs/development/quickstart bundle add stripe bundle install

Save the card
Server-side

Save the card by attaching the PaymentMethod to a Customer. You can use the Customer object to store other information about your customer, such as shipping details and email address.

curl https://api.stripe.com/v1/customers \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d payment_method="{{PAYMENT_METHOD_ID}}"

If you have an existing Customer, you can attach the PaymentMethod to that object instead.

Terminal
curl https://api.stripe.com/v1/payment_methods \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "customer"="{{CUSTOMER_ID}}"

At this point, associate the Customer ID and the PaymentMethod ID with your own internal representation of a customer, if you have one.

Charge the saved card
Server-side

When you are ready, fetch the PaymentMethod and Customer IDs to charge. You can do this by either storing the IDs of both in your database, or by using the Customer ID to look up all the Customer’s available PaymentMethods.

curl -G https://api.stripe.com/v1/payment_methods \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d customer=
"{{CUSTOMER_ID}}"
\ -d type=card

Use the PaymentMethod ID and the Customer ID to create a new PaymentIntent. Set error_on_requires_action to true to decline payments that require any actions from your customer, such as two-factor authentication.

Terminal
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d amount=1099 \ -d currency=usd \ -d customer="{{CUSTOMER_ID}}" \ -d payment_method="{{PAYMENT_METHOD_ID}}" \ -d error_on_requires_action=true \ -d confirm=true

When a payment attempt fails, the request also fails with a 402 HTTP status code and Stripe throws an error. You need to notify your customer to return to your application (for example, by sending an email) to complete the payment. Check the code of the Error raised by the Stripe API library or check the last_payment_error.decline_code on the PaymentIntent to inspect why the card issuer declined the payment.

Handle any card errors

Notify your customer that the payment failed and direct them to the payment form you made in Step 1 where they can enter new card details. Send that new PaymentMethod ID to your server to attach to the Customer object and make the payment again.

Alternatively, you can create a PaymentIntent and save a card all in one API call if you have already created a Customer.

Terminal
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d amount=1099 \ -d currency=usd \ -d customer="{{CUSTOMER_ID}}" \ -d payment_method="{{PAYMENT_METHOD_ID}}" \ -d error_on_requires_action=true \ -d confirm=true \ -d setup_future_usage=on_session

Setting setup_future_usage to on_session indicates to Stripe that you wish to save the card for later, without triggering unnecessary authentication.

Test the integration

Stripe provides test cards you can use in test mode to simulate different cards’ behavior. Use these cards with any CVC, postal code, and expiry date in the future.

NumberDescription
Succeeds and immediately processes the payment.
Always fails with a decline code of insufficient_funds.
Requires authentication, which in this integration will decline with a code of authentication_required.

OptionalRecollect a CVC

Upgrade your integration to handle card authentication

This integration declines cards that require authentication during payment. If you start seeing many payments in the Dashboard listed as Failed, then it’s time to upgrade your integration. Stripe’s global integration handles these payments instead of automatically declining.

Was this page helpful?
Questions? Contact us.
View developer tutorials on YouTube.
Check out our product changelog.
Powered by Markdoc
You can unsubscribe at any time. Read our privacy policy.
On this page
Collect card details
Set up Stripe
Save the card
Charge the saved card
Handle any card errors
Test the integration
Recollect a CVC
Upgrade your integration to handle card authentication
Stripe Shell
Test mode
▗▄ ▄▟█ █▀▀ ▗▟████▙▖ ██████ ███▗▟█ ███ ███▗▟██▙▖ ▗▟█████▙▖ ███▖ ▀▀ ███ ███▀▀▀ ███ ███▀ ███ ███ ███ ▝▜████▙▖ ███ ███ ███ ███ ███ █████████ ▄▄ ▝███ ███ ▄ ███ ███ ███▄ ███ ███ ▄▄ ▝▜████▛▘ ▝▜███▛ ███ ███ ███▝▜██▛▘ ▝▜█████▛▘ ███ ▀▘
Welcome to the Stripe Shell! Stripe Shell is a browser-based shell with the Stripe CLI pre-installed. Login to Stripe docs and press Control + Backtick on your keyboard to start managing your Stripe resources in test mode. - View supported commands: - Find webhook events: - Listen for webhook events: - Call Stripe APIs: stripe [api resource] [operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$