Skip to content
Create account or Sign in
The Stripe Docs logo
/
Ask AI
Create accountSign in
Get started
Payments
Revenue
Platforms and marketplaces
Money management
Developer resources
APIs & SDKsHelp
Overview
About Stripe payments
Upgrade your integration
Payments analytics
Online payments
OverviewFind your use caseUse Managed Payments
Use Payment Links
Use a prebuilt checkout page
Build a custom integration with Elements
    Overview
    Quickstart guides
    Stripe Elements
      Payment Element
        Payment Element best practices
        Card Element comparison
        Migrate to the Payment Element with Payment Intents
        Migrate to the Payment Element with Checkout Sessions
        Migrate to Confirmation Tokens
      Express Checkout Element
      Address Element
      Currency Selector Element
      Link Authentication Element
      Payment Method Messaging Element
      Tax ID Element
    Compare Checkout Sessions and PaymentIntents
    Design an advanced integration
    Customize look and feel
    Manage payment methods
    Collect additional information
    Build a subscriptions integration
    Dynamic updates
    Add discounts
    Collect taxes on your payments
    Redeem credits
    Let customers pay in their local currency
    Save and retrieve customer payment methods
    Send receipts and paid invoices
    Manually approve payments on your server
    Authorize and capture a payment separately
    Elements with Checkout Sessions API beta changelog
Build an in-app integration
In-person payments
Terminal
Payment methods
Add payment methods
Manage payment methods
Faster checkout with Link
Payment scenarios
Handle multiple currencies
Custom payment flows
Flexible acquiring
Orchestration
Beyond payments
Incorporate your company
Crypto
Agentic commerce
Financial Connections
Climate
Understand fraud
Radar fraud protection
Manage disputes
Verify identities
United States
English (United States)
HomePaymentsBuild a custom integration with ElementsStripe ElementsPayment Element

Migrate to the Payment Element with the Payment Intents API

Accept many payment methods with a single Element.

Interested in subscriptions, tax, discounts, shipping, or currency conversion?

Migrate to the Payment Element with the Checkout Sessions API, an integration that manages subscriptions, tax, discounts, shipping, and currency conversion for you.

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.

Note

If your integration still uses the Charges API with tokens, follow the Migrating to the Payment Intents API guide first.

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-authorized 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 instance
Client-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.

Before
After
const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); const elements = stripe.elements();
const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); const options = { mode: 'payment', currency: 'usd', amount: 1099, }; const elements = stripe.elements(options);

OptionalSave payment details during a payment

If your existing integration also saves payment details during a payment, use the setup_future_usage option when creating the Elements group instead of passing it at the confirm payment stage with stripe.confirmCardPayment. The Payment Element will use this information to display additional input fields and show mandates as needed.

Caution

You can’t save some payment methods during payments. You can still enable these payment methods for other use cases, but customers won’t see them as an option when setting up future payments. See Payment method integration options for more details about what’s supported.

const stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); const options = { mode: 'payment', currency: 'usd', amount: 1099, setup_future_usage: 'off_session', }; const elements = stripe.elements(options);

You also need to pass setup_future_usage when creating your PaymentIntent.

Command Line
curl
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:
\ -d "customer"="{{CUSTOMER_ID}}" \ -d "setup_future_usage"= "off_session" \ -d "amount"=1099 \ -d "currency"="usd" \

OptionalAdditional Elements options
Client-side

The Elements object accepts additional options that influence payment collection. Based on the options provided, the Payment Element displays available payment methods from those you’ve enabled. Learn more about payment method support.

PropertyTypeDescriptionRequired
mode
  • payment
  • setup
  • subscription
Indicates whether the Payment Element is used with a PaymentIntent, SetupIntent, or Subscription.Yes
currencystringThe currency of the amount to charge the customer.Yes
amountnumberThe amount to charge the customer, shown in Apple Pay, Google Pay, or BNPL UIs.For payment and subscription mode
setupFutureUsage
  • off_session
  • on_session
Indicates that you intend to make future payments with the payment details collected by the Payment Element. No
captureMethod
  • automatic
  • automatic_async
  • manual
Controls when to capture the funds from the customer’s account.No
onBehalfOfstringConnect only. The Stripe account ID, which is the business of record. See use cases to determine if this option is relevant for your integration.No
paymentMethodTypesstring[]A list of payment method types to render. You can omit this attribute to manage your payment methods in the Stripe Dashboard.No
paymentMethodConfigurationstringThe payment method configuration to use when managing your payment methods in the Stripe Dashboard. If not specified, your default configuration is used.No
paymentMethodCreationmanualAllows PaymentMethods to be created from the Elements instance using stripe.createPaymentMethod.No
paymentMethodOptions{us_bank_account: {verification_method: string}}Verification options for the us_bank_account payment method. Accepts the same verification methods as Payment Intents.No
paymentMethodOptions{card: {installments: {enabled: boolean}}}Allows manually enabling the card installment plan selection UI if applicable when you aren’t managing your payment methods in the Stripe Dashboard. You must set mode='payment' and explicitly specify paymentMethodTypes. Otherwise an error is raised. Incompatible with paymentMethodCreation='manual'.No

Add the Payment Element
Client-side

If you’re using React Stripe.js, update to the latest package to use the Payment Element.

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:

checkout.html
JavaScript
React
No results
<form id="payment-form"> <div id="card-element"> </div> <div id="payment-element"> <!-- Mount the Payment Element here --> </div> <button id="submit">Submit</button> </form>
checkout.js
JavaScript
React
No results
const cardElement = elements.create("card"); cardElement.mount("#card-element"); const paymentElement = elements.create("payment"); paymentElement.mount("#payment-element");

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 call
Server-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.

Command Line
curl
Ruby
Python
PHP
Java
Node.js
Go
.NET
Stripe CLI
No results
curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_BQokikJOvBiI2HlWgH4olfQ2
:
\ -H "Stripe-Version: 2025-10-29.clover" \ -d "amount"=1099 \ -d "currency"="usd" \ -d "payment_method_types[]"=card \ -d "automatic_payment_methods[enabled]"=true \

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 handler
Client-side

Instead of using individual confirm methods like stripe.confirmCardPayment or stripe.confirmP24Payment, 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.submit() to trigger form validation and collect any data required for wallets.
  • 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 the clientSecret from the PaymentIntent as parameters to stripe.confirmPayment.

When called, stripe.confirmPayment attempts to complete any required actions, such as authenticating your customers by displaying a 3DS dialog or redirecting them to a bank authorization page. When confirmation is complete, users are directed to the return_url 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_required.

The following code example replaces stripe.confirmCardPayment with stripe.confirmPayment:

Before
After
// 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 events
Server-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_intent.succeeded event, we recommend handling these other events when collecting payments with the Payment Element:

EventDescriptionAction
payment_intent.succeededSent when a customer successfully completes a payment.Send the customer an order confirmation and fulfill their order.
payment_intent.processingSent 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_intent.succeeded or payment_intent.payment_failed 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_failedSent when a customer attempts a payment, but the payment fails.If a payment transitions from processing to payment_failed, offer the customer another attempt to pay.

Test the integration

Card numberScenarioHow to test
The card payment succeeds and doesn’t require authentication.Fill out the credit card form using the credit card number with any expiration, CVC, and postal code.
The card payment requires authentication.Fill out the credit card form using the credit card number with any expiration, CVC, and postal code.
The card is declined with a decline code like insufficient_funds.Fill out the credit card form using the credit card number with any expiration, CVC, and postal code.
The UnionPay card has a variable length of 13-19 digits.Fill out the credit card form using the credit card number with any expiration, CVC, and postal code.

See Testing for additional information to test your integration.

Was this page helpful?
YesNo
  • Need help? Contact Support.
  • Check out our changelog.
  • Questions? Contact Sales.
  • LLM? Read llms.txt.
  • Powered by Markdoc