Legacy
Finalise payments on the server Legacy
Build an integration where you render the Payment Element before you create a PaymentIntent or SetupIntent, then confirm the Intent from your server.
Web
iOS
Android
React Native
Warning
You’re currently viewing an unsupported implementation. If you’re using an older integration with createPaymentMethod, we recommend you use our latest docs to Finalise payments on the server and Migrate to Confirmation Tokens.
The Payment Element allows you to accept multiple payment methods using a single integration. In this integration, you’ll build a custom payment flow where you render the Payment Element, create the PaymentIntent, and confirm the payment from your server.
Set up Stripe Server-side
First, create a Stripe account or sign in.
Use our official libraries to access the Stripe API from your application:
Command Line
Select a language
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# Available as a gem
sudo gem install stripe
Gemfile
Select a language
Ruby
Python
PHP
Java
Node.js
Go
.NET
No results
# If you use bundler, you can add this line to your Gemfile
gem 'stripe'
Enable payment methods
Caution
This integration path doesn’t support the related setting or pre-authorised debits that use the Automated Clearing Settlement System (the related setting). Also, if you create the deferred intent from the client-side, you can’t use customer_balance with dynamic payment methods because the PaymentIntent requires a customer-configured Account or Customer object, which the client-side flow doesn’t support. To use customer_balance, create the PaymentIntent server-side with an Account or Customer and return its client_secret to the client.
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.
Collect payment details Client-side
Use the Payment Element to securely send payment information collected in an iFrame to Stripe over an HTTPS connection.
Conflicting iFrames
Avoid placing the Payment Element within another iframe because it conflicts with payment methods that require redirecting to another page for payment confirmation.
Your checkout page URL must start with https:// rather than http:// for your integration to work. You can test your integration without using HTTPS, but remember to enable it when you’re ready to accept live payments.
Set up Stripe.js
The Payment Element is automatically available as a feature of Stripe.js. Include the Stripe.js script on your checkout page by adding it to the head of your HTML file. Always load Stripe.js directly from js.stripe.com to remain PCI compliant. Don’t include the script in a bundle or host a copy of it yourself.
checkout.html
Create an instance of Stripe with the following JavaScript on your checkout page:
checkout.js
// Set your publishable key: remember to change this to your live publishable key in production
// See your keys here: https://dashboard.stripe.com/apikeys
const stripe = Stripe('pk_test_GvF3BSyx8RSXMK5yAFhqEd3H');
Add the Payment Element to your checkout page
The Payment Element needs a place to live on your checkout page. Create an empty DOM node (container) with a unique ID in your payment form:
checkout.html
<form id="payment-form">
<div id="payment-element">
<!-- Elements will create form elements here -->
</div>
<button id="submit">Submit</button>
<div id="error-message">
<!-- Display error message to your customers here -->
</div>
</form>
After your form loads, create an Elements instance with the mode, amount, and currency. These values determine which payment methods the Element presents to your customer.
Then, create an instance of the Payment Element and mount it to the container DOM node.
checkout.js
const options = {
mode: 'payment',
amount: 1099,
currency: 'usd',
paymentMethodCreation: 'manual',
// Fully customizable with appearance API.
appearance: {/*...*/},
};
// Set up Stripe.js and Elements to use in checkout form
const elements = stripe.elements(options);
// Create and mount the Payment Element
const paymentElementOptions = { layout: 'accordion'};
const paymentElement = elements.create('payment', paymentElementOptions);
paymentElement.mount('#payment-element');
The Payment Element renders a dynamic form that allows your customer to pick a payment method. The form automatically collects all necessary payments details for the payment method selected by the customer.
You can customise the Payment Element to match the design of your site by passing the appearance object into options when creating the Elements provider.
Collect addresses
By default, the Payment Element only collects the necessary billing address details. Some behaviour, such as calculating tax or entering shipping details, requires your customer’s full address. You can:
- Use the Address Element to take advantage of autocomplete and localisation features to collect your customer’s full address. This helps ensure the most accurate tax calculation.
- Collect address details using your own custom form.
Optional Customise the layout Client-side
Optional Customise the appearance Client-side
Optional Save and retrieve customer payment methods
Optional Dynamically update payment details Client-side
Optional Additional Elements options Client-side
Create the PaymentMethod Client-side
When the customer submits your payment form, you can create a PaymentMethod to send to your server for additional validation or business logic prior to confirmation.
Caution
You must immediately use a created PaymentMethod to confirm a PaymentIntent and attach it to a Customer if you intend to use it in the future.
checkout.js
const form = document.getElementById('payment-form');
const submitBtn = document.getElementById('submit');
const handleError = (error) => {
const messageContainer = document.querySelector('#error-message');
messageContainer.textContent = error.message;
submitBtn.disabled = false;
}
form.addEventListener('submit', async (event) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();
// Prevent multiple form submissions
if (submitBtn.disabled) {
return;
}
// Disable form submission while loading
submitBtn.disabled = true;
// Trigger form validation and wallet collection
const {error: submitError} = await elements.submit();
if (submitError) {
handleError(submitError);
return;
}
// Create the PaymentMethod using the details collected by the Payment Element
const {error, paymentMethod} = await stripe.createPaymentMethod({
elements,
params: {
billing_details: {
name: 'Jenny Rosen',
}
}
});
if (error) {
// This point is only reached if there's an immediate error when
// creating the PaymentMethod. Show the error to your customer (for example, payment details incomplete)
handleError(error);
return;
}
// Create the PaymentIntent
const res = await fetch("/create-confirm-intent", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({
paymentMethodId: paymentMethod.id,
}),
});
const data = await res.json();
// Handle any next actions or errors. See the Handle any next actions step for implementation.
handleServerResponse(data);
});
Optional Insert custom business logic Server-side
Create and submit the payment to Stripe Server-side
When the customer submits your payment form, use a PaymentIntent to facilitate the confirmation and payment process. Create a PaymentIntent on your server with an amount and currency specified. In the latest version of the API, specifying the automatic_payment_methods parameter is optional because Stripe enables its functionality by default. 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. To prevent malicious customers from choosing their own prices, always decide how much to charge on the server-side (a trusted environment) and not the client.
You can use the PaymentMethod sent by your client to create and confirm the PaymentIntent in a single request.
Note
When confirming an Intent from the server, pass mandate_data to acknowledge that you’ve shown the customer the proper terms for collecting their payment details. To make sure you display the proper terms, all Elements options should match your Intent options (for example, setup_future_usage, amount, and currency).
app.js
Handle any next actions Client-side
When the PaymentIntent requires additional action from the customer, such as authenticating with 3D Secure or redirecting to a different site, you need to trigger those actions. Use stripe.handleNextAction to trigger the UI for handling customer action and completing the payment.
checkout.js
JavaScript
const handleServerResponse = async (response) => {
if (response.error) {
// Show error from server on payment form
} else if (response.status === "requires_action") {
// Use Stripe.js to handle the required next action
const {
error,
paymentIntent
} = await stripe.handleNextAction({
clientSecret: response.clientSecret
});
if (error) {
// Show error from Stripe.js in payment form
} else {
// Actions handled, show success message
}
} else {
// No actions needed, show success message
}
}
Optional Handle post-payment events
Disclose Stripe to your customers
Stripe collects information on customer interactions with Elements to provide services to you, prevent fraud, and improve its services. This includes using cookies and IP addresses to identify which Elements a customer saw during a single checkout session. You’re responsible for disclosing and obtaining all rights and consents necessary for Stripe to use data in these ways. For more information, visit our privacy center.
