Using PaymentIntents with Server-side Confirmation

    Learn how to build an integration in which the PaymentIntent is confirmed on the server.

    When using a PaymentIntent to accept payment from a customer, the final step is confirming the payment. In most conventional usage scenarios, this step takes place on the client. It occurs automatically when using the handleCardPayment function in Stripe.js—or can be accomplished by using the confirmPaymentIntent function in integrations that handle next actions manually. In some cases, however, you may wish to perform confirmation on the server instead of the client.

    Confirmation on the server can be useful when your application needs to securely check the details of a card before initiating payment—in integrations that only accept debit cards, for example. It is also helpful when performing automated charges with previously-saved payment information, particularly when the user is not directly involved. For recurring payments, however, Stripe’s Billing features may be better-suited for the needs of your application.

    Although confirmation on the server is possible, it entails tradeoffs that warrant attention. Your application becomes responsible for ensuring that customers perform any additional steps that are required to complete payment. Some steps, such as authentication, may still need to be performed on the client. As with a conventional PaymentIntents integration, you have the option of handling next actions manually or delegating the work to Stripe.js by using the handleCardPayment function. The latter is recommended, as it requires less effort to implement and requires no additional work to support new actions introduced in the future.

    To create a PaymentIntents integration with server-side confirmation, perform the following steps:

    1. Create a PaymentIntent and attach a payment method
    2. Check the PaymentIntent status
    3. Address additional steps required to complete payment

    Step 1: Create a PaymentIntent and attach a payment method

    When creating a PaymentIntent, you can attach a payment method object to provide the customer’s payment information. You should also set the value of the PaymentIntent’s confirm property to true, which causes confirmation to occur immediately—with the provided source—when the PaymentIntent is created. Note that you can also programmatically confirm a PaymentIntent that has already been created.

    If you intend to use handleCardPayment function on the client to address any additional steps that are required, don’t specify a return_url. If you intend to handle next steps manually, supply a value for the return_url parameter, which indicates where to send the user when they complete a redirect-based authentication flow.

    The following code example demonstrates how to create and confirm a PaymentIntent using an existing payment method:

    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="{SOURCE_ID}" \
      -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: '{SOURCE_ID}',
      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='{SOURCE_ID}',
      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" => "{SOURCE_ID}",
      "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", "{SOURCE_ID");
    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: "{SOURCE_ID}",
        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("{SOURCE_ID}"),
      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 = "{SOURCE_ID}",
      Confirm = true,
    };
    paymentIntents.Create(createOptions);
    

    Step 2: Check the PaymentIntent status

    Next, inspect the status property of the newly-created PaymentIntent to determine if the payment completed successfully. The following list describes possible status values and their significance:

    • requires_payment_method: the payment was unsuccessful—check the last_payment_error property and attempt to try again, collecting new payment information from the customer if necessary.
    • requires_action: additional steps are required to complete the payment—handle them on the client.
    • succeeded: the payment completed and resulted in the creation of a charge using the supplied payment method. No further steps are required.

    Step 3: Address additional steps required to complete payment

    When the value of the status property is requires_action and the type of the next_action is use_stripe_sdk, you must complete the required steps on the client. Make the PaymentIntent’s client secret available on the client and use the SDK to handle the actions. In a Stripe.js integration, pass the client secret to the handleCardPayment function, which automatically ushers the customer through the authentication process and initiates completion of the payment. You can refer to the Android and iOS SDK documentation for details about how to handle next steps in a mobile application.

    (async () => {
      const {paymentIntent, error} = await stripe.handleCardPayment(CLIENT_SECRET);
    })();
    

    To handle the redirect yourself, you may provide a value for the return_url property. You may then handle next actions manually. Inspect the PaymentIntent’s next_action property to determine how to proceed. If it provides a URL via the next_action.redirect_to_url.url property, you may redirect the customer to that address to complete authentication. When the customer finishes the authentication process, they are sent back to the destination that you specified with the return_url property when you created the PaymentIntent. The redirect also adds payment_intent and payment_intent_client_secret URL query parameters that your application can use to identify the PaymentIntent associated with the customer’s purchase.

    As authentication and other required steps occur asynchronously on the client, you must monitor for the payment_intent.succeeded and payment_intent.payment_failed events on your server in order to determine the outcome of the process and handle fulfillment upon success.

    Next steps

    Now you have a complete PaymentIntents integration with confirmation on the server. To learn more, continue reading:

    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.