Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
Security
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support
Overview
Payment Intents
Setup Intents
Payment Methods
Older APIs
Charges
Migrate to the new APIs
Accept a card payment
Save a card
Place a hold on a card
Charges with Connect
Sources
ACH Direct Debit (deprecated)
Testing
No-code options
HomePaymentsOlder APIsCharges

Migrating to the Payment Intents API

Learn how to migrate your existing cards and Charges API integration.

If your integration controls when funds move (for example, waits for the response from the client before finalizing the payment on the server), you can use the server-side confirmation guide (with some limitations).

Migrating your payment flow can be daunting. It is safe to incrementally adopt the Payment Intents API and use it in parallel with the Charges API. To this end, you can split up the migration into the following steps:

  1. Update your API version and your client library.
  2. If applicable, migrate code that reads from Charge properties so that you have a consistent read path between charges created by the Charges API and charges created by the Payment Intents API. This ensures a read-side integration that works for both your old and new payments integrations.
  3. Migrate your existing Charges API integration on Web, iOS, and Android to use the Payment Intents API.
  4. Migrate your integration that saves cards on Customer objects.
  5. Test with regulatory test cards to ensure your upgraded integration handles authentication correctly.

Update your API version and your client library

While the Payment Intents API works on all API versions, we recommend that you upgrade to the latest API version. If you decide to use an API version older than 2019-02-11, note the following two changes as you go through the code examples:

  • requires_source has been renamed to requires_payment_method
  • requires_source_action has been renamed to requires_action

In addition, if you use one of our Client libraries, upgrade to the latest version of the library in order to use the Payment Intents API.

Migrate your one-time payment flows

An integration built with Stripe.js & Elements consists of the following steps:

  1. Register your intent to collect payment on the server side
  2. Collect payment details on the client side
  3. Initiate creation of the payment
  4. Fulfill the customer’s order on the server side

Step 1: Register intent to collect payment on the server side

Create a PaymentIntent on your server and make it accessible on the client side.

Before
After

Not possible before

Terminal
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "amount"=1099 \ -d "currency"="usd"

Step 2: Collect payment details on the client side

Use the confirmCardPayment function, which collects the payment information and submits it directly to Stripe.

Before
After
stripe.createToken( cardElement ).then(function(token) { // Send token to server });
stripe.confirmCardPayment( INTENT_SECRET_FROM_STEP_1, { payment_method: {card: cardElement} } ).then(function(result) { if (result.error) { // Display error.message in your UI. } else { // The payment has succeeded // Display a success message } });

Step 3: Initiate creation of the payment

In your existing integration, the final step is using tokenized payment information to create a charge on your server. This is no longer necessary, as the confirmCardPayment function—called in the previous step—initiates creation of the charge.

Before
After
Terminal
curl https://api.stripe.com/v1/charges \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "source"="{{FROM_PREVIOUS_STEP}}" \ -d "amount"=1099 \ -d "currency"="usd"

Completed in previous step

Step 4: Fulfill the customer’s order

With automatic confirmation, the charge is created for you asynchronously based on customer action on the client side, so you must monitor webhooks to determine when the payment completes successfully. To perform steps like order fulfillment after a customer’s payment is successful, implement support for webhooks and monitor the payment_intent.succeeded event.

Before
After

If charge succeeds, fulfill.

Subscribe to the payment_intent.succeeded webhook and fulfill in the webhook handler.

Now that you have migrated, use the test cards in the following section to verify your upgraded integration handles 3D Secure authentication.

Migrate your integration that saves cards on Customer objects

A Payment Intents API integration that collects card information in the checkout flow consists of the following steps:

  1. Register your intent to collect payment on the server side
  2. Collect payment details on the client side
  3. Initiate creation of the payment
  4. Fulfill the customer’s order on the server side

Step 1: Register intent to collect payment on the server side

Create a PaymentIntent on your server. Set setup_future_usage to off_session if you primarily intend to charge users when they are outside of your application, or on_session if you plan to charge them in the application. If you plan to use the card for both on and off session payments use off_session. Providing the setup_future_usage parameter along with a Customer ID will save the resulting PaymentMethod to that Customer after the PaymentIntent has been confirmed and any required actions from the customer are complete. Next, make the PaymentIntent accessible on the client side.

Before
After

Not possible before

Terminal
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "setup_future_usage"="off_session" \ -d "amount"=1099 \ -d "currency"="usd"

Step 2: Collect payment details on the client side

Use the confirmCardPayment function, which collects the payment information and submits it directly to Stripe.

Before
After
stripe.createToken( // or stripe.createSource cardElement ).then(function(token) { // Send token to server });
stripe.confirmCardPayment( '{{INTENT_SECRET_FROM_STEP_1}}', { payment_method: {card: cardElement}, } ).then(function(result) { if (result.error) { // Display error.message in your UI. } else { // The payment has succeeded // Display a success message } });

Finally, attach the payment method (paymentIntent.payment_method) to the customer.

Before
After
Terminal
curl https://api.stripe.com/v1/customers/{{CUSTOMER_ID}}/sources \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "source"="{{TOKEN_OR_SOURCE}}"
Terminal
curl https://api.stripe.com/v1/payment_method/{{PAYMENT_METHOD_ID}}/attach \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "customer"="{{CUSTOMER_ID}}"

Step 3: Initiate creation of the payment

In your existing integration, the final step is using tokenized payment information to create a charge on your server. This is no longer necessary, as the confirmCardPayment function—called in the previous step—initiates creation of the charge.

Before
After
Terminal
curl https://api.stripe.com/v1/charges \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "source"="{{FROM_PREVIOUS_STEP}}" \ -d "customer"="{{CUSTOMER_ID}}" \ -d "amount"=1099 \ -d "currency"="usd"

Completed in previous step

Step 4: Fulfill the customer’s order

With automatic confirmation, the charge is created for you asynchronously based on customer action on the client side, so you must monitor webhooks to determine when the payment completes successfully. To perform steps like order fulfillment after a customer’s payment is successful, implement support for webhooks and monitor the payment_intent.succeeded event.

Before
After

If charge succeeds, fulfill.

Subscribe to the payment_intent.succeeded webhook and fulfill in the webhook handler.

Now that you have migrated, use the test cards in the following section to verify your upgraded integration handles 3D Secure authentication.

Access saved payment methods

To display the customer’s previously saved Cards, Sources, and PaymentMethods, list the payment methods instead of reading the sources property of the customer object. This is required because new PaymentMethods added to a customer will not be duplicated in the sources property of the customer object.

Before
After
Terminal
customer.sources
Terminal
curl https://api.stripe.com/v1/payment_methods?customer={{CUSTOMER_ID}}&type=card \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
:

Test the integration

It’s important to thoroughly test your integration to make sure you’re correctly handling cards that require additional authentication and cards that don’t. Use these card numbers in test mode with any expiration date in the future and any three digit CVC code to validate your integration when authentication is required and when it’s not required.

Number
Authentication
Description
Required on setup or first transactionThis test card requires authentication for one-time payments. However, if you set up this card using the Setup Intents API and use the saved card for subsequent payments, no further authentication is needed.
RequiredThis test card requires authentication on all transactions.
RequiredThis test card requires authentication, but payments will be declined with an insufficient_funds failure code after successful authentication.
SupportedThis test card supports authentication via 3D Secure 2, but does not require it. Payments using this card do not require additional authentication in test mode unless your test mode Radar rules request authentication.

Use these cards in your application or the payments demo to see the different behavior.

See also

  • Payment Intents on iOS
  • Payment Intents on Android
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
Update your API version and your client library
Migrate your one-time payment flows
Migrate your integration that saves cards on Customer objects
Access saved payment methods
Test the integration
See also
Stripe Shell
Test mode
▗▄ ▄▟█ █▀▀ ▗▟████▙▖ ██████ ███▗▟█ ███ ███▗▟██▙▖ ▗▟█████▙▖ ███▖ ▀▀ ███ ███▀▀▀ ███ ███▀ ███ ███ ███ ▝▜████▙▖ ███ ███ ███ ███ ███ █████████ ▄▄ ▝███ ███ ▄ ███ ███ ███▄ ███ ███ ▄▄ ▝▜████▛▘ ▝▜███▛ ███ ███ ███▝▜██▛▘ ▝▜█████▛▘ ███ ▀▘
Welcome to the Stripe Shell! This is a graphical user interface of the Stripe CLI. You can use it to discover webhook events and manage your Stripe resources. By pressing ctrl + ` you can toggle it open from any page within the Stripe documentation. - View supported commands: - Listen for webhook events: - Trigger webhook events: - Call Stripe APIs: stripe [api resource] [api operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$