The Payment Intents API

    Learn more about the Payment Intents API that powers Stripe payments.

    Our Payment Intents API prepares your business for growth:

    • Automatic authentication handling
    • No double charges
    • No idempotency key issues
    • Support for Strong Customer Authentication (SCA) and similar regulatory changes

    The Charges API is available for standing up basic payments—without handling additional authentication—in the U.S. and Canada. We strongly recommend updating your integration to make scaling your business simpler in a world of evolving payments regulations.

    A complete set of APIs

    Use the Payment Intents API together with the Setup Intents and Payment Methods APIs.

    These new APIs help you handle dynamic payments (e.g., additional authentication like 3D Secure) and prepare you for expansion to other countries. As new regulations and regional payment methods come with different requirements, these APIs help you support them.

    Building an integration with the Payment Intents API involves two actions: creating and confirming a PaymentIntent. Each PaymentIntent typically correlates with a single shopping cart or customer session in your application. The PaymentIntent encapsulates details about the transaction, such as the supported payment methods, the amount to collect, and the desired currency.

    Creating a PaymentIntent

    Create the PaymentIntent on the server and pass its client secret to the client. The payment is confirmed on the client and the server monitors webhooks to detect when it completes successfully or fails.

    When you create the PaymentIntent, you can specify options like the amount and currency:

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d "payment_method_types[]=card"
    
    # 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',
        payment_method_types: ['card']
    })
    
    # 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'
    
    stripe.PaymentIntent.create(
      amount=1099,
      currency='usd',
      payment_method_types=['card']
    )
    
    // 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');
    
    \Stripe\PaymentIntent::create([
        'amount' => 1099,
        'currency' => 'usd',
        'payment_method_types' => ['card'],
    ]);
    
    // 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";
    
    Map<String, Object> paymentintentParams = new HashMap<String, Object>();
    paymentintentParams.put("amount", 1099);
    paymentintentParams.put("currency", "usd");
    ArrayList payment_method_types = new ArrayList();
    payment_method_types.add("card");
    paymentintentParams.put("payment_method_types", payment_method_types);
    
    PaymentIntent.create(paymentintentParams);
    
    // 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',
        payment_method_types: ['card'],
      });
    })();
    
    // 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)),
      PaymentMethodTypes: stripe.StringSlice([]string{
        "card",
      }),
    }
    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",
        PaymentMethodTypes = new List<string> { "card" },
    };
    var intent = service.Create(options);
    

    If you haven’t already, install the Client library for your favorite language now. As a convenience, if you’re logged in while reading this page, we’ve pre-filled the example with your test secret API key. Only you can see this value. This will authenticate you to Stripe, so keep it secret and keep it safe. Remember to replace the test key with your live key in production. You can get all your keys from the Dashboard.

    After creating a PaymentIntent, you can pass the PaymentIntent client secret to the client side and securely collect and tokenize your customer’s card using Elements or our iOS and Android SDKs.

    Best practices

    We recommend creating a PaymentIntent as soon as the amount is known, such as when the customer begins the checkout process, to help track your sales funnel. If the amount changes, you can update its amount. For example, if your customer backs out of the checkout process and adds new items to their cart, you may need to update the amount accordingly when they start the checkout process again.

    If the checkout process is interrupted and resumes later, you should attempt to reuse the same PaymentIntent instead of creating a new one. Each PaymentIntent has a unique ID that you can use to retrieve it if you need it again. In your application’s data model, you can store the PaymentIntent’s ID on the customer’s shopping cart or session in order to facilitate retrieval. The benefit of reusing the PaymentIntent is that the object helps track any failed payment attempts for a given cart or session.

    You should also provide an idempotency key—typically based on the ID that you associate with the cart or customer session in your application—when creating the PaymentIntent to avoid erroneously creating duplicate PaymentIntents for the same purchase.

    Passing the client secret to the client side

    The PaymentIntent contains a client secret, a key that is unique to the individual PaymentIntent. On the client side of your application, the client secret is used as a parameter when invoking Stripe.js functions (such as stripe.handleCardPayment or stripe.handleCardAction) to complete the payment.

    To use the client secret, you must obtain it from the PaymentIntent on your server and pass it the client side. There are different approaches that you can use to get the client secret to the client side–choose the approach that best suits the architecture of your application.

    Server-side rendering

    If your application uses server-side rendering, you may wish to use your template framework to embed the client secret in the HTML output of your checkout page during rendering. You can embed it in a data attribute or hidden HTML element and then extract it with JavaScript in order to use it to complete payment.

    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="<%= @intent.client_secret %>">Submit Payment</button>
    get '/checkout' do
        @intent = # ... Fetch or create the PaymentIntent
        erb :checkout
    end
    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="{{ client_secret }}">
      Submit Payment
    </button>
    @app.route('/checkout')
    def checkout():
      intent = # ... Fetch or create the PaymentIntent
      return render_template('checkout.html', client_secret=intent.client_secret)
    <?php
        $intent = # ... Fetch or create the PaymentIntent;
    ?>
    ...
    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="<?= $intent->client_secret ?>">
        Submit Payment
    </button>
    ...
    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="{{ client_secret }}">
      Submit Payment
    </button>
    import java.util.HashMap;
    import java.util.Map;
    
    import com.stripe.model.PaymentIntent;
    
    import spark.ModelAndView;
    
    import static spark.Spark.get;
    
    public class StripeJavaQuickStart {
        public static void main(String[] args) {
            get("/checkout", (request, response) -> {
              PaymentIntent intent = // ... Fetch or create the PaymentIntent
    
              Map map = new HashMap();
              map.put("client_secret", intent.getClientSecret());
    
              return new ModelAndView(map, "checkout.hbs");
            }, new HandlebarsTemplateEngine());
        }
    }
    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="{{ client_secret }}">
      Submit Payment
    </button>
    const express = require('express');
    const expressHandlebars = require('express-handlebars');
    const app = express();
    
    app.engine('.hbs', expressHandlebars({ extname: '.hbs' }));
    app.set('view engine', '.hbs');
    app.set('views', './views');
    
    app.get('/checkout', async (req, res) => {
      const intent = // ... Fetch or create the PaymentIntent
      res.render('checkout', { client_secret: intent.client_secret });
    });
    
    app.listen(3000, () => {
      console.log('Running on port 3000')
    });
    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="{{ .ClientSecret }}">
      Submit Payment
    </button>
    package main
    
    import (
      "html/template"
      "net/http"
    
      stripe "github.com/stripe/stripe-go"
    )
    
    type CheckoutData struct {
      ClientSecret string
    }
    
    func main() {
      checkoutTmpl := template.Must(template.ParseFiles("views/checkout.html"))
    
      http.HandleFunc("/checkout", func(w http.ResponseWriter, r *http.Request) {
        intent := // ... Fetch or create the PaymentIntent
        data := CheckoutData{
          ClientSecret: intent.ClientSecret,
        }
        checkoutTmpl.Execute(w, data)
      })
    
      http.ListenAndServe(":3000", nil)
    }
    <input id="card-name" type="text">
    <!-- placeholder for Elements -->
    <div id="card-element"></div>
    <button id="card-button" data-secret="@ViewData["ClientSecret"]">
      Submit Payment
    </button>
    using System;
    using Microsoft.AspNetCore.Mvc;
    using Stripe;
    
    namespace StripeExampleApi.Controllers
    {
        [Route("/[controller]")]
        public class CheckoutController : Controller
        {
            public IActionResult Index()
            {
              var intent = // ... Fetch or create the PaymentIntent
              ViewData["ClientSecret"] = intent.ClientSecret;
              return View();
            }
        }
    }

    Single-page application

    Alternately, 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 or Vue. This example shows how to create the server endpoint that serves the client secret:

    get '/secret' do
        intent = # ... Create or retrieve the PaymentIntent
        {client_secret: intent.client_secret}.to_json
    end
    from flask import jsonify
    
    @app.route('/secret')
    def secret():
      intent = # ... Create or retrieve the PaymentIntent
      return jsonify(client_secret=intent.client_secret)
    <?php
        $intent = # ... Create or retrieve the PaymentIntent
        echo json_encode(array('client_secret' => $intent->client_secret));
    ?>
    import java.util.HashMap;
    import java.util.Map;
    
    import com.stripe.model.PaymentIntent;
    
    import com.google.gson.Gson;
    
    import static spark.Spark.get;
    
    public class StripeJavaQuickStart {
        public static void main(String[] args) {
          Gson gson = new Gson();
    
          get("/secret", (request, response) -> {
            PaymentIntent intent = // ... Fetch or create the PaymentIntent
    
            Map<String, String> map = new HashMap();
            map.put("client_secret", intent.getClientSecret());
    
            return map;
          }, gson::toJson);
        }
    }
    const express = require('express');
    const app = express();
    
    app.get('/secret', async (req, res) => {
      const intent = // ... Fetch or create the PaymentIntent
      res.json({client_secret: intent.client_secret});
    });
    
    app.listen(3000, () => {
      console.log('Running on port 3000')
    });
    package main
    
    import (
      "encoding/json"
      "net/http"
    
      stripe "github.com/stripe/stripe-go"
    )
    
    type CheckoutData struct {
      ClientSecret string `json:"client_secret"`
    }
    
    func main() {
      http.HandleFunc("/secret", func(w http.ResponseWriter, r *http.Request) {
        intent := // ... Fetch or create the PaymentIntent
        data := CheckoutData{
          ClientSecret: intent.ClientSecret,
        }
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusOK)
        json.NewEncoder(w).Encode(data)
      })
    
      http.ListenAndServe(":3000", nil)
    }
    using System;
    using Microsoft.AspNetCore.Mvc;
    using Stripe;
    
    namespace StripeExampleApi.Controllers
    {
        [Route("secret")]
        [ApiController]
        public class CheckoutApiController : Controller
        {
            [HttpGet]
            public ActionResult Get()
            {
                var intent = // ... Fetch or create the PaymentIntent
                return Json(new {client_secret = intent.ClientSecret});
            }
        }
    }

    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;
      // Call stripe.handleCardPayment() with the client secret.
    });
    
    (async () => {
      const response = await fetch('/secret');
      const {client_secret: clientSecret} = await response.json();
      // Call stripe.handleCardPayment() with the client secret.
    })();
    

    Similarly for iOS and Android applications, you can fetch the client secret from the server.

    Optimizing future payments

    When you save a payment method to use again in the future, use the setup_future_usage parameter to optimize authorization rates. To determine which value to use, consider how you want to use this card in the future.

    How you intend to use the card setup_future_usage enum value to use
    On-session payments only on_session
    Off-session payments only off_session
    Both on and off-session payments off_session

    A card set up for on-session payments can still be used to make off-session payments, but there’s a higher likelihood that the bank will reject the off-session payment and require authentication from the cardholder.

    The following example shows how to create a PaymentIntent while also specifying setup_future_usage:

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d setup_future_usage=off_session
    
    # 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'
    
    Stripe::PaymentIntent.create(
      amount: 1099,
      currency: 'usd',
      setup_future_usage: 'off_session',
    )
    
    # 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'
    
    stripe.PaymentIntent.create(
      amount=1099,
      currency='usd',
      setup_future_usage='off_session',
    )
    
    // 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',
        'setup_future_usage' => 'off_session',
    ])
    
    // 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";
    
    Map<String, Object> params = new HashMap<>();
    params.put("amount", 1099);
    params.put("currency", "eur");
    params.put("setup_future_usage", "off_session");
    PaymentIntent paymentIntent = PaymentIntent.create(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
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    (async () => {
      const intent = await stripe.paymentIntents.create({
        amount: 1099,
        currency: 'usd',
        setup_future_usage: 'off_session',
      });
    })();
    
    // 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)),
      SetupFutureUsage: stripe.String(string(stripe.PaymentIntentSetupFutureUsageOffSession)),
    }
    intent, err := 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",
        SetupFutureUsage = "off_session",
    };
    PaymentIntent paymentIntent = service.Create(options);
    

    Dynamic statement descriptor

    By default, your Stripe account’s statement descriptor appears on customer statements whenever you charge their card. To provide a different description on a per-payment basis, include the statement_descriptor parameter.

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d "payment_method_types[]=card" \
      -d statement_descriptor="Custom descriptor"
    
    # 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',
        payment_method_types: ['card'],
        statement_descriptor: 'Custom descriptor',
    })
    
    # 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'
    
    stripe.PaymentIntent.create(
      amount=1099,
      currency='usd',
      payment_method_types=['card'],
      statement_descriptor='Custom descriptor',
    )
    
    // 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');
    
    \Stripe\PaymentIntent::create([
        'amount' => 1099,
        'currency' => 'usd',
        'payment_method_types' => ['card'],
        'statement_descriptor' => 'Custom descriptor',
    ]);
    
    // 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";
    
    Map<String, Object> paymentintentParams = new HashMap<String, Object>();
    paymentintentParams.put("amount", 1099);
    paymentintentParams.put("currency", "usd");
    ArrayList payment_method_types = new ArrayList();
    payment_method_types.add("card");
    paymentintentParams.put("payment_method_types", payment_method_types);
    paymentintentParams.put("statement_descriptor", "Custom descriptor");
    
    PaymentIntent.create(paymentintentParams);
    
    // 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',
        payment_method_types: ['card'],
        statement_descriptor: 'Custom descriptor',
      });
    })();
    
    // 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)),
      PaymentMethodTypes: stripe.StringSlice([]string{
        "card",
      }),
      StatementDescriptor: stripe.String("Custom descriptor"),
    }
    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",
        PaymentMethodTypes = new List<string> { "card" },
        StatementDescriptor = "Custom descriptor",
    };
    var intent = service.Create(options);
    

    Statement descriptors are limited to 22 characters, cannot use the special characters <, >, ', ", or *, and must not consist solely of numbers. When using dynamic statement descriptors, the dynamic text is appended to the statement descriptor prefix set in the Stripe Dashboard. An * and an empty space are also added to separate the default statement descriptor from the dynamic portion. These two characters count towards the 22 character limit.

    Placing a card on hold without charging

    Stripe supports two-step card payments so you can first authorize the card, then wait to capture funds later. When a payment is authorized, the funds are guaranteed by the card issuer and the amount is held on the customer’s card for up to seven days. If the payment is not captured within this time, the PaymentIntent and authorization are both canceled and funds are released.

    For in-person payments made with Terminal, the PaymentIntent must be captured within 24 hours.

    To indicate that you want separate authorization and capture, you must set the value of capture_method option to manual when creating the PaymentIntent. This instructs Stripe to only authorize the amount on the customer’s card.

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d "payment_method_types[]=card" \
      -d capture_method=manual
    
    # 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',
      payment_method_types: ['card'],
      capture_method: 'manual',
    })
    
    # 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'
    
    stripe.PaymentIntent.create(
      amount=1099,
      currency='usd',
      payment_method_types=['card'],
      capture_method='manual',
    )
    
    // 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');
    
    \Stripe\PaymentIntent::create([
      'amount' => 1099,
      'currency' => 'usd',
      'payment_method_types' => ['card'],
      'capture_method' => 'manual',
    ]);
    
    // 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";
    
    Map<String, Object> paymentintentParams = new HashMap<String, Object>();
    paymentintentParams.put("amount", 1099);
    paymentintentParams.put("currency", "usd");
    ArrayList payment_method_types = new ArrayList();
    payment_method_types.add("card");
    paymentintentParams.put("payment_method_types", payment_method_types);
    paymentintentParams.put("capture_method", "manual");
    
    PaymentIntent.create(paymentintentParams);
    
    // 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',
        payment_method_types: ['card'],
        capture_method: 'manual',
      });
    })();
    
    // 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)),
      PaymentMethodTypes: stripe.StringSlice([]string{
        "card",
      }),
      CaptureMethod: stripe.String("manual"),
    }
    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",
      PaymentMethodTypes = new List<string> { "card" },
      CaptureMethod = "manual",
    };
    var intent = service.Create(options);
    

    To capture the authorized funds, make a PaymentIntent capture request. The total authorized amount is captured by default, and you cannot capture more than this. To capture less than the initial amount (e.g., $7.50 of the $10.99 authorization), pass the amount_to_capture option. Partially capturing automatically releases the remaining amount.

    The following example demonstrates how to capture funds from an authorized payment:

    curl https://api.stripe.com/v1/payment_intents/pi_dY5L7K7E3ecrUItZlzrf/capture \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount_to_capture=750
    
    # 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.capture(
      'pi_dY5L7K7E3ecrUItZlzrf',
      {
        amount_to_capture: 750,
      }
    )
    
    # 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.capture(
      'pi_dY5L7K7E3ecrUItZlzrf',
      amount_to_capture=750
    )
    
    // 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::retrieve('pi_dY5L7K7E3ecrUItZlzrf');
    $intent->capture(['amount_to_capture' => 750]);
    
    // 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";
    
    PaymentIntent intent = PaymentIntent.retrieve("pi_dY5L7K7E3ecrUItZlzrf");
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("amount_to_capture", 750);
    intent.capture(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
    const stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    (async () => {
      await stripe.paymentIntents.capture('pi_dY5L7K7E3ecrUItZlzrf', {
        amount_to_capture: 750,
      })
    })();
    
    // 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.PaymentIntentCaptureParams{
      AmountToCapture: stripe.Int64(750),
    }
    intent, err := paymentintent.Capture("pi_dY5L7K7E3ecrUItZlzrf", 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 PaymentIntentCaptureOptions
    {
      AmountToCapture = 750,
    };
    var intent = service.Capture("pi_dY5L7K7E3ecrUItZlzrf", options);
    

    If you need to cancel an authorization, you can cancel the PaymentIntent.

    Card statements from some issuers do not distinguish between authorizations and captured (settled) payments, which can sometimes lead to confusion for your customers. In addition, authorized payments can only be captured once. If you partially capture a payment, you cannot perform another capture for the difference. Depending on your requirements, you may be better served by saving customer’s card details for later and creating future payments as needed.

    Additionally, when a customer completes the payment process on a PaymentIntent with manual capture, it triggers the payment_intent.amount_capturable_updated event. You can inspect the PaymentIntent’s amount_capturable property to see the total amount that can be captured from the PaymentIntent.

    Storing information in metadata

    Stripe supports adding metadata to the most common requests you make, such as processing payments. Metadata isn’t shown to customers or factored into whether or not a payment is declined or blocked by our fraud prevention system.

    Through metadata, you can associate other information—meaningful to you—with Stripe activity. Any metadata you include is viewable in the Dashboard (e.g., when looking at the page for an individual payment), and is also available in common reports. As an example, your store’s order ID can be attached to the PaymentIntent used to pay for that order. Doing so allows you, your accountant, or your finance team to easily reconcile payments in Stripe to orders in your system.

    If you are using Radar, consider passing any additional customer information and order information as metadata. By doing so, you can write Radar rules using metadata attributes and have more information about the payment available within the Dashboard which can expedite your review process.

    When a PaymentIntent creates a charge, the PaymentIntent copies its metadata to the charge. Subsequent updates to the PaymentIntent’s metadata will not modify the metadata of charges previously created by the PaymentIntent.

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d "payment_method_types[]=card" \
      -d "metadata[order_id]=6735"
    
    # 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',
        payment_method_types: ['card'],
        metadata: {'order_id' => 6735},
    })
    
    # 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'
    
    stripe.PaymentIntent.create(
      amount=1099,
      currency='usd',
      payment_method_types=['card'],
      metadata={'order_id': 6735},
    )
    
    // 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');
    
    \Stripe\PaymentIntent::create([
        'amount' => 1099,
        'currency' => 'usd',
        'payment_method_types' => ['card'],
        'metadata' => ['order_id' => 6735],
    ]);
    
    // 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";
    
    Map<String, Object> paymentintentParams = new HashMap<String, Object>();
    paymentintentParams.put("amount", 1099);
    paymentintentParams.put("currency", "usd");
    ArrayList payment_method_types = new ArrayList();
    payment_method_types.add("card");
    paymentintentParams.put("payment_method_types", payment_method_types);
    Map<String, String> metadata = new HashMap<>();
    metadata.put("order_id", 6735);
    paymentintentParams.put("metadata", metadata);
    PaymentIntent.create(paymentintentParams);
    
    // 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',
        payment_method_types: ['card'],
        metadata: {order_id: 6735},
      });
    })();
    
    // 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)),
      PaymentMethodTypes: stripe.StringSlice([]string{
        "card",
      }),
    }
    params.AddMetadata("order_id", 6735)
    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",
        PaymentMethodTypes = new List<string> { "card" },
        Metadata = new Dictionary<String, String>() {{"OrderId", "6735"}},
    };
    var intent = service.Create(options);
    

    Next steps

    Now that you know how to create a PaymentIntent, learn how to use the PaymentIntent to complete a payment:

    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