PaymentIntents Usage Guide

    Learn how to use all of the features of PaymentIntents.

    A Stripe integration built with PaymentIntents typically follows these four steps:

    1. Create a new PaymentIntent on your server when the customer begins the checkout process.
    2. Make the PaymentIntent’s client secret available on the the client side.
    3. Use Stripe.js on the client side to collect payment information, initiate the charge, and handle required source actions.
    4. Use webhooks to monitor and handle the success or failure of the charge as needed.

    When using PaymentIntents, charge creation is initiated on the client side and takes place on Stripe’s servers. In a sense, the process is asynchronous–you don’t immediately receive a response on your server that indicates success or failure. As such, you should rely on webhooks to determine when you should fulfill the goods and services purchased by the customer.

    The approach required by PaymentIntents is an inversion of the more traditional Stripe model, where you use Stripe.js to tokenize the customer’s payment information on the client side and then send it to your server to create the charge. For more details about how PaymentIntents differ from direct charge creation, please refer to the migration guide.

    For step-by-step instructions that demonstrate how to build a complete Stripe integration with PaymentIntents, refer to the payments quickstart.

    Completing payment on the client side

    PaymentIntents integrate with Stripe.js, using Elements to securely collect payment information on the client side. To complete a purchase, retrieve the PaymentIntent’s client secret and pass it to the stripe.handleCardPayment function in Stripe.js:

    var stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx', {
      betas: ['payment_intent_beta_3']
    });
    
    stripe.handleCardPayment(clientSecret, cardElement).then(function(result) {
      if (result.error) {
        // Display error.message in your UI.
      } else {
        // The payment has succeeded. Display a success message.
      }
    });
    const stripe = Stripe('pk_test_TYooMQauvdEDq54NiTphI7jx', {
      betas: ['payment_intent_beta_3']
    });
    
    (async () => {
      const {paymentIntent, error} = await stripe.handleCardPayment(clientSecret, cardElement);
      if (error) {
        // Display error.message in your UI.
      } else {
        // The payment has succeeded. Display a success message.
      }
    })();

    When you call the function, it collects the customer’s payment information from the desired element and securely transmits it to Stripe to complete the transaction. If it completes successfully, the result object’s error property is null.

    Some payment methods require additional steps, such as authentication. When you use one of the handle functions in Stripe.js to complete the payment, it automatically ushers the customer through the necessary source actions. It also confirms the PaymentIntent for you.

    Handling source actions

    If you choose to handle source actions yourself instead of using a Stripe.js function like handleCardPayment, that handles them for you, inspect the PaymentIntent’s next_action property to determine what steps are necessary. The type of possible source actions can differ between various payment methods. The following is a list of source action types and the payment methods that may require them:

    Type Payment Methods What it means How to handle
    redirect_to_url Cards with 3DS The customer needs to be sent to the provided URL to authenticate the payment. top.location = sourceAction.redirect_to_url.url

    You can refer to the documentation for individual payment methods for more details about how to handle their required source actions.

    Monitoring a PaymentIntent with webhooks

    Stripe can send webhook events to your server to notify you when the status of a PaymentIntent changes. This is useful for purposes like determining when to fulfill the goods and services purchased by the customer. Your customers can leave your website while the payment is still processing, so we strongly recommend using webhooks to monitor the payment_intent.succeeded event instead of attempting to initiate fulfillment on the client side.

    To handle a webhook event, create a route on your server and configure a corresponding webhook endpoint in the Dashboard. Stripe sends the payment_intent.succeeded event when payment is successful and the payment_intent.payment_failed event when payment isn’t successful. The webhook payload includes the PaymentIntent object. The following example shows how to handle both events:

    require 'sinatra'
    require 'stripe'
    
    post '/webhook' do
      payload = request.body.read
      sig_header = request.env['HTTP_STRIPE_SIGNATURE']
      event = nil
    
      begin
          event = Stripe::Webhook.construct_event(
              payload, sig_header, endpoint_secret
          )
      rescue JSON::ParserError => e
          # Invalid payload
          status 400
          return
      rescue Stripe::SignatureVerificationError => e
          # Invalid signature
          status 400
          return
      end
    
      case event['type']
      when 'payment_intent.succeeded'
        intent = event['data']['object']
        puts "Succeeded:", intent['id']
        # Fulfill the customer's purchase
      when 'payment_intent.payment_failed'
        intent = event['data']['object']
        error_message = intent['last_payment_error'] && intent['last_payment_error']['message']
        puts "Failed:", intent['id'], error_message
        # Notify the customer that payment failed
      end
    
      status 200
    end
    
    # You can find your endpoint's secret in your webhook settings
    endpoint_secret = 'whsec_...'
    
    @app.route("/webhook", methods=['POST'])
    def webhook():
      payload = request.get_data()
      sig_header = request.headers.get('STRIPE_SIGNATURE')
      event = None
    
      try:
        event = stripe.Webhook.construct_event(
          payload, sig_header, endpoint_secret
        )
      except ValueError as e:
        # invalid payload
        return "Invalid payload", 400
      except stripe.error.SignatureVerificationError as e:
        # invalid signature
        return "Invalid signature", 400
    
      event_dict = event.to_dict()
      if event_dict['type'] == "payment_intent.succeeded":
        intent = event_dict['data']['object']
        print "Suceeded: ", intent['id']
        # Fulfill the customer's purchase
      elif event_dict['type'] == "payment_intent.payment_failed":
        intent = event_dict['data']['object']
        error_message = intent['last_payment_error']['message'] if intent.get('last_payment_error') else None
        print "Failed: ", intent['id'], error_message
        # Notify the customer that payment failed
    
      return "OK", 200
    
    // You can find your endpoint's secret in your webhook settings
    $endpoint_secret = 'whsec_...';
    
    $payload = @file_get_contents('php://input');
    $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
    $event = null;
    
    try {
      $event = \\Stripe\\Webhook::constructEvent(
        $payload, $sig_header, $endpoint_secret
      );
    } catch(\\UnexpectedValueException $e) {
      // Invalid payload
      http_response_code(400); // PHP 5.4 or greater
      exit();
    } catch(\\Stripe\\Error\\SignatureVerification $e) {
      // Invalid signature
      http_response_code(400); // PHP 5.4 or greater
      exit();
    }
    
    if ($event->type == "payment_intent.succeeded") {
      $intent = $event->data->object;
      printf("Succeeded: %s", $intent->id);
      http_response_code(200);
      exit();
    } elseif ($event->type == "payment_intent.payment_failed") {
      $intent = $event->data->object;
      $error_message = $intent->last_payment_error ? $intent->last_payment_error->message : "";
      printf("Failed: %s, %s", $intent->id, $error_message);
      http_response_code(200);
      exit();
    }
    
    import com.stripe.model.PaymentIntent;
    import com.stripe.model.Event;
    import com.stripe.net.Webhook;
    
    import static spark.Spark.post;
    
    public class StripeJavaQuickStart {
        public static void main(String[] args) {
          String endpointSecret = "whsec_...";
    
          post("/webhook", (request, response) -> {
            String payload = request.body();
            String sigHeader = request.headers("Stripe-Signature");
            Event event = null;
    
            try {
              event = Webhook.constructEvent(
                payload, sigHeader, endpointSecret
              );
            } catch (JsonSyntaxException e) {
              // Invalid payload
              response.status(400);
              return "Invalid payload";
            } catch (SignatureVerificationException e) {
              // Invalid signature
              response.status(400);
              return "Invalid signature";
            }
    
            PaymentIntent intent = null;
            switch(event.getType()) {
              case "payment_intent.succeeded":
                intent = (PaymentIntent) event.getData().getObject();
                System.out.println("Succeeded: " + intent.getId());
                break;
                // Fulfil the customer's purchase
    
              case "payment_intent.payment_failed":
                intent = (PaymentIntent) event.getData().getObject();
                System.out.println("Failed: " + intent.getId());
                break;
                // Notify the customer that payment failed
    
              default:
                // Handle other event types
                break;
            }
    
            response.status(200);
            return "OK";
          });
        }
    }
    
    app.use(require('body-parser').text({type: '*/*'}));
    
    const endpointSecret = "whsec_...";
    
    app.post('/webhook', function(request, response) {
      const sig = request.headers["stripe-signature"];
      const body = request.body;
    
      let event = null;
    
      try {
        event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
      }
      catch (err) {
        // invalid signature
        response.status(400).end();
        return;
      }
    
      let intent = null;
      switch (event['type']) {
        case 'payment_intent.succeeded':
          intent = event.data.object;
          console.log("Succeeded:", intent.id);
          break;
        case 'payment_intent.payment_failed':
          intent = event.data.object;
          const message = intent.last_payment_error && intent.last_payment_error.message;
          console.log("Failed:", intent.id, message);
          break;
      }
    
      response.sendStatus(200);
    });
    
    package main
    
    import (
      "encoding/json"
      "net/http"
    
      stripe "github.com/stripe/stripe-go"
      webhook "github.com/stripe/stripe-go/webhook"
    )
    
    func main() {
      http.HandleFunc("/webhook", func(w http.ResponseWriter, req *http.Request) {
        body, err := ioutil.ReadAll(req.Body)
        if err != nil {
          fmt.Fprintf(os.Stderr, "Error reading request body: %v\n", err)
          w.WriteHeader(http.StatusServiceUnavailable)
          return
        }
    
        // Pass the request body & Stripe-Signature header to ConstructEvent, along with the webhook signing key
        // You can find your endpoint's secret in your webhook settings
        endpointSecret := "whsec_...";
        event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret)
    
        if err != nil {
          fmt.Fprintf(os.Stderr, "Error verifying webhook signature: %v\n", err)
          w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature
          return
        }
    
        if event.Type == "payment_intent.succeeded" {
          var paymentIntent stripe.PaymentIntent
          err := json.Unmarshal(event.Data.Raw, &paymentIntent)
          if err != nil {
            fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
            w.WriteHeader(http.StatusBadRequest)
            return
          }
          fmt.Sprintf("Succeeded: %v\n", paymentIntent)
          // Fulfil the customer's purchase
    
        } else if event.Type == "payment_intent.payment_failed" {
          var paymentIntent stripe.PaymentIntent
            err := json.Unmarshal(event.Data.Raw, &paymentIntent)
            if err != nil {
              fmt.Fprintf(os.Stderr, "Error parsing webhook JSON: %v\n", err)
              w.WriteHeader(http.StatusBadRequest)
              return
            }
            fmt.Sprintf("Failed: %v, %v\n", paymentIntent, paymentIntent.LastPaymentError)
            // Notify the customer that payment failed
        }
        w.WriteHeader(http.StatusOK)
      })
    
      http.ListenAndServe(":3000", nil)
    }
    using System;
    using System.IO;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using Stripe;
    
    namespace StripeExampleApi.Controllers
    {
        [Route("webhook")]
        [ApiController]
        public class WebhookController : Controller
        {
            private readonly ILogger<WebhookController> _logger;
    
            public WebhookController(ILogger<WebhookController> logger)
            {
                _logger = logger;
            }
    
            const string secret = "whsec_...";
    
            [HttpPost]
            public ActionResult Post()
            {
                try {
                    var json = new StreamReader(HttpContext.Request.Body).ReadToEnd();
                    var stripeEvent = EventUtility.ConstructEvent(json,
                        Request.Headers["Stripe-Signature"], secret);
    
                    PaymentIntent intent = null;
    
                    switch (stripeEvent.Type)
                    {
                      case "payment_intent.succeeded":
                        intent = (PaymentIntent)stripeEvent.Data.Object;
                        _logger.LogInformation("Succeeded: {ID}", intent.Id);
    
                        // Fulfil the customer's purchase
    
                        break;
                      case "payment_intent.payment_failed":
                        intent = (PaymentIntent)stripeEvent.Data.Object;
                        _logger.LogInformation("Failure: {ID}", intent.Id);
    
                        // Notify the customer that payment failed
    
                        break;
                      default:
                        // Handle other event types
    
                        break;
                    }
                    return new EmptyResult();
    
                }
                catch (StripeException e) {
                    // Invalid Signature
                    return BadRequest();
                }
            }
        }
    }
    

    When payment is unsuccessful, you can find more details by inspecting the PaymentIntent’s last_payment_error property. You can notify the customer that their payment didn’t complete and encourage them to try again with a different payment method. When creating a new charge for the user to help them complete their purchase, you can reuse the existing PaymentIntent because the value of its status property has not transitioned to succeeded yet.

    The following list describes how to handle webhook events and responses returned by stripe.handleCardPayment:

    • On your checkout page, when stripe.handleCardPayment resolves with a PaymentIntent:
      • What happened: your customer completed a payment while still on your checkout page.
      • Expected integration: while your customer is still on your page, tell them that their payment has succeeded. Note that it is possible for your customer to pay successfully, but leave before this promise resolves.
    • On your checkout page, when stripe.handleCardPayment resolves with an error:
      • What happened: your customer’s payment failed while still on your checkout page.
      • Expected integration: while your customer is still on your page, display the error and tell them to provide another card and try again.
    • Your webhook endpoint receives a payment_intent.succeeded event:
      • What happened: you received a successful payment.
      • Expected integration: if you wish to fulfill goods or services once payment succeeds, you should perform those actions when you receive this event. This is the only way to guarantee that your integration is aware that a payment has completed successfully for asynchronous payment flows such as 3DS.
    • Your webhook endpoint receives a payment_intent.amount_capturable_updated event:
      • What happened: a payment has been authorized and is ready to be captured, and you may capture the amount up to the PaymentIntent’s amount_capturable property.
      • Expected integration: if you use separate separate authorization and capture, you’ll receive this event prior to payment_intent.succeeded . If you wish to capture the funds for a payment once the payment has been authorized, you should do that here.
    • Your webhook endpoint receives a payment_intent.payment_failed event:
      • What happened: a payment was declined by the card network or otherwise expired.
      • Expected integration: optionally reach out to your customer via email or push notification to prompt them to provide another payment method to complete their payment.

    Refunds

    When you use a PaymentIntent to collect payment from a customer, Stripe creates a charge behind the scenes. To refund the customer’s payment after the PaymentIntent has succeeded, create a refund on the charge object. You can also optionally refund part of their payment by specifying an amount. You can perform refunds with the API or through the Dashboard.

    Note that this does not apply if you are using separate authorization and capture, and you wish to refund a PaymentIntent that has a status of requires_capture. In this case, the charge attached to the PaymentIntent is still uncaptured and cannot be refunded directly. You should cancel the PaymentIntent instead.

    To find the charge object, you can inspect the PaymentIntent’s charges property, which has an array of all the charges created by the PaymentIntent. The first charge in the array is the one that completed successfully.

    The following example shows to refund a PaymentIntent’s charge:

    curl https://api.stripe.com/v1/payment_intents/pi_Aabcxyz01aDfoo \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc:
    # Retrieve the ID of the first charge in PaymentIntent
    # charges array returned from the previous request and use
    # it to create a refund.
    curl https://api.stripe.com/v1/refunds \
    -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
    -d charge="{CHARGE_ID}"
    # 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.retrieve("pi_Aabcxyz01aDfoo")
    intent['charges']['data'].first.refund
    
    # 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.retrieve("pi_Aabcxyz01aDfoo")
    intent['charges']['data'][0].refund()
    
    // 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 = StripePaymentIntent::retrieve("pi_Aabcxyz01aDfoo");
    $intent->charges->data[0].refund();
    
    // 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_Aabcxyz01aDfoo");
    intent.charges.getData().get(0).refund(new Map());
    
    // 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
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    (async () => {
      const intent = await stripe.paymentIntents.retrieve("pi_Aabcxyz01aDfoo");
      const refund = await stripe.refunds.create({
        charge: intent.charges.data[0].id
      });
    })();
    
    // 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"
    
    intent, err := paymentintent.Get("pi_Aabcxyz01aDfoo", nil)
    refundParams := &stripe.RefundParams{
      Charge: stripe.String(intent.Charges.Data[0].ID),
    }
    r, err := refund.New(refundParams)
    
    // 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.SetApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var paymentIntents = new PaymentIntentService();
    var refunds = new RefundService();
    var intent = paymentIntents.Get("pi_Aabcxyz01aDfoo");
    var refundOptions = new RefundCreateOptions {
      ChargeId = intent.Charges.Data[0].Id
    };
    var refund = refunds.Create(refundOptions);
    

    Sources and customers

    Collected payment information can be saved and associated with a customer for later reuse. When you create a PaymentIntent, set the value of save_payment_method to true and specify the desired customer and source. The following example demonstrates how to create a PaymentIntent that saves the customer’s payment information:

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d payment_method_types[]=card \
      -d save_payment_method=true \
      -d customer=cus_DyA7gideDWXNOX \
      -d source=src_1DWaarHgsMRXo4MtXrvYGoMZ
    
    # 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'],
      save_payment_method: true,
      customer: 'cus_DyA7gideDWXNOX',
      source: 'src_1DWaarHgsMRXo4MtXrvYGoMZ',
    })
    
    # 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'],
      save_payment_method=true,
      customer='cus_DyA7gideDWXNOX',
      source='src_1DWaarHgsMRXo4MtXrvYGoMZ'
    )
    
    // 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"],
      "save_payment_method" => true,
      "customer" => "cus_DyA7gideDWXNOX",
      "source" => "src_1DWaarHgsMRXo4MtXrvYGoMZ",
    ]);
    
    // 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);
    paymentintentsParams.put("save_payment_method", true);
    paymentintentsParams.put("customer", "cus_DyA7gideDWXNOX");
    paymentintentsParams.put("source", "src_1DWaarHgsMRXo4MtXrvYGoMZ");
    
    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
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    (async () => {
      const paymentIntent = await stripe.paymentIntents.create({
        amount: 1099,
        currency: 'usd',
        payment_method_types: ['card'],
        save_payment_method: true,
        customer: "cus_DyA7gideDWXNOX",
        source: "src_1DWaarHgsMRXo4MtXrvYGoMZ",
      });
    })();
    
    // 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: []*string{
        stripe.String("card"),
      },
      SaveSourceToCustomer: stripe.Boolean(true),
      Customer: stripe.String("cus_DyA7gideDWXNOX"),
      Source: stripe.String("src_1DWaarHgsMRXo4MtXrvYGoMZ")
    }
    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.SetApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var paymentIntents = new PaymentIntentService();
    var createOptions = new PaymentIntentCreateOptions {
      Amount = 1099,
      Currency = "usd",
      PaymentMethodTypes = new List<string> { "card" },
      SaveSourceToCustomer = true,
      Customer = "cus_DyA7gideDWXNOX",
      Source = "src_1DWaarHgsMRXo4MtXrvYGoMZ"
    };
    paymentIntents.Create(createOptions);
    

    The client-side handleCardPayment function also has a save_payment_method parameter, which you can optionally use to save the payment information provided by the customer. This is useful in cases where you would like to give the customer the option to choose whether their payment information is saved during the checkout process. This parameter only applies to the currently provided payment information. If the customer later provides different payment information, save_payment_method must be specified again to save the new information.

    Using a saved source

    When creating a PaymentIntent, you can instruct it to use a saved source by providing the relevant IDs with the customer and source parameters.

    When a PaymentIntent is confirmed with the source parameter, it immediately attempts to complete payment with the specified source. If the PaymentIntent can successfully complete payment with the saved source, you do not need to pass the PaymentIntent to the client side and collect billing information. The following example demonstrates how to create a PaymentIntent that uses a saved source:

    curl https://api.stripe.com/v1/payment_intents \
      -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
      -d amount=1099 \
      -d currency=usd \
      -d payment_method_types[]=card \
      -d source=src_1DWDnvHgsMRlo4Mtl1GO25qW \
      -d customer=cus_DyA7gideDWXNOX \
      -d confirm=true
    
    # 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'],
      source: 'src_1DWDnvHgsMRlo4Mtl1GO25qW',
      customer: 'cus_DyA7gideDWXNOX',
      confirm: true,
    })
    
    # 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'],
      source='src_1DWDnvHgsMRlo4Mtl1GO25qW',
      customer='cus_DyA7gideDWXNOX',
      confirm=True
    )
    
    // 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"],
      "source" => "src_1DWDnvHgsMRlo4Mtl1GO25qW",
      "customer" => "cus_DyA7gideDWXNOX",
      "confirm" => true,
    ]);
    
    // 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);
    paymentintentsParams.put("source", "src_1DWDnvHgsMRlo4Mtl1GO25qW");
    paymentintentsParams.put("customer", "cus_DyA7gideDWXNOX");
    paymentIntentsParams.put("confirm", true);
    
    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
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    (async () => {
      const paymentIntent = await stripe.paymentIntents.create({
        amount: 1099,
        currency: 'usd',
        payment_method_types: ['card'],
        source: "src_1DWDnvHgsMRlo4Mtl1GO25qW",
        customer: "cus_DyA7gideDWXNOX",
        confirm: true,
      });
    })();
    
    // 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: []*string{
        stripe.String("card"),
      },
      Source: stripe.String("src_1DWDnvHgsMRlo4Mtl1GO25qW"),
      Customer: stripe.String("cus_DyA7gideDWXNOX"),
      Confirm: true
    }
    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.SetApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var paymentIntents = new PaymentIntentService();
    var createOptions = new PaymentIntentCreateOptions {
      Amount = 1099,
      Currency = "usd",
      PaymentMethodTypes = new List<string> { "card" },
      Source = "src_1DWDnvHgsMRlo4Mtl1GO25qW",
      Customer = "cus_DyA7gideDWXNOX",
      Confirm = true
    };
    paymentIntents.Create(createOptions);
    

    Using Connect

    Stripe supports several approaches for creating charges on behalf of a connected account.

    One approach is a direct charge, in which the connected account is responsible for the cost of the Stripe fees, refunds, and chargebacks. To perform a direct charge with a PaymentIntent, supply the ID of the connected account while creating 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 \
      -H "Stripe-Account: {CONNECTED_ACCOUNT_ID}"
    
    # 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'],
    }, stripe_account: "{CONNECTED_ACCOUNT_ID}")
    
    # 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'],
      stripe_account='{CONNECTED_ACCOUNT_ID}'
    )
    
    // 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"],
    ], ["stripe_account" => "{CONNECTED_ACCOUNT_ID}"]);
    
    // 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);
    
    RequestOptions requestOptions = RequestOptions.builder().setStripeAccount("{CONNECTED_ACCOUNT_ID}").build();
    
    PaymentIntent.create(paymentintentParams, requestOptions);
    
    // 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
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    (async () => {
      const paymentIntent = await stripe.paymentIntents.create({
        amount: 1099,
        currency: 'usd',
        payment_method_types: ['card']
      }, {
        stripe_account: "{CONNECTED_ACCOUNT_ID}"
      });
    })();
    
    // 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: []*string{
        stripe.String("card"),
      },
    }
    params.SetStripeAccount("{CONNECTED_ACCOUNT_ID}")
    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.SetApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var paymentIntents = new PaymentIntentService();
    var createOptions = new PaymentIntentCreateOptions {
      Amount = 1099,
      Currency = "usd",
      PaymentMethodTypes = new List<string> { "card" }
    };
    var requestOptions = new RequestOptions {
      StripeConnectAccountId = "{CONNECTED_ACCOUNT_ID}"
    }
    paymentIntents.Create(createOptions, requestOptions);
    

    Additionally, PaymentIntents support creating a transfer to a connected account automatically and setting a connected account as the business of record for the payment.

    The transfer_data[destination] is the ID of the connected account that should receive the transfer.

    The on_behalf_of parameter is the ID of the connected account to use as the business of record for the payment. When it is set, Stripe automatically:

    • Settles charges in the country of the specified account, thereby minimizing declines and avoiding currency conversions
    • Uses the fee structure for the connected account’s country
    • If the account is in a different country than the platform, the connected account’s address and phone number shows up on the customer’s credit card statement (as opposed to the platform’s)

    The transfer_group parameter is propagated to all charges created by the PaymentIntent, and it behaves identically.

    Finally, you may withhold an application fee by providing the application_fee_amount 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 application_fee_amount=200 \
      -d on_behalf_of="{CONNECTED_ACCOUNT_ID}" \
      -d transfer_data[destination]="{CONNECTED_ACCOUNT_ID}"
    
    # 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'],
      application_fee_amount: 200,
      on_behalf_of: '{CONNECTED_ACCOUNT_ID}',
      transfer_data: {destination: '{CONNECTED_ACCOUNT_ID}'}
    })
    
    # 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',
      application_fee_amount=200,
      payment_method_types=['card'],
      on_behalf_of='{CONNECTED_ACCOUNT_ID}',
      transfer_data={'destination': '{CONNECTED_ACCOUNT_ID}'}
    )
    
    // 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",
      "application_fee_amount" => 200,
      "payment_method_types" => ["card"],
      "on_behalf_of" => "{CONNECTED_ACCOUNT_ID}",
      "transfer_data" => [
        "destination" => "{CONNECTED_ACCOUNT_ID}"
      ]
    ]);
    
    // 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("on_behalf_of", "{CONNECTED_ACCOUNT_ID}");
    paymentintentParams.put("application_fee_amount", 200);
    
    Map<String, Object> transferDataParams = new HashMap<String, Object>();
    transferDataParams.put("destination", "{CONNECTED_ACCOUNT_ID}");
    
    paymentintentParams.put("transfer_data", transferDataParams);
    
    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
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    (async () => {
      const paymentIntent = await stripe.paymentIntents.create({
        amount: 1099,
        currency: 'usd',
        payment_method_types: ['card'],
        application_fee_amount: 200,
        on_behalf_of: '{CONNECTED_ACCOUNT_ID}',
        transfer_data: {
          destination: '{CONNECTED_ACCOUNT_ID}'
        }
      });
    })();
    
    // 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"
    
    transferData = &stripe.PaymentIntentTransferDataParams{
      Destination: stripe.String("{CONNECTED_ACCOUNT_ID}"),
    }
    
    params := &stripe.PaymentIntentParams{
      Amount: stripe.Int64(1099),
      Currency: stripe.String(string(stripe.CurrencyUSD)),
      PaymentMethodTypes: []*string{
        stripe.String("card"),
      },
      OnBehalfOf: stripe.String("{CONNECTED_ACCOUNT_ID}"),
      ApplicationFeeAmount: stripe.Int64(200),
      TransferData: transferData,
    }
    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.SetApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    var paymentIntents = new PaymentIntentService();
    var createOptions = new PaymentIntentCreateOptions {
      Amount = 1099,
      Currency = "usd",
      PaymentMethodTypes = new List<string> { "card" },
      ApplicationFeeAmount = 200,
      OnBehalfOf = "{CONNECTED_ACCOUNT_ID}",
      TransferData = new PaymentIntentTransferDataOptions {
        DestinationId = "{CONNECTED_ACCOUNT_ID}",
      }
    };
    paymentIntents.Create(createOptions);
    

    Payment Request and Apple Pay

    Follow the Payment Request Button quickstart guide until step 4.

    Instead of creating a charge directly from a token in step 4, listen to the source event to receive a source object.

    Then, supply the source ID to stripe.confirmPaymentIntent and stripe.handleCardPayment to complete the payment.

    paymentRequest.on('source', function(ev) {
      stripe.confirmPaymentIntent(clientSecret, {
        source: ev.source.id,
        use_stripe_sdk: true
      }).then(function(confirmResult) {
        if (confirmResult.error) {
          // Report to the browser that the payment failed, prompting it to
          // re-show the payment interface, or show an error message and close
          // the payment interface.
          ev.complete('fail');
        } else {
          // Report to the browser that the confirmation was successful, prompting
          // it to close the browser payment method collection interface.
          ev.complete('success');
          if (confirmResult.paymentIntent.status === 'succeeded') {
            // The payment has succeeded. No additional steps are required.
          } else {
            // Let Stripe.js handle the rest of the payment flow.
            stripe.handleCardPayment(clientSecret).then(function(result) {
              if (result.error) {
                // The payment failed -- ask your customer for a new payment method.
              } else {
                // The payment has succeeded.
              }
            });
          }
        }
      });
    });
    paymentRequest.on('source', async (ev) => {
      const {
        error: confirmError,
        paymentIntent,
      } = stripe.confirmPaymentIntent(clientSecret, {
        source: ev.source.id,
        use_stripe_sdk: true,
      });
    
      if (confirmError) {
        // Report to the browser that the payment failed, prompting it to
        // re-show the payment interface, or show an error message and close
        // the payment interface.
        ev.complete('fail');
      } else {
        // Report to the browser that the confirmation was successful, prompting
        // it to close the browser payment method collection interface.
        ev.complete('success');
        if (paymentIntent.status === 'succeeded') {
          // The payment has succeeded. No additional steps are required.
        } else {
          // Let Stripe.js handle the rest of the payment flow.
          const {error} = await stripe.handleCardPayment(clientSecret);
          if (error) {
            // The payment failed -- ask your customer for a new payment method.
          } else {
            // The payment has succeeded.
          }
        }
      }
    });

    Next steps

    To learn more about PaymentIntents, read more:

    Questions?

    We're always happy to help with code or other questions you might have! Search our documentation, contact support, or connect with our sales team. You can also chat live with other developers in #stripe on freenode

    Was this page helpful? Yes No

    Send

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