Accept a payment Payment Intents API

    Securely accept card payments online.

    Overview

    Collecting payments on your website consists of creating an object to track a payment, collecting card information, and submitting the payment to Stripe for processing.

    Stripe uses this payment object, called a PaymentIntent, to track and handle all the states of the payment—even when the bank requires customer intervention, like additional card authentication—until the payment completes.

    Try the demo to see what you can build from this guide, or skip to the steps below to get started.

    Demo

    1 Set up Stripe Server-side

    First, you need a Stripe account. Register now.

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

    Available as a gem:

    sudo gem install stripe

    If you use bundler, you can add this line:

    gem 'stripe'

    Available through pip:

    pip install --upgrade stripe

    Alternatively, you can also use easy_install:

    easy_install --upgrade stripe

    The PHP library can be installed via Composer:

    composer require stripe/stripe-php

    Alternatively, you can download the source directly.

    For Gradle, add the following dependency to your build.gradle:

    implementation "com.stripe:stripe-java:{VERSION}"
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    For Maven, add the following dependency to your POM:

    <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    In other environments, manually install the following JARs:

    Install via npm:

    npm install stripe

    Install via go:

    go get github.com/stripe/stripe-go

    Then import the package:

    import ( "github.com/stripe/stripe-go" )

    Install via dotnet:

    dotnet add package Stripe.net dotnet restore

    Or using NuGet:

    PM> Install-Package Stripe.net

    2 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.

    curl https://api.stripe.com/v1/payment_intents \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1099 \ -d currency=usd
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', })
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = stripe.PaymentIntent.create( amount=1099, currency='usd', )
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $intent = \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', ]);
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; import com.stripe.model.PaymentIntent; import com.stripe.param.PaymentIntentCreateParams; PaymentIntentCreateParams createParams = new PaymentIntentCreateParams.Builder() .setCurrency("usd").setAmount(new Long(1099)) .build(); PaymentIntent intent = PaymentIntent.create(createParams);
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); (async () => { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', }); })();
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), } paymentintent.New(params)
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", }; service.Create(options);

    Included in the returned PaymentIntent is a client secret, which you’ll use to securely complete the payment process instead of passing the entire PaymentIntent object. Send the client secret back to the client so you can use it in later steps.

    3 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.

    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.

    <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:

    // Set your publishable key: remember to change this to your live publishable key in production // See your keys here: https://dashboard.stripe.com/account/apikeys var stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx'); var elements = stripe.elements();

    Add Elements to your 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.

    <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">Pay</button>

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

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

    The card Element simplifies the form and minimizes the number of fields required by inserting a single, flexible input field that securely collects all necessary card details. For a full list of supported Element types, refer to our Stripe.js reference documentation.

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

    card.addEventListener('change', ({error}) => { const displayError = document.getElementById('card-errors'); if (error) { displayError.textContent = error.message; } else { displayError.textContent = ''; } });
    card.addEventListener('change', function(event) { var displayError = document.getElementById('card-errors'); if (event.error) { displayError.textContent = event.error.message; } else { displayError.textContent = ''; } });

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

    Install react-stripe-elements with npm, yarn, or UDM:

    npm install --save react-stripe-elements
    yarn add react-stripe-elements
    <!-- exports a global ReactStripeElements object --> <script src="https://unpkg.com/react-stripe-elements@latest/dist/react-stripe-elements.min.js"></script>

    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.

    <script src="https://js.stripe.com/v3/"></script> <link rel="stylesheet" href="MyCardElement.css">

    Now you can use individual *Element components, such as CardElement, to build your form.

    /** * Use the CSS tab above to style your Element's container. */ import React from 'react'; import {CardElement} from 'react-stripe-elements'; const style = { base: { color: "#32325d", fontFamily: '"Helvetica Neue", Helvetica, sans-serif', fontSmoothing: "antialiased", fontSize: "16px", "::placeholder": { color: "#aab7c4" } }, invalid: { color: "#fa755a", iconColor: "#fa755a" } }; const CardSection = () => { return ( <label> Card details <CardElement className=“MyCardElement” style={style} /> </label> ); }; export default CardSection;
    /** * Shows how you can use CSS to style your Element's container. */ .MyCardElement { height: 40px; padding: 10px 12px; width: 100%; color: #32325d; background-color: white; border: 1px solid transparent; border-radius: 4px; box-shadow: 0 1px 3px 0 #e6ebf1; -webkit-transition: box-shadow 150ms ease; transition: box-shadow 150ms ease; } .MyCardElement--focus { box-shadow: 0 1px 3px 0 #cfd7df; } .MyCardElement--invalid { border-color: #fa755a; } .MyCardElement--webkit-autofill { background-color: #fefde5 !important; }

    Elements are completely customizable. You can style Elements to match the look and feel of your site, providing a seamless checkout experience for your customers. It’s also possible to style various input states, for example when the Element has focus.

    Advanced integrations

    This guide outlines the most common integration, which makes the following assumptions:

    • The Stripe.js script is loaded before your application’s code
    • Your code is only run in a browser environment
    • You don’t need fine-tuned control over the Stripe instance that react-stripe-elements uses

    When all of these assumptions are true, you can pass the apiKey prop to <StripeProvider> and let react-stripe-elements handle the rest.

    When one or more of these assumptions doesn’t hold true for your integration, you can pass a Stripe instance as the stripe prop to <StripeProvider> directly. For these integrations, see our React docs on GitHub.

    Add Elements to your page

    For your application to access the Stripe object, add StripeProvider to your root React App component:

    import React from 'react'; import {render} from 'react-dom'; import {StripeProvider} from 'react-stripe-elements'; import MyStoreCheckout from './MyStoreCheckout'; const App = () => { return ( <StripeProvider apiKey="pk_test_TYooMQauvdEDq54NiTphI7jx" > <MyStoreCheckout /> </StripeProvider> ); }; render(<App />, document.getElementById('root'));

    Next, when you’re building components for your checkout form, you’ll want to wrap the Elements component around your form. This groups the set of Stripe Elements you’re using together, so that Stripe can pull data from groups of Elements when you’re tokenizing.

    import React from 'react'; import {Elements} from 'react-stripe-elements'; import InjectedCheckoutForm from './CheckoutForm'; class MyStoreCheckout extends React.Component { render() { return ( <Elements> <InjectedCheckoutForm /> </Elements> ); } } export default MyStoreCheckout;

    4 Submit the payment to Stripe Client-side

    Rather than sending the entire PaymentIntent object to the client, use its client secret from step 2. This is different from your API keys that authenticate Stripe API requests.

    The client secret should still be handled carefully because it can complete the charge. Do not log it, embed it in URLs, or expose it to anyone but the customer.

    To complete the payment when the user clicks, retreive the client secret from the PaymentIntent you created in step two and call stripe.confirmCardPayment:

    var submitButton = document.getElementById('submit'); submitButton.addEventListener('click', function(ev) { stripe.confirmCardPayment(clientSecret, { payment_method: {card: card} }).then(function(result) { if (result.error) { // Show error to your customer (e.g., 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. } } }); });

    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 is not successful, inspect the returned error to determine the cause.

    Use the injectStripe Higher-Order Component (HOC) to build your payment form components in the Elements tree. The Higher-Order Component pattern in React can be unfamiliar to those who’ve never seen it before, so consider reading up before continuing.

    The injectStripe HOC provides the this.props.stripe property that manages your Elements groups. Within an injected component, call any of the following:

    • this.props.stripe.createPaymentMethod
    • this.props.stripe.handleCardPayment

    This collects data from the appropriate Element and uses it to submit payment data to Stripe.

    Note that injectStripe cannot be used on the same element that renders the Elements component; it must be used on the child component of Elements. injectStripe returns a wrapped component that needs to sit under <Elements> but above any code where you’d like to access this.props.stripe.

    import React from 'react'; import {injectStripe} from 'react-stripe-elements'; import CardSection from './CardSection'; class CheckoutForm extends React.Component { handleSubmit = (ev) => { // We don't want to let default form submission happen here, which would refresh the page. ev.preventDefault(); // You can also use handleCardPayment with the PaymentIntents API. // See our handleCardPayment documentation for more: // https://stripe.com/docs/stripe-js/reference#stripe-handle-card-payment this.props.stripe.handleCardPayment('{PAYMENT_INTENT_CLIENT_SECRET}', {billing_details: {name: 'Jenny Rosen'}}); }; render() { return ( <form onSubmit={this.handleSubmit}> <CardSection /> <button>Confirm order</button> </form> ); } } export default injectStripe(CheckoutForm);

    5 Test the integration

    By this point you should have a basic card integration that collects card details and makes a payment.

    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.

    Number Description
    4242424242424242 Succeeds and immediately processes the payment.
    4000002500003155 Requires authentication. Stripe will trigger a modal asking for the customer to authenticate.
    4000000000009995 Always fails with a decline code of insufficient_funds.

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

    Optional Handle post-payment events

    Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like 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. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future, like direct debit.

    Receive events and run business actions

    Manually

    Use the Stripe Dashboard to view all your Stripe payments, send email receipts, handle payouts, or retry failed payments.

    Custom Code

    Build a webhook handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI.

    Prebuilt Apps

    Handle common business events, like shipping and inventory management, by integrating a partner application.

    See also

    Congrats, you are done with your integration! You can learn more about the Payment Intents API and Elements.

    Overview

    Collecting payments in your iOS app consists of creating an object to track a payment on your server, collecting card information in your app, and submitting the payment to Stripe for processing.

    Stripe uses this payment object, called a PaymentIntent, to track and handle all the states of the payment—even when the bank requires customer intervention, like additional card authentication—until the payment completes.

    1 Set up Stripe Client-side Server-side

    First, you need a Stripe account. Register now.

    Server-side

    This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server:

    Available as a gem:

    sudo gem install stripe

    If you use bundler, you can add this line:

    gem 'stripe'

    Available through pip:

    pip install --upgrade stripe

    Alternatively, you can also use easy_install:

    easy_install --upgrade stripe

    The PHP library can be installed via Composer:

    composer require stripe/stripe-php

    Alternatively, you can download the source directly.

    For Gradle, add the following dependency to your build.gradle:

    implementation "com.stripe:stripe-java:{VERSION}"
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    For Maven, add the following dependency to your POM:

    <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    In other environments, manually install the following JARs:

    Install via npm:

    npm install stripe

    Install via go:

    go get github.com/stripe/stripe-go

    Then import the package:

    import ( "github.com/stripe/stripe-go" )

    Install via dotnet:

    dotnet add package Stripe.net dotnet restore

    Or using NuGet:

    PM> Install-Package Stripe.net

    Client-side

    The iOS SDK is open source, fully documented, and compatible with apps supporting iOS 9 or above.

    1. If you haven't already, install the latest version of CocoaPods.
    2. If you don't have an existing Podfile, run the following command to create one:
      pod init
    3. Add this line to your Podfile:
      pod 'Stripe'
    4. Run the following command:
      pod install
    5. Don't forget to use the .xcworkspace file to open your project in Xcode, instead of the .xcodeproj file, from here on out.
    6. In the future, to update to the latest version of the SDK, just run:
      pod update Stripe
    1. If you haven't already, install the latest version of Carthage.
    2. Add this line to your Cartfile:
      github "stripe/stripe-ios"
    3. Follow the Carthage installation instructions.
    4. In the future, to update to the latest version of the SDK, run the following command:
      carthage update stripe-ios --platform ios
    1. Head to our GitHub releases page and download and unzip Stripe.framework.zip.
    2. Drag Stripe.framework to the "Embedded Binaries" section of your Xcode project's "General" settings. Make sure to select "Copy items if needed".
    3. Head to the "Build Phases" section of your Xcode project settings, and create a new "Run Script Build Phase". Paste the following snippet into the text field:
      bash "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Stripe.framework/integrate-dynamic-framework.sh"
    4. In the future, to update to the latest version of our SDK, just repeat steps 1 and 2.

    When your app starts, configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API.

    import UIKit import Stripe @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { Stripe.setDefaultPublishableKey("pk_test_TYooMQauvdEDq54NiTphI7jx") // do any other necessary launch configuration return true } }
    #import "AppDelegate.h" #import <Stripe/Stripe.h> @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [Stripe setDefaultPublishableKey:@"pk_test_TYooMQauvdEDq54NiTphI7jx"]; // do any other necessary launch configuration return YES; } @end

    2 Create your checkout page Client-side

    Securely collect card information on the client with STPPaymentCardTextField, a drop-in UI component provided by the SDK.

    STPPaymentCardTextField performs on-the-fly validation and formatting.

    Create an instance of the card component and a Pay button with the following code:

    import UIKit import Stripe class CheckoutViewController: UIViewController { lazy var cardTextField: STPPaymentCardTextField = { let cardTextField = STPPaymentCardTextField() return cardTextField }() lazy var payButton: UIButton = { let button = UIButton(type: .custom) button.layer.cornerRadius = 5 button.backgroundColor = .systemBlue button.titleLabel?.font = UIFont.systemFont(ofSize: 22) button.setTitle("Pay", for: .normal) button.addTarget(self, action: #selector(pay), for: .touchUpInside) return button }() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white let stackView = UIStackView(arrangedSubviews: [cardTextField, payButton]) stackView.axis = .vertical stackView.spacing = 20 stackView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(stackView) NSLayoutConstraint.activate([ stackView.leftAnchor.constraint(equalToSystemSpacingAfter: view.leftAnchor, multiplier: 2), view.rightAnchor.constraint(equalToSystemSpacingAfter: stackView.rightAnchor, multiplier: 2), stackView.topAnchor.constraint(equalToSystemSpacingBelow: view.topAnchor, multiplier: 2), ]) } @objc func pay() { // ... } }
    #import "CheckoutViewController.h" #import <Stripe/Stripe.h> @interface CheckoutViewController () @property (weak) STPPaymentCardTextField *cardTextField; @property (weak) UIButton *payButton; @end @implementation CheckoutViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; STPPaymentCardTextField *cardTextField = [[STPPaymentCardTextField alloc] init]; self.cardTextField = cardTextField; UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.layer.cornerRadius = 5; button.backgroundColor = [UIColor systemBlueColor]; button.titleLabel.font = [UIFont systemFontOfSize:22]; [button setTitle:@"Pay" forState:UIControlStateNormal]; [button addTarget:self action:@selector(pay) forControlEvents:UIControlEventTouchUpInside]; self.payButton = button; UIStackView *stackView = [[UIStackView alloc] initWithArrangedSubviews:@[cardTextField, button]]; stackView.axis = UILayoutConstraintAxisVertical; stackView.translatesAutoresizingMaskIntoConstraints = NO; stackView.spacing = 20; [self.view addSubview:stackView]; [NSLayoutConstraint activateConstraints:@[ [stackView.leftAnchor constraintEqualToSystemSpacingAfterAnchor:self.view.leftAnchor multiplier:2], [self.view.rightAnchor constraintEqualToSystemSpacingAfterAnchor:stackView.rightAnchor multiplier:2], [stackView.topAnchor constraintEqualToSystemSpacingBelowAnchor:self.view.topAnchor multiplier:2], ]]; } - (void)pay { // ... } @end

    Run your app, and make sure your checkout page shows the card component and pay button.

    3 Create a PaymentIntent Client-side Server-side

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

    Server-side

    On your server, make an endpoint that creates a PaymentIntent 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.

    curl https://api.stripe.com/v1/payment_intents \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1099 \ -d currency=usd
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', }) client_secret = payment_intent['client_secret'] # Pass the client secret to the client
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = stripe.PaymentIntent.create( amount=1099, currency='usd', ) client_secret = intent.client_secret # Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $intent = \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', ]); $client_secret = $intent->client_secret // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; import com.stripe.model.PaymentIntent; import com.stripe.param.PaymentIntentCreateParams; PaymentIntentCreateParams createParams = new PaymentIntentCreateParams.Builder() .setCurrency("usd").setAmount(new Long(1099)) .build(); PaymentIntent intent = PaymentIntent.create(createParams); String clientSecret = intent.getClientSecret(); // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); (async () => { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', }); const clientSecret = paymentIntent.client_secret // Pass the client secret to the client })();
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), } paymentintent.New(params) // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", }; service.Create(options); // Pass the client secret to the client

    Instead of passing the entire PaymentIntent object to your app, just return its client secret. The PaymentIntent’s client secret is a unique key that lets you confirm the payment and update card details on the client, without allowing manipulation of sensitive information, like payment amount.

    Client-side

    On the client, request a PaymentIntent from your server and store its client secret.

    class CheckoutViewController: UIViewController { var paymentIntentClientSecret: String? // ...continued from previous step override func viewDidLoad() { // ...continued from previous step startCheckout() } func startCheckout() { // Request a PaymentIntent from your server and store its client secret // Click Open on GitHub to see a full implementation } }
    @interface CheckoutViewController () // ...continued from previous step @property (strong) NSString *paymentIntentClientSecret; @end @implementation CheckoutViewController - (void)viewDidLoad { [super viewDidLoad]; // ...continued from previous step [self startCheckout]; } - (void)startCheckout { // Request a PaymentIntent from your server and store its client secret // Click Open on GitHub to see a full implementation } @end

    4 Submit the payment to Stripe Client-side

    When the customer taps the Pay button, confirm the PaymentIntent to complete the payment.

    First, assemble a STPPaymentIntentParams object with:

    1. The card text field’s payment method details
    2. The PaymentIntent client secret from your server

    Rather than sending the entire PaymentIntent object to the client, use its client secret. This is different from your API keys that authenticate Stripe API requests. The client secret is a string that lets your app access important fields from the PaymentIntent (e.g., status) while hiding sensitive ones (e.g., customer).

    The client secret should still be handled carefully because it can complete the charge. Do not log it, embed it in URLs, or expose it to anyone but the customer.

    Next, complete the payment by calling the STPPaymentHandler confirmPayment method.

    class CheckoutViewController: UIViewController { // ... @objc func pay() { guard let paymentIntentClientSecret = paymentIntentClientSecret else { return; } // Collect card details let cardParams = cardTextField.cardParams let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: nil, metadata: nil) let paymentIntentParams = STPPaymentIntentParams(clientSecret: paymentIntentClientSecret) paymentIntentParams.paymentMethodParams = paymentMethodParams // Submit the payment let paymentHandler = STPPaymentHandler.shared() paymentHandler.confirmPayment(withParams: paymentIntentParams, authenticationContext: self) { (status, paymentIntent, error) in switch (status) { case .failed: self.displayAlert(title: "Payment failed", message: error?.localizedDescription ?? "") break case .canceled: self.displayAlert(title: "Payment canceled", message: error?.localizedDescription ?? "") break case .succeeded: self.displayAlert(title: "Payment succeeded", message: paymentIntent?.description ?? "", restartDemo: true) break @unknown default: fatalError() break } } } } extension CheckoutViewController: STPAuthenticationContext { func authenticationPresentingViewController() -> UIViewController { return self } }
    @interface CheckoutViewController () <STPAuthenticationContext> // ... @end @implementation CheckoutViewController // ... - (void)pay { if (!self.paymentIntentClientSecret) { NSLog(@"PaymentIntent hasn't been created"); return; } // Collect card details STPPaymentMethodCardParams *cardParams = self.cardTextField.cardParams; STPPaymentMethodParams *paymentMethodParams = [STPPaymentMethodParams paramsWithCard:cardParams billingDetails:nil metadata:nil]; STPPaymentIntentParams *paymentIntentParams = [[STPPaymentIntentParams alloc] initWithClientSecret:self.paymentIntentClientSecret]; paymentIntentParams.paymentMethodParams = paymentMethodParams; // Submit the payment STPPaymentHandler *paymentHandler = [STPPaymentHandler sharedHandler]; [paymentHandler confirmPayment:paymentIntentParams withAuthenticationContext:self completion:^(STPPaymentHandlerActionStatus status, STPPaymentIntent *paymentIntent, NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ switch (status) { case STPPaymentHandlerActionStatusFailed: { [self displayAlertWithTitle:@"Payment failed" message:error.localizedDescription ?: @"" restartDemo:NO]; break; } case STPPaymentHandlerActionStatusCanceled: { [self displayAlertWithTitle:@"Payment canceled" message:error.localizedDescription ?: @"" restartDemo:NO]; break; } case STPPaymentHandlerActionStatusSucceeded: { [self displayAlertWithTitle:@"Payment succeeded" message:paymentIntent.description ?: @"" restartDemo:YES]; break; } default: break; } }); }]; } # pragma mark STPAuthenticationContext - (UIViewController *)authenticationPresentingViewController { return self; } @end

    If authentication is required by regulation such as Strong Customer Authentication, STPPaymentHandler presents view controllers using the STPAuthenticationContext passed in and walks the customer through that process. See Supporting 3D Secure Authentication on iOS to learn more.

    If the payment succeeds, the completion handler is called with a status of .succeeded. If it fails, the status is .failed and you can display the error.localizedDescription to the user.

    You can also check the status of a PaymentIntent in the Dashboard or by inspecting the status property on the object.

    5 Test the integration

    By this point you should have a basic card integration that collects card details and makes a payment.

    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.

    Number Description
    4242424242424242 Succeeds and immediately processes the payment.
    4000002500003155 Requires authentication. Stripe will trigger a modal asking for the customer to authenticate.
    4000000000009995 Always fails with a decline code of insufficient_funds.

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

    Optional Handle post-payment events

    Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like 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. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future, like direct debit.

    Receive events and run business actions

    Manually

    Use the Stripe Dashboard to view all your Stripe payments, send email receipts, handle payouts, or retry failed payments.

    Custom Code

    Build a webhook handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI.

    Prebuilt Apps

    Handle common business events, like shipping and inventory management, by integrating a partner application.

    See also

    Overview

    Collecting payments in your Android app consists of creating an object to track a payment on your server, collecting card information in your app, and submitting the payment to Stripe for processing.

    Stripe uses this payment object, called a PaymentIntent, to track and handle all the states of the payment—even when the bank requires customer intervention, like additional card authentication—until the payment completes.

    1 Set up Stripe Client-side Server-side

    First, you need a Stripe account. Register now.

    Server-side

    This integration requires endpoints on your server that talk to the Stripe API. Use our official libraries for access to the Stripe API from your server:

    Available as a gem:

    sudo gem install stripe

    If you use bundler, you can add this line:

    gem 'stripe'

    Available through pip:

    pip install --upgrade stripe

    Alternatively, you can also use easy_install:

    easy_install --upgrade stripe

    The PHP library can be installed via Composer:

    composer require stripe/stripe-php

    Alternatively, you can download the source directly.

    For Gradle, add the following dependency to your build.gradle:

    implementation "com.stripe:stripe-java:{VERSION}"
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    For Maven, add the following dependency to your POM:

    <dependency> <groupId>com.stripe</groupId> <artifactId>stripe-java</artifactId> <version>{VERSION}</version> </dependency>
    (Replace {VERSION} with the actual version number you want to use. You can find the most recent version on Maven Repository or GitHub.)

    In other environments, manually install the following JARs:

    Install via npm:

    npm install stripe

    Install via go:

    go get github.com/stripe/stripe-go

    Then import the package:

    import ( "github.com/stripe/stripe-go" )

    Install via dotnet:

    dotnet add package Stripe.net dotnet restore

    Or using NuGet:

    PM> Install-Package Stripe.net

    Client-side

    The Android SDK is open source and fully documented.

    To install the SDK, add stripe-android to the dependencies block of your app/build.gradle file:

    apply plugin: 'com.android.application' android { ... } dependencies { // ... // Stripe Android SDK implementation 'com.stripe:stripe-android:12.6.0' }

    Configure the SDK with your Stripe publishable key so that it can make requests to the Stripe API, such as in your Application subclass:

    import com.stripe.android.PaymentConfiguration class MyApp: Application() { override fun onCreate() { super.onCreate() PaymentConfiguration.init(applicationContext, "pk_test_TYooMQauvdEDq54NiTphI7jx") } }
    import com.stripe.android.PaymentConfiguration; public class MyApp extends Application { @Override public void onCreate() { super.onCreate(); PaymentConfiguration.init(getApplicationContext(), "pk_test_TYooMQauvdEDq54NiTphI7jx"); } }

    Our code samples also use OkHttp and GSON to make HTTP requests to a server.

    2 Create your checkout page Client-side

    Securely collect card information on the client with CardInputWidget, a drop-in UI component provided by the SDK.

    CardInputWidget performs on-the-fly validation and formatting.

    Create an instance of the card component and a Pay button by adding the following to your checkout page’s layout:

    <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_checkout" tools:context=".CheckoutActivity"> <!-- ... --> <com.stripe.android.view.CardInputWidget android:id="@+id/cardInputWidget" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="20dp"/> <Button android:text="Pay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/payButton" android:layout_marginTop="20dp" app:layout_constraintTop_toBottomOf="@+id/cardInputWidget" app:layout_constraintStart_toStartOf="@+id/cardInputWidget" app:layout_constraintEnd_toEndOf="@+id/cardInputWidget"/> <!-- ... --> </androidx.constraintlayout.widget.ConstraintLayout>

    Run your app, and make sure your checkout page shows the card component and pay button.

    3 Create a PaymentIntent Client-side Server-side

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

    Server-side

    On your server, make an endpoint that creates a PaymentIntent 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.

    curl https://api.stripe.com/v1/payment_intents \ -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \ -d amount=1099 \ -d currency=usd
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = Stripe::PaymentIntent.create({ amount: 1099, currency: 'usd', }) client_secret = payment_intent['client_secret'] # Pass the client secret to the client
    # Set your secret key: remember to change this to your live secret key in production # See your keys here: https://dashboard.stripe.com/account/apikeys stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc' intent = stripe.PaymentIntent.create( amount=1099, currency='usd', ) client_secret = intent.client_secret # Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys \Stripe\Stripe::setApiKey('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); $intent = \Stripe\PaymentIntent::create([ 'amount' => 1099, 'currency' => 'usd', ]); $client_secret = $intent->client_secret // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys Stripe.apiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; import com.stripe.model.PaymentIntent; import com.stripe.param.PaymentIntentCreateParams; PaymentIntentCreateParams createParams = new PaymentIntentCreateParams.Builder() .setCurrency("usd").setAmount(new Long(1099)) .build(); PaymentIntent intent = PaymentIntent.create(createParams); String clientSecret = intent.getClientSecret(); // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc'); (async () => { const paymentIntent = await stripe.paymentIntents.create({ amount: 1099, currency: 'usd', }); const clientSecret = paymentIntent.client_secret // Pass the client secret to the client })();
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc" params := &stripe.PaymentIntentParams{ Amount: stripe.Int64(1099), Currency: stripe.String(string(stripe.CurrencyUSD)), } paymentintent.New(params) // Pass the client secret to the client
    // Set your secret key: remember to change this to your live secret key in production // See your keys here: https://dashboard.stripe.com/account/apikeys StripeConfiguration.ApiKey = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"; var service = new PaymentIntentService(); var options = new PaymentIntentCreateOptions { Amount = 1099, Currency = "usd", }; service.Create(options); // Pass the client secret to the client

    Instead of passing the entire PaymentIntent object to your app, just return its client secret. The PaymentIntent’s client secret is a unique key that lets you confirm the payment and update card details on the client, without allowing manipulation of sensitive information, like payment amount.

    Client-side

    On the client, request a PaymentIntent from your server and store its client secret.

    class CheckoutActivity : AppCompatActivity() { private lateinit var paymentIntentClientSecret: String override fun onCreate(savedInstanceState: Bundle?) { // ... startCheckout() } private fun startCheckout() { // Request a PaymentIntent from your server and store its client secret in paymentIntentClientSecret // Click Open on GitHub to see a full implementation } }
    public class CheckoutActivity extends AppCompatActivity { private String paymentIntentClientSecret; @Override public void onCreate(Bundle savedInstanceState) { // ... startCheckout(); } private void startCheckout() { // Request a PaymentIntent from your server and store its client secret in paymentIntentClientSecret // Click Open on GitHub to see a full implementation } }

    4 Submit the payment to Stripe Client-side

    When the customer taps the Pay button, confirm the PaymentIntent to complete the payment.

    First, assemble a ConfirmPaymentIntentParams object with:

    1. The card component’s payment method details
    2. The PaymentIntent client secret from your server

    Rather than sending the entire PaymentIntent object to the client, use its client secret. This is different from your API keys that authenticate Stripe API requests. The client secret is a string that lets your app access important fields from the PaymentIntent (e.g., status) while hiding sensitive ones (e.g., customer).

    The client secret should still be handled carefully because it can complete the charge. Do not log it, embed it in URLs, or expose it to anyone but the customer.

    Next, complete the payment by calling the stripe confirmPayment method.

    class CheckoutActivity : AppCompatActivity() { // ... private lateinit var paymentIntentClientSecret: String private lateinit var stripe: Stripe private fun startCheckout() { // ... // Hook up the pay button to the card widget and stripe instance val payButton: Button = findViewById(R.id.payButton) payButton.setOnClickListener { val params = cardInputWidget.paymentMethodCreateParams if (params != null) { val confirmParams = ConfirmPaymentIntentParams .createWithPaymentMethodCreateParams(params, paymentIntentClientSecret) stripe = Stripe(applicationContext, PaymentConfiguration.getInstance(applicationContext).publishableKey) stripe.confirmPayment(this, confirmParams) } } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) val weakActivity = WeakReference<Activity>(this) // Handle the result of stripe.confirmPayment stripe.onPaymentResult(requestCode, data, object : ApiResultCallback<PaymentIntentResult> { override fun onSuccess(result: PaymentIntentResult) { val paymentIntent = result.intent val status = paymentIntent.status if (status == StripeIntent.Status.Succeeded) { val gson = GsonBuilder().setPrettyPrinting().create() displayAlert(weakActivity.get(), "Payment succeeded", gson.toJson(paymentIntent), restartDemo = true) } else { displayAlert(weakActivity.get(), "Payment failed", paymentIntent.lastPaymentError?.message ?: "") } } override fun onError(e: Exception) { displayAlert(weakActivity.get(), "Payment failed", e.toString()) } }) }
    public class CheckoutActivity extends AppCompatActivity { // ... private String paymentIntentClientSecret; private Stripe stripe private void startCheckout() { // ... // Hook up the pay button to the card widget and stripe instance Button payButton = findViewById(R.id.payButton); payButton.setOnClickListener((View view) -> { PaymentMethodCreateParams params = cardInputWidget.getPaymentMethodCreateParams(); if (params != null) { ConfirmPaymentIntentParams confirmParams = ConfirmPaymentIntentParams .createWithPaymentMethodCreateParams(params, paymentIntentClientSecret); stripe = Stripe(applicationContext, PaymentConfiguration.getInstance(applicationContext).publishableKey; stripe.confirmPayment(this, confirmParams); } }); } // ... @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Handle the result of stripe.confirmPayment stripe.onPaymentResult(requestCode, data, new PaymentResultCallback(this)); } // ... private static final class PaymentResultCallback implements ApiResultCallback<PaymentIntentResult> { @NonNull private final WeakReference<CheckoutActivity> activityRef; PaymentResultCallback(@NonNull CheckoutActivity activity) { activityRef = new WeakReference<>(activity); } @Override public void onSuccess(@NonNull PaymentIntentResult result) { final CheckoutActivity activity = activityRef.get(); if (activity == null) { return; } PaymentIntent paymentIntent = result.getIntent(); PaymentIntent.Status status = paymentIntent.getStatus(); if (status == PaymentIntent.Status.Succeeded) { // Payment completed successfully Gson gson = new GsonBuilder().setPrettyPrinting().create(); activity.displayAlert( "Payment completed", gson.toJson(paymentIntent), true ); } else if (status == PaymentIntent.Status.RequiresPaymentMethod) { // Payment failed activity.displayAlert( "Payment failed", Objects.requireNonNull(paymentIntent.getLastPaymentError()).message, false ); } } @Override public void onError(@NonNull Exception e) { final CheckoutActivity activity = activityRef.get(); if (activity == null) { return; } // Payment request failed – allow retrying using the same payment method activity.displayAlert("Error", e.toString(), false); } } }

    If authentication is required by regulation such as Strong Customer Authentication, the SDK presents additional activities and walks the customer through that process. See Supporting 3D Secure Authentication on Android to learn more.

    When the payment completes, onSuccess is called and the value of the returned PaymentIntent’s status is Succeeded. Any other value indicates the payment was not successful. Inspect lastPaymentError to determine the cause.

    You can also check the status of a PaymentIntent in the Dashboard or by inspecting the status property on the object.

    5 Test the integration

    By this point you should have a basic card integration that collects card details and makes a payment.

    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.

    Number Description
    4242424242424242 Succeeds and immediately processes the payment.
    4000002500003155 Requires authentication. Stripe will trigger a modal asking for the customer to authenticate.
    4000000000009995 Always fails with a decline code of insufficient_funds.

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

    Optional Handle post-payment events

    Stripe sends a payment_intent.succeeded event when the payment completes. Use the Dashboard, a custom webhook, or a partner solution to receive these events and run actions, like 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. Setting up your integration to listen for asynchronous events also makes it easier to accept more payment methods in the future, like direct debit.

    Receive events and run business actions

    Manually

    Use the Stripe Dashboard to view all your Stripe payments, send email receipts, handle payouts, or retry failed payments.

    Custom Code

    Build a webhook handler to listen for events and build custom asynchronous payment flows. Test and debug your webhook integration locally with the Stripe CLI.

    Prebuilt Apps

    Handle common business events, like shipping and inventory management, by integrating a partner application.

    See also

    Overview

    Collect Stripe payments in whichever publishing or e-commerce platform you use, with a Stripe plugin created by our partners. The Stripe developer community uses Stripe’s APIs to create plugins and extensions.

    If you use a third-party platform to build and maintain a website, you can add Stripe payments with a plugin.

    Get started

    Try one of our recommended solutions for your platform:

    • Magento: E-commerce platform creating distinct digital retail experiences
    • WordPress: Website creation tool and content management system
    • Drupal: Open-source content management system
    • Joomla: Open-source content management system

    Don’t see your platform? Check out our full list of partners for a solution to your use case.

    Was this page helpful?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page