Collecting Payments with the JavaScript SDK Invite Only

    Learn how to collect in-person payments with the Stripe Terminal JavaScript SDK.

    Collecting payments using the Stripe Terminal JavaScript SDK requires just four steps:

    1. Create a PaymentIntent (via the backend)
    2. Confirm the PaymentIntent (SDK)
    3. Handle failures (SDK)
    4. Capture the PaymentIntent (backend)

    Step 1: Create a PaymentIntent

    First, create a PaymentIntent object. A PaymentIntent represents your intent to collect payment from a customer, tracking the lifecycle of the payment process through each step.

    Each PaymentIntent typically correlates with a single cart or customer session in your application. When you create a PaymentIntent, specify the currency, the permitted source types, and the amount to collect from the customer.

    The following example shows how to create a PaymentIntent on your server:

    curl https://api.stripe.com/v1/payment_intents \
       -u sk_test_4eC39HqLyjWDarjtT1zdp7dc: \
       -d amount=1000 \
       -d currency=usd \
       -d allowed_source_types[]=card_present \
       -d capture_method=manual
    
    
    require 'stripe'
    Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
    
    intent = Stripe::PaymentIntent.create({
      amount: 1000,
      currency: 'usd',
      allowed_source_types: ['card_present'],
      capture_method: 'manual',
    }, {
      idempotency_key: my_order_id,
    })
    
    import stripe
    stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
    
    stripe.PaymentIntent.create(
      amount=1000,
      currency='usd',
      allowed_source_types: ['card_present'],
      capture_method: 'manual',
    )
    
    \Stripe\Stripe::setApiKey("sk_test_4eC39HqLyjWDarjtT1zdp7dc");
    
    \Stripe\PaymentIntent::create([
      "amount" => 1000,
      "currency" => "usd",
      "allowed_source_types" => ["card_present"],
      "capture_method" => "manual",
    ]);
    
    import stripe
    Stripe.apiKey = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
    
    final List<String> allowedSourceTypes = new ArrayList<String>();
    allowedSourceTypes.add("card_present");
    final Map<String, Object> params = new HashMap<>();
    params.put("allowed_source_types", allowedSourceTypes);
    params.put("amount", 1000);
    params.put("currency", "usd");
    params.put("capture_method", "manual");
    
    final PaymentIntent paymentIntent = PaymentIntent.create(params);
    
    var stripe = require("stripe")("sk_test_4eC39HqLyjWDarjtT1zdp7dc")
    
    stripe.paymentIntents.create({
      amount: 1000,
      currency: 'usd',
      allowed_source_types: ['card_present'],
      capture_method: 'manual',
    }, function(err, paymentIntent) {
      // asynchronously called
    });
    
    import "github.com/stripe/stripe-go"
    
    stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
    params := &stripe.PaymentIntentParams{
      Amount: stripe.Int64(1000),
      Currency: stripe.String(string(stripe.CurrencyUSD)),
      AllowedSourceTypes: []*string{
        stripe.String("card"),
      },
      CaptureMethod: stripe.String("manual"),
    }
    paymentIntent.New(params)
    

    The allowed_source_types parameter must include card_present for Stripe Terminal payments. To ensure that a card present payment is not unintentionally captured, only a capture_method of manual is allowed for card_present PaymentIntents.

    You can choose to cancel stale, uncaptured PaymentIntents. Canceling a PaymentIntent releases all uncaptured funds. A canceled PaymentIntent can no longer be used to perform charges.

    After creating a PaymentIntent on your server, you can interact with the PaymentIntent client-side by exposing its client_secret to your application.

    Step 2: Confirm the PaymentIntent

    After creating a PaymentIntent, its status will be requires_source. Call terminal.collectPaymentMethod to collect a payment method. The SDK then waits for a payment method to be presented to the reader.

    // clientSecret is the client_secret from the PaymentIntent you created in Step 1.
    terminal.collectPaymentMethod(clientSecret).then(function(result) {
      if (result.error) {
        console.error("Collect payment method failed: " + result.error.message);
      }
      else {
        console.log("Payment method: ", result.paymentIntent.payment_method)
        // Confirm PaymentIntent (see below)
        confirmPaymentIntent(result.paymentIntent)
      }
    });
    async () => {
      // clientSecret is the client_secret from the PaymentIntent you created in Step 1.
      const result = await terminal.collectPaymentMethod(clientSecret);
      if (result.error) {
        console.error(`Collect payment method failed: ${result.error.message}`);
      }
      else {
        console.log("Payment method: ", result.paymentIntent.payment_method);
        // Confirm PaymentIntent (see below)
        confirmPaymentIntent(result.paymentIntent);
      }
    }
    

    If collecting payment method fails, the completion block returns an error. If collecting payment method succeeds, the completion block returns the PaymentIntent with a requires_confirmation status.

    To proceed with the payment, call terminal.confirmPaymentIntent.

    function confirmPaymentIntent(paymentIntent) {
      return terminal.confirmPaymentIntent(paymentIntent).then(function(confirmResult) {
        if (confirmResult.error) {
          console.error("Confirm failed: " + confirmResult.error.message);
        } else if (confirmResult.paymentIntent) {
          // Placeholder for notifying your backend to capture the PaymentIntent
        }
      });
    }
    async function confirmPaymentIntent(paymentIntent) {
      const confirmResult = await terminal.confirmPaymentIntent(paymentIntent);
      if (confirmResult.error) {
        console.error(`Confirm failed: ${confirmResult.error.message}`);
      } else if (confirmResult.paymentIntent) {
        // Placeholder for notifying your backend to capture the PaymentIntent
      }
    }
    

    If confirming the PaymentIntent fails, the completion block returns an error. If confirming the PaymentIntent succeeds, the completion block returns the PaymentIntent with a requires_capture status.

    Step 3: Handle failures

    When confirming a PaymentIntent fails, the SDK returns an error that includes the updated PaymentIntent. Your application should inspect the PaymentIntent to decide how to deal with the error.

    If the updated PaymentIntent’s status is requires_source (e.g., the request failed because the payment method was declined), call collectPaymentMethod with the updated PaymentIntent to try charging another payment method.

    If the updated PaymentIntent’s status is requires_confirmation (e.g., the request failed because of a temporary connectivity problem), call confirmPaymentIntent again with the updated PaymentIntent to retry the request.

    If the updated PaymentIntent is null, the request to Stripe’s servers timed out, and the PaymentIntent’s status is unknown. In this situation, retry confirming the original PaymentIntent. Do not create a new PaymentIntent, as that could result in multiple authorizations for the cardholder.

    If you encounter multiple, consecutive timeouts, there might be local networking problems. In this case, make sure that your application is able to communicate with the Internet.

    Step 4: Capture the PaymentIntent

    Stripe Terminal uses a two-step process to prevent unintended and duplicate payments. When the SDK returns a confirmed PaymentIntent to your app, the payment is authorized, but not captured. Read our Auth and capture documentation for more information about the difference.

    When your app receives a confirmed PaymentIntent from the SDK, it should notify your backend to capture the PaymentIntent. You should create an endpoint on your backend that accepts a PaymentIntent ID and sends a request to the Stripe API to capture it.

    require 'stripe'
    Stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
    
    # Using Sinatra
    post '/capture/:payment_intent_id' do
      payment_intent = Stripe::PaymentIntent.retrieve(params["payment_intent_id"])
      payment_intent.capture
      # Optionally reconcile the PaymentIntent with your internal order system.
      status 200
    end
    
    from django.http import HttpResponse
    import stripe
    stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
    
    # Using Django
    def my_payment_intent_capture_view(request, payment_intent_id):
      payment_intent = stripe.PaymentIntent.retrieve(payment_intent_id)
      payment_intent.capture()
      # Optionally reconcile the PaymentIntent with your internal order system.
      return HttpResponse('')
    
    // Using the Spark framework (http://sparkjava.com)
    public Object handle(Request request, Response response) {
      String paymentIntentId = request.queryParams("paymentIntentId");
      PaymentIntent paymentIntent = PaymentIntent.retrieve(paymentIntentId);
      paymentIntent.capture();
      // Optionally reconcile the PaymentIntent with your internal order system.
      response.status(200);
      return "";
    }
    
    // Using Express
    var app = require('express')();
    var stripe = require('stripe')('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
    
    // Retrieve the raw body as a buffer and match all content types:
    app.use(require('body-parser').raw({type: '*/*'}));
    
    app.post('/capture', function(request, response) {
      var payment_intent_id = request.body.payment_intent_id;
      var payment_intent = stripe.paymentIntents.retrieve(payment_intent_id);
      payment_intent.capture();
      // Optionally reconcile the PaymentIntent with your internal order system.
      response.send(200);
    });
    
    package main
    
    import (
        "github.com/stripe/stripe-go"
        "github.com/stripe/stripe-go/paymentintent"
        "net/http"
    )
    
    func main() {
        stripe.Key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
    
        http.HandleFunc("/capture", func(w http.ResponseWriter, req *http.Request) {
            err := req.ParseForm()
            if err != nil {
                w.WriteHeader(http.StatusBadRequest)
                return
            }
            payment_intent_id := req.Form.Get("payment_intent_id")
            payment_intent_params := &stripe.PaymentIntentCaptureParams{}
            paymentintent.Capture(payment_intent_id, payment_intent_params)
            // Optionally reconcile the PaymentIntent with your internal order system.
    
            w.WriteHeader(http.StatusOK)
        })
    
        http.ListenAndServe(":4567", nil)
    }
    
    

    Next steps

    Congratulations! You're set up to authorize and capture your first payment. Next, use our test cards to test your integration.

    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.