Migrate to the Payment Element
Accept many payment methods with a single Element.
Note
If your integration still uses the Charges API with tokens, follow the Migrating to the Payment Intents API guide first.
Interested in using Stripe Billing, Tax, discounts, shipping, or currency conversion?
We’re developing a Payment Element integration that manages subscriptions, tax, discounts, shipping, and currency conversion. Read the Build a checkout page guide to learn more.
Previously, each payment method (cards, iDEAL, and so on) required a separate Element. By migrating to the Payment Element, you can accept many payment methods with a single Element.
PaymentIntents and SetupIntents each have their own set of migration guidelines. See the appropriate guide for your integration path, including example code.
If your existing integration uses the Payment Intents API to create and track payments or save card details during a payment, follow the steps below to use the Payment Element.
Enable payment methods
Caution
This integration path doesn’t support BLIK or pre-authorised debits that use the Automated Clearing Settlement System (ACSS).
View your payment methods settings and enable the payment methods you want to support. You need at least one payment method enabled to create a PaymentIntent.
By default, Stripe enables cards and other prevalent payment methods that can help you reach more customers, but we recommend turning on additional payment methods that are relevant for your business and customers. See Payment method support for product and payment method support, and our pricing page for fees.
Update Elements instanceClient-side
Next, update your client-side code to pass mode
, currency
, and amount
when you create the Elements instance. For use with a PaymentIntent, set the mode
to 'payment'
and the currency
and amount
to what you’ll charge your customer.
Add the Payment ElementClient-side
You can now replace the Card Element and individual payment methods Elements with the Payment Element. The Payment Element automatically adjusts to collect input fields based on the payment method and country (for example, full billing address collection for SEPA Direct Debit) so you don’t have to maintain customized input fields anymore.
The following example replaces CardElement
with PaymentElement
:
If your payment flow already always collects details like the customer’s name or email address, you can prevent the Payment Element from collecting this information by passing the fields option when creating the Payment Element. If you disable the collection of a certain field, you must pass that same data back with stripe.confirmPayment.
Update your PaymentIntent creation callServer-side
The Payment Element allows you to accept multiple payment methods. You can manage payment methods from the Dashboard. Stripe handles the return of eligible payment methods based on factors such as the transaction’s amount, currency, and payment flow. We prioritize payment methods that increase conversion and are most relevant to the customer’s currency and location.
Any of the additional elements options passed when creating the Elements group in the earlier step should also be passed when creating the PaymentIntent.
Caution
Each payment method needs to support the currency passed in the PaymentIntent and your business needs to be based in one of the countries each payment method supports. See the Payment method integration options page for more details about what’s supported.
Update the submit handlerClient-side
Instead of using individual confirm methods like stripe.
or stripe.
, use stripe.confirmPayment to collect payment information and submit it to Stripe.
To confirm the PaymentIntent, make the following updates to your submit handler:
- Call
await elements.
to trigger form validation and collect any data required for wallets.submit() - Optional: Move PaymentIntent creation to the submit handler. This way you only create the PaymentIntent when you’re sure of the final amount.
- Pass the
elements
instance you used to create the Payment Element and theclientSecret
from the PaymentIntent as parameters tostripe.
.confirmPayment
When called, stripe.
attempts to complete any required actions, such as authenticating your customers by displaying a 3DS window or redirecting them to a bank authorisation page. When confirmation is complete, users are directed to the return_
you configured, which normally corresponds to a page on your website that provides the status of the payment.
If you want to keep the same checkout flow for card payments and only redirect for redirect-based payment methods, you can set redirect to if_
.
The following code example replaces stripe.
with stripe.
:
// Create the PaymentIntent and obtain clientSecret const res = await fetch("/create-intent", { method: "POST", headers: {"Content-Type": "application/json"}, }); const {client_secret: clientSecret} = await res.json(); const handleSubmit = async (event) => { event.preventDefault(); if (!stripe) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } setLoading(true); const {error} = await stripe.confirmCardPayment(clientSecret, { payment_method: { card: elements.getElement(CardElement) } }); if (error) { handleError(error); } };
const handleSubmit = async (event) => { event.preventDefault(); if (!stripe) { // Stripe.js hasn't yet loaded. // Make sure to disable form submission until Stripe.js has loaded. return; } setLoading(true); // Trigger form validation and wallet collection const {error: submitError} = await elements.submit(); if (submitError) { handleError(submitError); return; } // Create the PaymentIntent and obtain clientSecret const res = await fetch("/create-intent", { method: "POST", headers: {"Content-Type": "application/json"}, }); const {client_secret: clientSecret} = await res.json(); // Use the clientSecret and Elements instance to confirm the setup const {error} = await stripe.confirmPayment({ elements, clientSecret, confirmParams: { return_url: 'https://example.com/order/123/complete', }, // Uncomment below if you only want redirect for redirect-based payments // redirect: "if_required", }); if (error) { handleError(error); } };
Handle post-payment eventsServer-side
Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard webhook tool or follow the webhook guide to receive these events and run actions, such as sending an order confirmation email to your customer, logging the sale in a database, or starting a shipping workflow.
Listen for these events rather than waiting on a callback from the client. On the client, the customer could close the browser window or quit the app before the callback executes, and malicious clients could manipulate the response. Setting up your integration to listen for asynchronous events is what enables you to accept different types of payment methods with a single integration.
In addition to handling the payment_
event, we recommend handling these other events when collecting payments with the Payment Element:
Event | Description | Action |
---|---|---|
payment_intent.succeeded | Sent when a customer successfully completes a payment. | Send the customer an order confirmation and fulfill their order. |
payment_intent.processing | Sent when a customer successfully initiates a payment, but the payment has yet to complete. This event is most commonly sent when the customer initiates a bank debit. It’s followed by either a payment_ or payment_ event in the future. | Send the customer an order confirmation that indicates their payment is pending. For digital goods, you might want to fulfill the order before waiting for payment to complete. |
payment_intent.payment_failed | Sent when a customer attempts a payment, but the payment fails. | If a payment transitions from processing to payment_ , offer the customer another attempt to pay. |
Test the integration
See Testing for additional information to test your integration.