Payments
U.S. and Canadian cards
Save cards without authentication

Save a card without bank authentication Payment Intents API

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

Stripe allows you to collect your customer’s card details and charge at a later time.

In some regions, like Europe and India, banks often require a second form of authentication to make a purchase, such as entering a code sent to their phone. This decreases conversion if your customer is not actively using your website or application because they are not available to authenticate the purchase.

If you primarily do business in the U.S. and Canada, banks do not require authentication and 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.

1 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.

<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>

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.

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

A Stripe Element contains an iframe that securely sends the payment information to Stripe over a 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.

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; } }); });
const cardholderName = document.getElementById('cardholder-name'); const cardButton = document.getElementById('card-button'); const resultContainer = document.getElementById('card-result'); cardButton.addEventListener('click', async (ev) => { const {paymentMethod, error} = await stripe.createPaymentMethod({ type: 'card', card: cardElement, billing_details: { name: cardholderName.value, }, } ); if (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.

2 Set up Stripe Server-side

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

# Available as a gem gem install stripe
# If you use bundler, you can add this line to your Gemfile gem 'stripe'
# Install through pip pip install --upgrade stripe
# Or find the Stripe package on http://pypi.python.org/pypi/stripe/
# Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=2.48.0,<3.0
# Install the PHP library via Composer composer require stripe/stripe-php
# Or download the source directly: https://github.com/stripe/stripe-php/releases
/* For Gradle, add the following dependency to your build.gradle and replace {VERSION} with the version number you want to use from - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:{VERSION}"
<!-- For Maven, add the following dependency to your POM and replace {VERSION} with the version number you want to use from - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest --> <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
# For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson
# Install via npm npm install --save stripe
# Make sure your project is using Go Modules god mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v71
// Then import the package import ( "github.com/stripe/stripe-go/v71" )
# Install via dotnet dotnet add package Stripe.net dotnet restore
# Or install via NuGet PM> Install-Package Stripe.net

3 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}}"
stripe customers create --payment-method={{PAYMENT_METHOD_ID}}
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # This creates a new Customer and attaches the PaymentMethod in one API call. customer = Stripe::Customer.create({ payment_method: '{{PAYMENT_METHOD_ID}}', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # This creates a new Customer and attaches the PaymentMethod in one API call. stripe.Customer.create( payment_method='{{PAYMENT_METHOD_ID}}', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // This creates a new Customer and attaches the PaymentMethod in one API call. \Stripe\Customer::create([ 'payment_method' => '{{PAYMENT_METHOD_ID}}', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // This creates a new Customer and attaches the PaymentMethod in one API call. CustomerCreateParams params = CustomerCreateParams.builder() .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .build(); Customer customer = Customer.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // This creates a new Customer and attaches the PaymentMethod in one API call. const customer = await stripe.customers.create({ payment_method: '{{PAYMENT_METHOD_ID}}', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // This creates a new Customer and attaches the PaymentMethod in one API call. params := &stripe.CustomerParams{ PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), } c, _ := customer.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new CustomerCreateOptions { PaymentMethod = "{{PAYMENT_METHOD_ID}}", }; var service = new CustomerService(); var customer = service.Create(options);

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

curl https://api.stripe.com/v1/payment_methods/{{PAYMENT_METHOD_ID}}/attach \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer="{{CUSTOMER_ID}}"
stripe payment_methods attach {{PAYMENT_METHOD_ID}} --customer={{CUSTOMER_ID}}
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' payment_method = Stripe::PaymentMethod.attach( '{{PAYMENT_METHOD_ID}}', { customer: '{{CUSTOMER_ID}}', } )
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' payment_method = stripe.PaymentMethod.attach( '{{PAYMENT_METHOD_ID}}', customer='{{CUSTOMER_ID}}' )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $payment_method = \Stripe\PaymentMethod::retrieve('{{PAYMENT_METHOD_ID}}'); $payment_method->attach(['customer' => '{{CUSTOMER_ID}}']);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentMethod paymentMethod = PaymentMethod.retrieve("{{PAYMENT_METHOD_ID}}"); PaymentMethodAttachParams params = PaymentMethodAttachParams.builder() .setCustomer("{{CUSTOMER_ID}}") .build(); paymentMethod.attach(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentMethod = await stripe.paymentMethods.attach( '{{PAYMENT_METHOD_ID}}', { customer: '{{CUSTOMER_ID}}', } );
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentMethodAttachParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), } pm, _ := paymentmethod.Attach("{{PAYMENT_METHOD_ID}}", params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentMethodAttachOptions { Customer = "{{CUSTOMER_ID}}", }; var service = new PaymentMethodService(); var paymentMethod = service.Attach("{{PAYMENT_METHOD_ID}}", options);

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

4 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 https://api.stripe.com/v1/payment_methods \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer="{{CUSTOMER_ID}}" \ -d type=card \ -G
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' Stripe::PaymentMethod.list({ customer: '{{CUSTOMER_ID}}', type: 'card', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' stripe.PaymentMethod.list( customer="{{CUSTOMER_ID}}", type="card", )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); \Stripe\PaymentMethod::all([ 'customer' => '{{CUSTOMER_ID}}', 'type' => 'card', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentMethodListParams params = PaymentMethodListParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setType(PaymentMethodListParams.Type.CARD) .build(); PaymentMethodCollection paymentMethods = PaymentMethod.list(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentMethods = await stripe.paymentMethods.list({ customer: '{{CUSTOMER_ID}}', type: 'card', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentMethodListParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Type: stripe.String(string(stripe.PaymentMethodTypeCard)), } i := paymentmethod.List(params) for i.Next() { pm := i.PaymentMethod() }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentMethodListOptions { Customer = "{{CUSTOMER_ID}}", Type = "card", }; var service = new PaymentMethodService(); var paymentMethods = service.List(options);

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.

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
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' begin intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, }) rescue Stripe::CardError => e # Error code will be authentication_required if authentication is needed puts "Error is: #{e.error.code}" payment_intent_id = e.error.payment_intent.id payment_intent = Stripe::PaymentIntent.retrieve(payment_intent_id) puts payment_intent.id end
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' try: stripe.PaymentIntent.create( amount=1099, currency='usd', customer='{{CUSTOMER_ID}}', payment_method='{{PAYMENT_METHOD_ID}}', error_on_requires_action=True, confirm=True, ) except stripe.error.CardError as e: err = e.error # Error code will be authentication_required if authentication is needed print("Code is: %s" % err.code) payment_intent_id = err.payment_intent['id'] payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); try { \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'error_on_requires_action' => true, 'confirm' => true, ]); } catch (\Stripe\Exception\CardException $e) { // Error code will be authentication_required if authentication is needed echo 'Error code is:' . $e->getError()->code; $payment_intent_id = $e->getError()->payment_intent->id; $payment_intent = \Stripe\PaymentIntent::retrieve($payment_intent_id); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setCurrency("usd") .setAmount(1099) .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setCustomer("{{CUSTOMER_ID}}") .setConfirm(true) .setErrorOnRequiresAction(true) .build(); try { PaymentIntent.create(params); } catch (CardException err) { // Error code will be authentication_required if authentication is needed System.out.println("Error code is : " + e.getCode()); String paymentIntentId = e.getStripeError().getPaymentIntent().getId(); PaymentIntent paymentIntent = PaymentIntent.retrieve(paymentIntentId); System.out.println(paymentIntent.getId()); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); try { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, }); } catch (err) { // Error code will be authentication_required if authentication is needed console.log('Error code is: ', err.code); const paymentIntentRetrieved = await stripe.paymentIntents.retrieve(err.raw.payment_intent.id); console.log('PI retrieved: ', paymentIntentRetrieved.id); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Confirm: stripe.Bool(true), ErrorOnRequiresAction: stripe.Bool(true), } _, err := paymentintent.New(params) if err != nil { if stripeErr, ok := err.(*stripe.Error); ok { // Error code will be authentication_required if authentication is needed fmt.Printf("Error code: %v", stripeErr.Code) paymentIntentID := stripeErr.PaymentIntent.ID paymentIntent, _ := paymentintent.Get(paymentIntentID, nil) fmt.Printf("PI: %v", paymentIntent.ID) } }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; try { var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethod = "{{PAYMENT_METHOD_ID}}", Confirm = true, ErrorOnRequiresAction = true, }; service.Create(options); } catch (StripeException e) { switch (e.StripeError.ErrorType) { case "card_error": // Error code will be authentication_required if authentication is needed Console.WriteLine("Error code: " + e.StripeError.Code); var paymentIntentId = e.StripeError.PaymentIntent.Id; var service = new PaymentIntentService(); var paymentIntent = service.Get(paymentIntentId); Console.WriteLine(paymentIntent.Id); break; default: break; } }

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 (e.g., 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.

5 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 already have a Customer created.

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
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Use the new PaymentMethod ID and existing Customer ID to create a new payment intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, setup_future_usage: 'on_session', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Use the new PaymentMethod ID and existing Customer ID to create a new payment stripe.PaymentIntent.create( amount=1099, currency='usd', customer='{{CUSTOMER_ID}}', payment_method='{{PAYMENT_METHOD_ID}}', error_on_requires_action=True, confirm=True, setup_future_usage='on_session' )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Use the new PaymentMethod ID and existing Customer ID to create a new payment \\Stripe\\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'error_on_requires_action' => true, 'confirm' => true, 'setup_future_usage' => 'on_session', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // Use the new PaymentMethod ID and existing Customer ID to create a new payment PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setCurrency("usd") .setAmount(1099L) .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setCustomer("{{CUSTOMER_ID}}") .setConfirm(true) .setErrorOnRequiresAction(true) .setSetupFutureUsage("on_session") .build(); PaymentIntent paymentIntent = PaymentIntent.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Use the new PaymentMethod ID and existing Customer ID to create a new payment const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, setup_future_usage: 'on_session', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // Use the new PaymentMethod ID and existing Customer ID to create a new payment params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Confirm: stripe.Bool(true), ErrorOnRequiresAction: stripe.Bool(true), SetupFutureUsage: stripe.String(string(stripe.PaymentIntentSetupFutureUsageOnSession)), } _, err := paymentintent.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethod = "{{PAYMENT_METHOD_ID}}", Confirm = true, ErrorOnRequiresAction = true, SetupFutureUsage = "on_session", }; var service = new PaymentIntentService(); service.Create(options);

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

6 Test the integration

By this point you should have an integration that:

  1. Collects card details without charging the customer
  2. Saves the card details to a customer
  3. Charges the card at a later date

Stripe has 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.

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

For the full list of test cards see our guide on testing.

Stripe allows you to collect your customer’s card details and charge at a later time.

In some regions, like Europe and India, banks often require a second form of authentication to make a purchase, such as entering a code sent to their phone. This decreases conversion if your customer is not actively using your website or application because they are not available to authenticate the purchase.

If you primarily do business in the U.S. and Canada, banks do not require authentication and 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.

1 Set up Stripe Client-side Server-side

First, you need a Stripe account. Register now.

Set up the iOS and server Stripe SDKs before starting your integration.

Server-side

This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries:

# Available as a gem gem install stripe
# If you use bundler, you can add this line to your Gemfile gem 'stripe'
# Install through pip pip install --upgrade stripe
# Or find the Stripe package on http://pypi.python.org/pypi/stripe/
# Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=2.48.0,<3.0
# Install the PHP library via Composer composer require stripe/stripe-php
# Or download the source directly: https://github.com/stripe/stripe-php/releases
/* For Gradle, add the following dependency to your build.gradle and replace {VERSION} with the version number you want to use from - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:{VERSION}"
<!-- For Maven, add the following dependency to your POM and replace {VERSION} with the version number you want to use from - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest --> <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
# For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson
# Install via npm npm install --save stripe
# Make sure your project is using Go Modules god mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v71
// Then import the package import ( "github.com/stripe/stripe-go/v71" )
# Install via dotnet dotnet add package Stripe.net dotnet restore
# Or install via NuGet PM> Install-Package Stripe.net

Client-side

The iOS SDK is open source, fully documented, and compatible with apps supporting iOS 10 or above.

  1. If you haven't already, install the latest version of CocoaPods.
  2. If you don't have an existing Podfile, run the following command to create one:
    pod init
  3. Add this line to your Podfile:
    pod 'Stripe'
  4. Run the following command:
    pod install
  5. Don't forget to use the .xcworkspace file to open your project in Xcode, instead of the .xcodeproj file, from here on out.
  6. In the future, to update to the latest version of the SDK, just run:
    pod update Stripe
  1. If you haven't already, install the latest version of Carthage.
  2. Add this line to your Cartfile:
    github "stripe/stripe-ios"
  3. Follow the Carthage installation instructions.
  4. In the future, to update to the latest version of the SDK, run the following command:
    carthage update stripe-ios --platform ios
  1. Head to our GitHub releases page and download and unzip Stripe.framework.zip.
  2. Drag Stripe.framework to the "Embedded Binaries" section of your Xcode project's "General" settings. Make sure to select "Copy items if needed".
  3. Head to the "Build Phases" section of your Xcode project settings, and create a new "Run Script Build Phase". Paste the following snippet into the text field:
    bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stripe.framework/integrate-dynamic-framework.sh"
  4. In the future, to update to the latest version of our SDK, just repeat steps 1 and 2.

When your app starts, configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API.

import UIKit import Stripe @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { Stripe.setDefaultPublishableKey("pk_test_TYooMQauvdEDq54NiTphI7jx") // do any other necessary launch configuration return true } }
#import "AppDelegate.h" #import <Stripe/Stripe.h> @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Stripe setDefaultPublishableKey:@"pk_test_TYooMQauvdEDq54NiTphI7jx"]; // do any other necessary launch configuration return YES; } @end

2 Collect card details Client-side

Start by displaying a payment form to your customer. Collect card details from the customer using STPPaymentCardTextField, a drop-in UI component provided by the SDK.

STPPaymentCardTextField performs on-the-fly validation and formatting.

Pass the card details to createPaymentMethod to create a PaymentMethod.

class CheckoutViewController: UIViewController { lazy var cardTextField: STPPaymentCardTextField = { let cardTextField = STPPaymentCardTextField() return cardTextField }() @objc func pay() { // Collect card details on the client let cardParams = cardTextField.cardParams let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: nil, metadata: nil) STPAPIClient.shared().createPaymentMethod(with: paymentMethodParams) { [weak self] paymentMethod, error in guard let paymentMethod = paymentMethod else { // Display the error to the user return } let paymentMethodId = paymentMethod.stripeId // Send paymentMethodId to your server for the next steps } } }
@interface CheckoutViewController () @property (nonatomic, weak) STPPaymentCardTextField *cardTextField; @end @implementation CheckoutViewController - (void)pay { // Collect card details on the client STPPaymentMethodCardParams *cardParams = self.cardTextField.cardParams; STPPaymentMethodParams *paymentMethodParams = [STPPaymentMethodParams paramsWithCard:cardParams billingDetails:nil metadata:nil]; [[STPAPIClient sharedClient] createPaymentMethodWithParams:paymentMethodParams completion:^(STPPaymentMethod *paymentMethod, NSError *createError) { // Create PaymentMethod failed if (createError != nil) { // Display the error to the user return; } NSString *paymentMethodId = paymentMethod.stripeId; // Send paymentMethodId to your server for the next steps }]; } @end

Send the resulting PaymentMethod ID to your server and follow the remaining steps to save the card to a customer and charge the card in the future.

3 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}}"
stripe customers create --payment-method={{PAYMENT_METHOD_ID}}
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # This creates a new Customer and attaches the PaymentMethod in one API call. customer = Stripe::Customer.create({ payment_method: '{{PAYMENT_METHOD_ID}}', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # This creates a new Customer and attaches the PaymentMethod in one API call. stripe.Customer.create( payment_method='{{PAYMENT_METHOD_ID}}', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // This creates a new Customer and attaches the PaymentMethod in one API call. \Stripe\Customer::create([ 'payment_method' => '{{PAYMENT_METHOD_ID}}', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // This creates a new Customer and attaches the PaymentMethod in one API call. CustomerCreateParams params = CustomerCreateParams.builder() .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .build(); Customer customer = Customer.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // This creates a new Customer and attaches the PaymentMethod in one API call. const customer = await stripe.customers.create({ payment_method: '{{PAYMENT_METHOD_ID}}', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // This creates a new Customer and attaches the PaymentMethod in one API call. params := &stripe.CustomerParams{ PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), } c, _ := customer.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new CustomerCreateOptions { PaymentMethod = "{{PAYMENT_METHOD_ID}}", }; var service = new CustomerService(); var customer = service.Create(options);

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

curl https://api.stripe.com/v1/payment_methods/{{PAYMENT_METHOD_ID}}/attach \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer="{{CUSTOMER_ID}}"
stripe payment_methods attach {{PAYMENT_METHOD_ID}} --customer={{CUSTOMER_ID}}
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' payment_method = Stripe::PaymentMethod.attach( '{{PAYMENT_METHOD_ID}}', { customer: '{{CUSTOMER_ID}}', } )
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' payment_method = stripe.PaymentMethod.attach( '{{PAYMENT_METHOD_ID}}', customer='{{CUSTOMER_ID}}' )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $payment_method = \Stripe\PaymentMethod::retrieve('{{PAYMENT_METHOD_ID}}'); $payment_method->attach(['customer' => '{{CUSTOMER_ID}}']);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentMethod paymentMethod = PaymentMethod.retrieve("{{PAYMENT_METHOD_ID}}"); PaymentMethodAttachParams params = PaymentMethodAttachParams.builder() .setCustomer("{{CUSTOMER_ID}}") .build(); paymentMethod.attach(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentMethod = await stripe.paymentMethods.attach( '{{PAYMENT_METHOD_ID}}', { customer: '{{CUSTOMER_ID}}', } );
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentMethodAttachParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), } pm, _ := paymentmethod.Attach("{{PAYMENT_METHOD_ID}}", params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentMethodAttachOptions { Customer = "{{CUSTOMER_ID}}", }; var service = new PaymentMethodService(); var paymentMethod = service.Attach("{{PAYMENT_METHOD_ID}}", options);

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

4 Charge the saved card Server-side

When you are ready to charge the Customer, look up the PaymentMethod ID 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 https://api.stripe.com/v1/payment_methods \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer="{{CUSTOMER_ID}}" \ -d type=card \ -G
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' Stripe::PaymentMethod.list({ customer: '{{CUSTOMER_ID}}', type: 'card', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' stripe.PaymentMethod.list( customer="{{CUSTOMER_ID}}", type="card", )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); \Stripe\PaymentMethod::all([ 'customer' => '{{CUSTOMER_ID}}', 'type' => 'card', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentMethodListParams params = PaymentMethodListParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setType(PaymentMethodListParams.Type.CARD) .build(); PaymentMethodCollection paymentMethods = PaymentMethod.list(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentMethods = await stripe.paymentMethods.list({ customer: '{{CUSTOMER_ID}}', type: 'card', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentMethodListParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Type: stripe.String(string(stripe.PaymentMethodTypeCard)), } i := paymentmethod.List(params) for i.Next() { pm := i.PaymentMethod() }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentMethodListOptions { Customer = "{{CUSTOMER_ID}}", Type = "card", }; var service = new PaymentMethodService(); var paymentMethods = service.List(options);

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.

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
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' begin intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, }) rescue Stripe::CardError => e # Error code will be authentication_required if authentication is needed puts "Error is: #{e.error.code}" payment_intent_id = e.error.payment_intent.id payment_intent = Stripe::PaymentIntent.retrieve(payment_intent_id) puts payment_intent.id end
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' try: stripe.PaymentIntent.create( amount=1099, currency='usd', customer='{{CUSTOMER_ID}}', payment_method='{{PAYMENT_METHOD_ID}}', error_on_requires_action=True, confirm=True, ) except stripe.error.CardError as e: err = e.error # Error code will be authentication_required if authentication is needed print("Code is: %s" % err.code) payment_intent_id = err.payment_intent['id'] payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); try { \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'error_on_requires_action' => true, 'confirm' => true, ]); } catch (\Stripe\Exception\CardException $e) { // Error code will be authentication_required if authentication is needed echo 'Error code is:' . $e->getError()->code; $payment_intent_id = $e->getError()->payment_intent->id; $payment_intent = \Stripe\PaymentIntent::retrieve($payment_intent_id); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setCurrency("usd") .setAmount(1099) .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setCustomer("{{CUSTOMER_ID}}") .setConfirm(true) .setErrorOnRequiresAction(true) .build(); try { PaymentIntent.create(params); } catch (CardException err) { // Error code will be authentication_required if authentication is needed System.out.println("Error code is : " + e.getCode()); String paymentIntentId = e.getStripeError().getPaymentIntent().getId(); PaymentIntent paymentIntent = PaymentIntent.retrieve(paymentIntentId); System.out.println(paymentIntent.getId()); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); try { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, }); } catch (err) { // Error code will be authentication_required if authentication is needed console.log('Error code is: ', err.code); const paymentIntentRetrieved = await stripe.paymentIntents.retrieve(err.raw.payment_intent.id); console.log('PI retrieved: ', paymentIntentRetrieved.id); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Confirm: stripe.Bool(true), ErrorOnRequiresAction: stripe.Bool(true), } _, err := paymentintent.New(params) if err != nil { if stripeErr, ok := err.(*stripe.Error); ok { // Error code will be authentication_required if authentication is needed fmt.Printf("Error code: %v", stripeErr.Code) paymentIntentID := stripeErr.PaymentIntent.ID paymentIntent, _ := paymentintent.Get(paymentIntentID, nil) fmt.Printf("PI: %v", paymentIntent.ID) } }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; try { var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethod = "{{PAYMENT_METHOD_ID}}", Confirm = true, ErrorOnRequiresAction = true, }; service.Create(options); } catch (StripeException e) { switch (e.StripeError.ErrorType) { case "card_error": // Error code will be authentication_required if authentication is needed Console.WriteLine("Error code: " + e.StripeError.Code); var paymentIntentId = e.StripeError.PaymentIntent.Id; var service = new PaymentIntentService(); var paymentIntent = service.Get(paymentIntentId); Console.WriteLine(paymentIntent.Id); break; default: break; } }

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 (e.g., by sending an in-app notification) 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.

5 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 already have a Customer created.

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
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Use the new PaymentMethod ID and existing Customer ID to create a new payment intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, setup_future_usage: 'on_session', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Use the new PaymentMethod ID and existing Customer ID to create a new payment stripe.PaymentIntent.create( amount=1099, currency='usd', customer='{{CUSTOMER_ID}}', payment_method='{{PAYMENT_METHOD_ID}}', error_on_requires_action=True, confirm=True, setup_future_usage='on_session' )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Use the new PaymentMethod ID and existing Customer ID to create a new payment \\Stripe\\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'error_on_requires_action' => true, 'confirm' => true, 'setup_future_usage' => 'on_session', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // Use the new PaymentMethod ID and existing Customer ID to create a new payment PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setCurrency("usd") .setAmount(1099L) .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setCustomer("{{CUSTOMER_ID}}") .setConfirm(true) .setErrorOnRequiresAction(true) .setSetupFutureUsage("on_session") .build(); PaymentIntent paymentIntent = PaymentIntent.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Use the new PaymentMethod ID and existing Customer ID to create a new payment const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, setup_future_usage: 'on_session', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // Use the new PaymentMethod ID and existing Customer ID to create a new payment params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Confirm: stripe.Bool(true), ErrorOnRequiresAction: stripe.Bool(true), SetupFutureUsage: stripe.String(string(stripe.PaymentIntentSetupFutureUsageOnSession)), } _, err := paymentintent.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethod = "{{PAYMENT_METHOD_ID}}", Confirm = true, ErrorOnRequiresAction = true, SetupFutureUsage = "on_session", }; var service = new PaymentIntentService(); service.Create(options);

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

6 Test the integration

By this point you should have an integration that:

  1. Collects card details without charging the customer
  2. Saves the card details to a customer
  3. Charges the card at a later date

Stripe has 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.

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

For the full list of test cards see our guide on testing.

Stripe allows you to collect your customer’s card details and charge at a later time.

In some regions, like Europe and India, banks often require a second form of authentication to make a purchase, such as entering a code sent to their phone. This decreases conversion if your customer is not actively using your website or application because they are not available to authenticate the purchase.

If you primarily do business in the U.S. and Canada, banks do not require authentication and 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.

1 Set up Stripe Client-side Server-side

First, you need a Stripe account. Register now.

Set up the Android and server Stripe SDKs before starting your integration.

Server-side

This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server:

# Available as a gem gem install stripe
# If you use bundler, you can add this line to your Gemfile gem 'stripe'
# Install through pip pip install --upgrade stripe
# Or find the Stripe package on http://pypi.python.org/pypi/stripe/
# Find the version you want to pin: # https://github.com/stripe/stripe-python/blob/master/CHANGELOG.md # Specify that version in your requirements.txt file stripe>=2.48.0,<3.0
# Install the PHP library via Composer composer require stripe/stripe-php
# Or download the source directly: https://github.com/stripe/stripe-php/releases
/* For Gradle, add the following dependency to your build.gradle and replace {VERSION} with the version number you want to use from - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest */ implementation "com.stripe:stripe-java:{VERSION}"
<!-- For Maven, add the following dependency to your POM and replace {VERSION} with the version number you want to use from - https://mvnrepository.com/artifact/com.stripe/stripe-java or - https://github.com/stripe/stripe-java/releases/latest --> <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
# For other environments, manually install the following JARs: # - The Stripe JAR from https://github.com/stripe/stripe-java/releases/latest # - Google Gson from https://github.com/google/gson
# Install via npm npm install --save stripe
# Make sure your project is using Go Modules god mod init # Install stripe-go go get -u github.com/stripe/stripe-go/v71
// Then import the package import ( "github.com/stripe/stripe-go/v71" )
# Install via dotnet dotnet add package Stripe.net dotnet restore
# Or install via NuGet PM> Install-Package Stripe.net

Client-side

The Android SDK is open source and fully documented.

To install the SDK, add stripe-android to the dependencies block of your app/build.gradle file:

apply plugin: 'com.android.application' android { ... } dependencies { // ... // Stripe Android SDK implementation 'com.stripe:stripe-android:15.0.1' }

Configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API, such as in your Application subclass:

import com.stripe.android.PaymentConfiguration class MyApp : Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init( applicationContext, "pk_test_TYooMQauvdEDq54NiTphI7jx" ) } }
import com.stripe.android.PaymentConfiguration; public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); PaymentConfiguration.init( getApplicationContext(), "pk_test_TYooMQauvdEDq54NiTphI7jx" ); } }

2 Collect card details Client-side

When the customer submits the payment form, collect their card details using CardInputWidget, a drop-in UI component provided by the SDK.

CardInputWidget performs on-the-fly validation and formatting.

Pass the card details to createPaymentMethod to create a PaymentMethod.

class CheckoutActivity : AppCompatActivity() { private lateinit var stripe: Stripe private fun pay() { val weakActivity = WeakReference<Activity>(this) // Collect card details on the client val cardInputWidget = findViewById<CardInputWidget>(R.id.cardInputWidget) val params = cardInputWidget.paymentMethodCreateParams if (params == null) { return } // Configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API stripe = Stripe(applicationContext, PaymentConfiguration.getInstance(applicationContext).publishableKey) stripe.createPaymentMethod(params, object : ApiResultCallback<PaymentMethod> { // Create PaymentMethod failed override fun onError(e: Exception) { // Display the error to the user } override fun onSuccess(result: PaymentMethod) { val paymentMethodId = result.id // Send paymentMethodId to your server for the next steps } }) } private fun pay(paymentMethod: String?, paymentIntent: String?) { // ... } }
public class CheckoutActivity extends AppCompatActivity { private Stripe stripe; private void pay() { CardInputWidget cardInputWidget = findViewById(R.id.cardInputWidget); PaymentMethodCreateParams params = cardInputWidget.getPaymentMethodCreateParams(); if (params == null) { return; } // Configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API stripe = Stripe(applicationContext, PaymentConfiguration.getInstance(applicationContext).getPublishableKey()); stripe.createPaymentMethod(params, new ApiResultCallback<PaymentMethod>() { @Override public void onSuccess(@NonNull PaymentMethod result) { String paymentMethodId = result.id // Send paymentMethodId to your server for the next steps } @Override public void onError(@NonNull Exception e) { // Display the error to the user } }); }

Send the resulting PaymentMethod ID to your server and follow the remaining steps to save the card to a customer and charge the card in the future.

3 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}}"
stripe customers create --payment-method={{PAYMENT_METHOD_ID}}
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # This creates a new Customer and attaches the PaymentMethod in one API call. customer = Stripe::Customer.create({ payment_method: '{{PAYMENT_METHOD_ID}}', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # This creates a new Customer and attaches the PaymentMethod in one API call. stripe.Customer.create( payment_method='{{PAYMENT_METHOD_ID}}', )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // This creates a new Customer and attaches the PaymentMethod in one API call. \Stripe\Customer::create([ 'payment_method' => '{{PAYMENT_METHOD_ID}}', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // This creates a new Customer and attaches the PaymentMethod in one API call. CustomerCreateParams params = CustomerCreateParams.builder() .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .build(); Customer customer = Customer.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // This creates a new Customer and attaches the PaymentMethod in one API call. const customer = await stripe.customers.create({ payment_method: '{{PAYMENT_METHOD_ID}}', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // This creates a new Customer and attaches the PaymentMethod in one API call. params := &stripe.CustomerParams{ PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), } c, _ := customer.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new CustomerCreateOptions { PaymentMethod = "{{PAYMENT_METHOD_ID}}", }; var service = new CustomerService(); var customer = service.Create(options);

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

curl https://api.stripe.com/v1/payment_methods/{{PAYMENT_METHOD_ID}}/attach \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer="{{CUSTOMER_ID}}"
stripe payment_methods attach {{PAYMENT_METHOD_ID}} --customer={{CUSTOMER_ID}}
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' payment_method = Stripe::PaymentMethod.attach( '{{PAYMENT_METHOD_ID}}', { customer: '{{CUSTOMER_ID}}', } )
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' payment_method = stripe.PaymentMethod.attach( '{{PAYMENT_METHOD_ID}}', customer='{{CUSTOMER_ID}}' )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $payment_method = \Stripe\PaymentMethod::retrieve('{{PAYMENT_METHOD_ID}}'); $payment_method->attach(['customer' => '{{CUSTOMER_ID}}']);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentMethod paymentMethod = PaymentMethod.retrieve("{{PAYMENT_METHOD_ID}}"); PaymentMethodAttachParams params = PaymentMethodAttachParams.builder() .setCustomer("{{CUSTOMER_ID}}") .build(); paymentMethod.attach(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentMethod = await stripe.paymentMethods.attach( '{{PAYMENT_METHOD_ID}}', { customer: '{{CUSTOMER_ID}}', } );
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentMethodAttachParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), } pm, _ := paymentmethod.Attach("{{PAYMENT_METHOD_ID}}", params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentMethodAttachOptions { Customer = "{{CUSTOMER_ID}}", }; var service = new PaymentMethodService(); var paymentMethod = service.Attach("{{PAYMENT_METHOD_ID}}", options);

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

4 Charge the saved card Server-side

When you are ready to charge the Customer, look up the PaymentMethod ID 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 https://api.stripe.com/v1/payment_methods \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d customer="{{CUSTOMER_ID}}" \ -d type=card \ -G
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' Stripe::PaymentMethod.list({ customer: '{{CUSTOMER_ID}}', type: 'card', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' stripe.PaymentMethod.list( customer="{{CUSTOMER_ID}}", type="card", )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); \Stripe\PaymentMethod::all([ 'customer' => '{{CUSTOMER_ID}}', 'type' => 'card', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentMethodListParams params = PaymentMethodListParams.builder() .setCustomer("{{CUSTOMER_ID}}") .setType(PaymentMethodListParams.Type.CARD) .build(); PaymentMethodCollection paymentMethods = PaymentMethod.list(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); const paymentMethods = await stripe.paymentMethods.list({ customer: '{{CUSTOMER_ID}}', type: 'card', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentMethodListParams{ Customer: stripe.String("{{CUSTOMER_ID}}"), Type: stripe.String(string(stripe.PaymentMethodTypeCard)), } i := paymentmethod.List(params) for i.Next() { pm := i.PaymentMethod() }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentMethodListOptions { Customer = "{{CUSTOMER_ID}}", Type = "card", }; var service = new PaymentMethodService(); var paymentMethods = service.List(options);

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.

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
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' begin intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, }) rescue Stripe::CardError => e # Error code will be authentication_required if authentication is needed puts "Error is: #{e.error.code}" payment_intent_id = e.error.payment_intent.id payment_intent = Stripe::PaymentIntent.retrieve(payment_intent_id) puts payment_intent.id end
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' try: stripe.PaymentIntent.create( amount=1099, currency='usd', customer='{{CUSTOMER_ID}}', payment_method='{{PAYMENT_METHOD_ID}}', error_on_requires_action=True, confirm=True, ) except stripe.error.CardError as e: err = e.error # Error code will be authentication_required if authentication is needed print("Code is: %s" % err.code) payment_intent_id = err.payment_intent['id'] payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); try { \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'error_on_requires_action' => true, 'confirm' => true, ]); } catch (\Stripe\Exception\CardException $e) { // Error code will be authentication_required if authentication is needed echo 'Error code is:' . $e->getError()->code; $payment_intent_id = $e->getError()->payment_intent->id; $payment_intent = \Stripe\PaymentIntent::retrieve($payment_intent_id); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setCurrency("usd") .setAmount(1099) .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setCustomer("{{CUSTOMER_ID}}") .setConfirm(true) .setErrorOnRequiresAction(true) .build(); try { PaymentIntent.create(params); } catch (CardException err) { // Error code will be authentication_required if authentication is needed System.out.println("Error code is : " + e.getCode()); String paymentIntentId = e.getStripeError().getPaymentIntent().getId(); PaymentIntent paymentIntent = PaymentIntent.retrieve(paymentIntentId); System.out.println(paymentIntent.getId()); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); try { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, }); } catch (err) { // Error code will be authentication_required if authentication is needed console.log('Error code is: ', err.code); const paymentIntentRetrieved = await stripe.paymentIntents.retrieve(err.raw.payment_intent.id); console.log('PI retrieved: ', paymentIntentRetrieved.id); }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Confirm: stripe.Bool(true), ErrorOnRequiresAction: stripe.Bool(true), } _, err := paymentintent.New(params) if err != nil { if stripeErr, ok := err.(*stripe.Error); ok { // Error code will be authentication_required if authentication is needed fmt.Printf("Error code: %v", stripeErr.Code) paymentIntentID := stripeErr.PaymentIntent.ID paymentIntent, _ := paymentintent.Get(paymentIntentID, nil) fmt.Printf("PI: %v", paymentIntent.ID) } }
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; try { var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethod = "{{PAYMENT_METHOD_ID}}", Confirm = true, ErrorOnRequiresAction = true, }; service.Create(options); } catch (StripeException e) { switch (e.StripeError.ErrorType) { case "card_error": // Error code will be authentication_required if authentication is needed Console.WriteLine("Error code: " + e.StripeError.Code); var paymentIntentId = e.StripeError.PaymentIntent.Id; var service = new PaymentIntentService(); var paymentIntent = service.Get(paymentIntentId); Console.WriteLine(paymentIntent.Id); break; default: break; } }

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 (e.g., by sending an in-app notification) 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.

5 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 already have a Customer created.

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
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Use the new PaymentMethod ID and existing Customer ID to create a new payment intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, setup_future_usage: 'on_session', })
# Set your secret key. Remember to switch to your live secret key in production! # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' # Use the new PaymentMethod ID and existing Customer ID to create a new payment stripe.PaymentIntent.create( amount=1099, currency='usd', customer='{{CUSTOMER_ID}}', payment_method='{{PAYMENT_METHOD_ID}}', error_on_requires_action=True, confirm=True, setup_future_usage='on_session' )
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Use the new PaymentMethod ID and existing Customer ID to create a new payment \\Stripe\\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', 'customer' => '{{CUSTOMER_ID}}', 'payment_method' => '{{PAYMENT_METHOD_ID}}', 'error_on_requires_action' => true, 'confirm' => true, 'setup_future_usage' => 'on_session', ]);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; // Use the new PaymentMethod ID and existing Customer ID to create a new payment PaymentIntentCreateParams params = PaymentIntentCreateParams.builder() .setCurrency("usd") .setAmount(1099L) .setPaymentMethod("{{PAYMENT_METHOD_ID}}") .setCustomer("{{CUSTOMER_ID}}") .setConfirm(true) .setErrorOnRequiresAction(true) .setSetupFutureUsage("on_session") .build(); PaymentIntent paymentIntent = PaymentIntent.create(params);
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); // Use the new PaymentMethod ID and existing Customer ID to create a new payment const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', customer: '{{CUSTOMER_ID}}', payment_method: '{{PAYMENT_METHOD_ID}}', error_on_requires_action: true, confirm: true, setup_future_usage: 'on_session', });
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" // Use the new PaymentMethod ID and existing Customer ID to create a new payment params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), Customer: stripe.String("{{CUSTOMER_ID}}"), PaymentMethod: stripe.String("{{PAYMENT_METHOD_ID}}"), Confirm: stripe.Bool(true), ErrorOnRequiresAction: stripe.Bool(true), SetupFutureUsage: stripe.String(string(stripe.PaymentIntentSetupFutureUsageOnSession)), } _, err := paymentintent.New(params)
// Set your secret key. Remember to switch to your live secret key in production! // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", Customer = "{{CUSTOMER_ID}}", PaymentMethod = "{{PAYMENT_METHOD_ID}}", Confirm = true, ErrorOnRequiresAction = true, SetupFutureUsage = "on_session", }; var service = new PaymentIntentService(); service.Create(options);

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

6 Test the integration

By this point you should have an integration that:

  1. Collects card details without charging the customer
  2. Saves the card details to a customer
  3. Charges the card at a later date

Stripe has 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.

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

For the full list of test cards see our guide on testing.

Upgrading your integration to handle card authentication

Congratulations! You completed an integration to save cards without authentication. Note that 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.
Developer tutorials on YouTube.
You can unsubscribe at any time. Read our privacy policy.