Sign in
An image of the Stripe logo
Create account
Sign in
Home
Payments
Business operations
Financial services
Developer tools
All products
Home
Payments
Business operations
Home
Payments
Business operations
Financial services
Developer tools
Support

Accept a card payment

Securely accept card payments online.

We recommend that you follow the Accept a payment guide instead. Only use this guide if you need to use manual server-side confirmation or your integration requires presenting payment methods separately. If you’ve already integrated with Elements, see the Payment Element migration guide.

Complexity:

Customize all components with CSS.

Integrate Apple Pay and Google Pay with extra code.

Clone a sample integration from the docs or on GitHub.

Set up Stripe
Server-side

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

Terminal
# For detailed setup, see our quickstarts at https://stripe.com/docs/development/quickstart bundle add stripe bundle install

Create a PaymentIntent
Server-side

Stripe uses a PaymentIntent object to represent your intent to collect payment from a customer, tracking charge attempts and payment state changes throughout the process.

Create a PaymentIntent on your server with an amount and currency. Always decide how much to charge on the server side, a trusted environment, as opposed to the client. This prevents malicious customers from being able to choose their own prices.

Terminal
# Verify your integration in this guide by including the metadata parameter curl https://api.stripe.com/v1/payment_intents \ -u
sk_test_4eC39HqLyjWDarjtT1zdp7dc
: \ -d "amount"=1099 \ -d "currency"="usd" \ -d "metadata[integration_check]"="accept_a_payment"

The returned PaymentIntent includes a client secret. The client side uses the client secret to securely complete the payment process instead of passing the entire PaymentIntent object. There are different approaches that you can use to pass the client secret to the client side.

You can retrieve the client secret from an endpoint on your server using the browser’s fetch function on the client side. This approach is generally most suitable when your client side is a single-page application, particularly one built with a modern frontend framework such as React. This example shows how to create the server endpoint that serves the client secret:

main.rb
get '/secret' do intent = # ... Create or retrieve the PaymentIntent {client_secret: intent.client_secret}.to_json end

This example demonstrates how to fetch the client secret with JavaScript on the client side:

var response = fetch('/secret').then(function(response) { return response.json(); }).then(function(responseJson) { var clientSecret = responseJson.client_secret; // Render the form to collect payment details, then // call stripe.confirmCardPayment() with the client secret. });

Collect card details
Client-side

You’re ready to collect card information on the client with Stripe Elements. Elements is a set of prebuilt UI components for collecting and validating card number, ZIP code, and expiration date.

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

Set up Stripe Elements

Stripe Elements 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. Do not include the script in a bundle or host a copy of it yourself.

checkout.html
<head> <title>Checkout</title> <script src="https://js.stripe.com/v3/"></script> </head>

Create an instance of Elements with the following JavaScript on your checkout page:

script.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 var stripe = Stripe(
'pk_test_TYooMQauvdEDq54NiTphI7jx'
); var elements = stripe.elements();

Add Elements to your payment page

Elements needs a place to live in your payment form. Create empty DOM nodes (containers) with unique IDs in your payment form and then pass those IDs to Elements.

checkout.html
View full sample
<form id="payment-form"> <div id="card-element"> <!-- Elements will create input elements here --> </div> <!-- We'll put the error messages in this element --> <div id="card-errors" role="alert"></div> <button id="submit">Submit Payment</button> </form>

When the form above has loaded, create an instance of an Element and mount it to the Element container:

client.js
View full sample
// Set up Stripe.js and Elements to use in checkout form var elements = stripe.elements(); var style = { base: { color: "#32325d", } }; var card = elements.create("card", { style: style }); card.mount("#card-element");

More examples

See additional payment forms created with Elements on GitHub.

The card Element simplifies the form and minimizes the number of required fields by inserting a single, flexible input field that securely collects all necessary card and billing details. Otherwise, combine cardNumber, cardExpiry, and cardCvc Elements for a flexible, multi-input card form.

Always collect a postal code to increase card acceptance rates and reduce fraud.

The single input card Element automatically collects and sends the customer’s postal code to Stripe. If you build your payment form with multi-input card Elements (cardNumber, cardExpiry, cardCvc), add a separate input field for the customer’s postal code.

For a full list of supported Element types, refer to our Stripe.js reference documentation.

Elements validates input as your customers type. To help your customers catch mistakes, listen to change events on the card Element and display any errors:

card.on('change', ({error}) => { let displayError = document.getElementById('card-errors'); if (error) { displayError.textContent = error.message; } else { displayError.textContent = ''; } });

Postal code validation depends on your customer’s billing country. Use our international test cards to experiment with other postal code formats.

Submit the payment to Stripe
Client-side

Rather than sending the entire PaymentIntent object to the client, use its client secret from step 2. After you create the PaymentIntent, the API returns a unique client secret for it (the client secret is different from the secret key you use to make Stripe API requests).

The client secret can complete a charge, so handle it with discretion. Don’t log it, embed it in URLs, or expose it to anyone but the customer.

To complete the payment when the user clicks, retrieve the client secret from the PaymentIntent you created in step 2 and call stripe.confirmCardPayment with the client secret.

Pass additional billing details, such as the cardholder name and address, to the billing_details hash. The card Element automatically sends the customer’s postal code information. However, combining cardNumber, cardCvc, and cardExpiry Elements requires you to pass the postal code to billing_details[address][postal_code].

client.js
View full sample
var form = document.getElementById('payment-form'); form.addEventListener('submit', function(ev) { ev.preventDefault(); // If the client secret was rendered server-side as a data-secret attribute // on the <form> element, you can retrieve it here by calling `form.dataset.secret` stripe.confirmCardPayment(clientSecret, { payment_method: { card: card, billing_details: { name: 'Jenny Rosen' } } }).then(function(result) { if (result.error) { // Show error to your customer (for example, insufficient funds) console.log(result.error.message); } else { // The payment has been processed! if (result.paymentIntent.status === 'succeeded') { // Show a success message to your customer // There's a risk of the customer closing the window before callback // execution. Set up a webhook or plugin to listen for the // payment_intent.succeeded event that handles any business critical // post-payment actions. } } }); });

stripe.confirmCardPayment may take several seconds to complete. During this time, disable resubmitting your form and show a waiting indicator like a spinner. If you receive an error, show it to the customer, re-enable the form, and hide the waiting indicator.

If the customer must authenticate the card, Stripe.js walks them through that process by showing them a modal. You can see an example of this modal experience by using the test card number 4000 0025 0000 3155 with any CVC, future expiration date, and postal code in the demo at the top of the page.

When the payment completes successfully, the value of the returned PaymentIntent’s status property is succeeded. Check the status of a PaymentIntent in the Dashboard or by inspecting the status property on the object. If the payment isn’t successful, inspect the returned error to determine the cause.

Test the integration

There are several test cards you can use in test mode to make sure this integration is ready. Use them with any CVC, postal code, and future expiration date.

NumberDescription
Succeeds and immediately processes the payment.
Always fails with a decline code of insufficient_funds.
Requires authentication, which in this integration will fail with a decline code of authentication_not_handled.

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

OptionalHandle post-payment events

See also

Congratulations, you’re done with your integration! Next, you can learn more about the Payment Intents API and Elements.

  • Learn about Payment Intents
  • Learn about Stripe Elements
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
Set up Stripe
Create a PaymentIntent
Collect card details
Submit the payment to Stripe
Test the integration
Handle post-payment events
Stripe Shell
Test mode
▗▄ ▄▟█ █▀▀ ▗▟████▙▖ ██████ ███▗▟█ ███ ███▗▟██▙▖ ▗▟█████▙▖ ███▖ ▀▀ ███ ███▀▀▀ ███ ███▀ ███ ███ ███ ▝▜████▙▖ ███ ███ ███ ███ ███ █████████ ▄▄ ▝███ ███ ▄ ███ ███ ███▄ ███ ███ ▄▄ ▝▜████▛▘ ▝▜███▛ ███ ███ ███▝▜██▛▘ ▝▜█████▛▘ ███ ▀▘
Welcome to the Stripe Shell! Stripe Shell is a browser-based shell with the Stripe CLI pre-installed. Login to Stripe docs and press Control + Backtick on your keyboard to start managing your Stripe resources in test mode. - View supported commands: - Find webhook events: - Listen for webhook events: - Call Stripe APIs: stripe [api resource] [operation] (e.g. )
The Stripe Shell is best experienced on desktop.
$