Collecting Payments with the iOS SDK Invite Only

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

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

    1. Create a PaymentIntent (via the SDK or 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 a 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 and the amount to collect from the customer.

    The following example shows how to create a PaymentIntent client-side via the SDK:

    let params = PaymentIntentParameters(amount: 1000, currency: "usd")
    terminal.createPaymentIntent(params) { paymentIntent in
        // Placeholder for continuing payment with the created PaymentIntent
    }
    

    You can choose to cancel stale, uncaptured PaymentIntents via the SDK or on your server. Canceling a PaymentIntent releases all uncaptured funds. A canceled PaymentIntent can no longer be used to perform charges.

    If the information required to create a PaymentIntent isn’t readily available in your application, you can also create the PaymentIntent on your server, and retrieve it via the SDK.

    Step 2: Confirm the PaymentIntent

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

    let cancelable = terminal.collectPaymentMethod(paymentIntent, delegate: self) { intent, error in
        if let intent = intent {
            // Placeholder for confirming the updated PaymentIntent
        }
        else if let error = error {
            // Placeholder for handling the error
        }
    }
    

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

    To proceed with the payment method, call terminal.confirmPaymentIntent with the updated PaymentIntent.

    terminal.confirmPaymentIntent(paymentIntent) { intent, error in
        if let intent = intent {
            // Placeholder for notifying your backend to capture the PaymentIntent
        }
        else if let error = error {
            // Placeholder for handling the error
        }
    }
    

    If confirming the PaymentIntent fails, the completion block returns a ConfirmError. If confirming the PaymentIntent succeeds, the completion block returns the updated PaymentIntent with a status of requires_capture.

    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 nil, 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.