PayPal Checkout

Capture Transaction Funds

Note: This guide assumes you have completed a basic Smart Payment Buttons integration.

On the server

  1. Set up your server to make calls to PayPal
  2. Set up your server to receive a call from the client with the order ID
  3. Call PayPal to capture the order
  4. Save the capture ID to your database
  5. Handle any errors from the call
  6. Return a successful response to the client

Note: To install the PayPal SDK on your server, see the Set up Server-Side SDK guide. If you are calling the API directly, you do not need to install the SDK.

// Note: This code is intended as a *pseudocode* example. Each server platform and programming language has a different way of handling requests, making HTTP API calls, and serving responses to the browser.

// 1. Set up your server to make calls to PayPal

// 1a. Add your client ID and secret
PAYPAL_CLIENT = 'PAYPAL_SANDBOX_CLIENT';
PAYPAL_SECRET = 'PAYPAL_SANDBOX_SECRET';

// 1b. Point your server to the PayPal API
PAYPAL_OAUTH_API = 'https://api.sandbox.paypal.com/v1/oauth2/token/';
PAYPAL_ORDER_API = 'https://api.sandbox.paypal.com/v2/checkout/orders/';

// 1c. Get an access token from the PayPal API
basicAuth = base64encode(`${ PAYPAL_CLIENT }:${ PAYPAL_SECRET }`);
auth = http.post(PAYPAL_OAUTH_API {
  headers: {
    Accept:        `application/json`,
    Authorization: `Basic ${ basicAuth }`
  },
  data: `grant_type=client_credentials`
});

// 2. Set up your server to receive a call from the client
function handleRequest(request, response) {

  // 2a. Get the order ID from the request body
  orderID = request.body.orderID;

  // 3. Call PayPal to capture the order
  capture = http.post(PAYPAL_ORDER_API + orderID + '/capture', {
    headers: {
      Accept:        `application/json`,
      Authorization: `Bearer ${ auth.access_token }`
    }
  });

  // 4. Save the capture ID to your database
  if (!capture.error) {
    captureID = capture.purchase_units[0]
        .payments.captures[0].id;
    database.saveCaptureID(captureID);
  }

  // 5. Handle any errors from the call
  if (capture.error) {
    console.error(capture.error);
    return response.send(500);
  }

  // 6. Return a successful response to the client
  response.send(200);
}
curl -v -X POST https://api.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T/capture \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token" \
-H "PayPal-Request-Id: 7b92603e-77ed-4896-8e78-5dea2050476a"
// 1. Set up your server to make calls to PayPal

// 1a. Import the SDK package
const checkoutNodeJssdk = require('@paypal/checkout-server-sdk');

// 1b. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
/**
 *
 * PayPal HTTP client dependency
 */
const payPalClient = require('../Common/payPalClient');

// 2. Set up your server to receive a call from the client
module.exports = async function handleRequest(req, res) {

  // 2a. Get the order ID from the request body
  const orderID = req.body.orderID;

  // 3. Call PayPal to capture the order
  const request = new checkoutNodeJssdk.orders.OrdersCaptureRequest(orderID);
  request.requestBody({});

  try {
    const capture = await payPalClient.client().execute(request);

    // 4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
    const captureID = capture.result.purchase_units[0]
        .payments.captures[0].id;
   // await database.saveCaptureID(captureID);

  } catch (err) {

    // 5. Handle any errors from the call
    console.error(err);
    return res.send(500);
  }

  // 6. Return a successful response to the client
  res.send(200);
}
<?php

namespace Sample\CaptureIntentExamples;

require __DIR__ . '/vendor/autoload.php';
//1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;

class CaptureOrder
{

  // 2. Set up your server to receive a call from the client
  /**
   *This function can be used to capture an order payment by passing the approved
   *order ID as argument.
   *
   *@param orderId
   *@param debug
   *@returns
   */
  public static function captureOrder($orderId, $debug=false)
  {
    $request = new OrdersCaptureRequest($orderId);

    // 3. Call PayPal to capture an authorization
    $client = PayPalClient::client();
    $response = $client->execute($request);
    // 4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
    if ($debug)
    {
      print "Status Code: {$response->statusCode}\n";
      print "Status: {$response->result->status}\n";
      print "Order ID: {$response->result->id}\n";
      print "Links:\n";
      foreach($response->result->links as $link)
      {
        print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n";
      }
      print "Capture Ids:\n";
      foreach($response->result->purchase_units as $purchase_unit)
      {
        foreach($purchase_unit->payments->captures as $capture)
        {   
          print "\t{$capture->id}";
        }
      }
      // To print the whole response body, uncomment the following line
      // echo json_encode($response->result, JSON_PRETTY_PRINT);
    }

    return $response;
  }
}

/**
 *This driver function invokes the captureOrder function with
 *approved order ID to capture the order payment.
 */
if (!count(debug_backtrace()))
{
  CaptureOrder::captureOrder('REPLACE-WITH-APPORVED-ORDER-ID', true);
}
?>
# 1. Import the PayPal SDK client created in `Set up Server-Side SDK` section.
from sample import PayPalClient
from paypalcheckoutsdk.orders import OrdersCaptureRequest


class CaptureOrder(PayPalClient):

  #2. Set up your server to receive a call from the client
  """this sample function performs payment capture on the order.
  Approved order ID should be passed as an argument to this function"""

  def capture_order(self, order_id, debug=False):
    """Method to capture order using order_id"""
    request = OrdersCaptureRequest(order_id)
    #3. Call PayPal to capture an order
    response = self.client.execute(request)
    #4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
    if debug:
      print 'Status Code: ', response.status_code
      print 'Status: ', response.result.status
      print 'Order ID: ', response.result.id
      print 'Links: '
      for link in response.result.links:
        print('\t{}: {}\tCall Type: {}'.format(link.rel, link.href, link.method))
      print 'Capture Ids: '
      for purchase_unit in response.result.purchase_units:
        for capture in purchase_unit.payments.captures:
          print '\t', capture.id
      print "Buyer:"
      print "\tEmail Address: {}\n\tName: {}\n\tPhone Number: {}".format(response.result.payer.email_address,
        response.result.payer.name.given_name + " " + response.result.payer.name.surname,
        response.result.payer.phone.phone_number.national_number)
    return response


"""This driver function invokes the capture order function.
Replace Order ID value with the approved order ID. """
if __name__ == "__main__":
  order_id = 'REPLACE-WITH-APPORVED-ORDER-ID'
  CaptureOrder().capture_order(order_id, debug=True)
# 1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
require_relative '../paypal_client'
include PayPalCheckoutSdk::Orders
module Samples
  module CaptureIntentExamples
  class CaptureOrder

    #2. Set up your server to receive a call from the client
    # This sample function performs payment capture on the order.
    # Pass the approved order ID as an argument to this function
    def capture_order (order_id, debug=false)
    request = OrdersCaptureRequest::new(order_id)
    request.prefer("return=representation")
    #3. Call PayPal to capture an order
    begin
      response = PayPalClient::client.execute(request)
      #4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
    rescue => e
      puts e.result
      #5. Handle errors, if any.
    end
    if debug
      puts "Status Code: " + response.status_code.to_s
      puts "Status: " + response.result.status
      puts "Order ID: " + response.result.id
      puts "Intent: " + response.result.intent
      puts "Links:"
      for link in response.result.links
      # This could also be named link.rel or link.href, but method is a reserved keyword for Ruby. Avoid using link.method.
      puts "\t#{link["rel"]}: #{link["href"]}\tCall Type: #{link["method"]}"
      end
      puts "Capture Ids: "
      for purchase_unit in response.result.purchase_units
        for capture in purchase_unit.payments.captures
          puts "\t #"
        end
      end
      puts "Buyer:"
      buyer = response.result.payer
      puts "\tEmail Address: #\n\tName: #\n\tPhone Number: #"
      end
    return response
    end
  end
  end
end
# This driver function invokes the capture order function.
# Replace the order ID value with the approved order ID.
if __FILE__ == $0
  Samples::CaptureIntentExamples::CaptureOrder::new::capture_order('REPLACE-WITH-APPORVED-ORDER-ID', true)
end
package com.paypal.CaptureIntentExamples;

import java.io.IOException;

import com.braintreepayments.http.HttpResponse;
import com.paypal.PayPalClient;
import com.paypal.orders.Capture;
import com.paypal.orders.Customer;
import com.paypal.orders.LinkDescription;
import com.paypal.orders.Order;
import com.paypal.orders.OrderRequest;
import com.paypal.orders.OrdersCaptureRequest;
import com.paypal.orders.PurchaseUnit;

/*
*
*1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
*This step extends the SDK client.  It's not mandatory to extend the client, you can also inject it.
*/
public class CaptureOrder extends PayPalClient {

  //2. Set up your server to receive a call from the client
  /**
   *Method to capture order after creation. Pass a valid, approved order ID
   *an argument to this method.
   *
   *@param orderId Authorization ID from authorizeOrder response
   *@param debug   true = print response data
   *@return HttpResponse<Capture> response received from API
   *@throws IOException Exceptions from API if any
   */
  public HttpResponse<Order> captureOrder(String orderId, boolean debug) throws IOException {
    OrdersCaptureRequest request = new OrdersCaptureRequest(orderId);
    request.requestBody(buildRequestBody());
    //3. Call PayPal to capture an order
    HttpResponse<Order> response = client().execute(request);
    //4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
    if (debug) {
      System.out.println("Status Code: " + response.statusCode());
      System.out.println("Status: " + response.result().status());
      System.out.println("Order ID: " + response.result().id());
      System.out.println("Links: ");
      for (LinkDescription link : response.result().links()) {
        System.out.println("\t" + link.rel() + ": " + link.href());
      }
      System.out.println("Capture ids:");
      for (PurchaseUnit purchaseUnit : response.result().purchaseUnits()) {
        for (Capture capture : purchaseUnit.payments().captures()) {
          System.out.println("\t" + capture.id());
        }
      }
      System.out.println("Buyer: ");
      Customer buyer = response.result().payer();
      System.out.println("\tEmail Address: " + buyer.emailAddress());
      System.out.println("\tName: " + buyer.name().fullName());
      System.out.println("\tPhone Number: " + buyer.phone().countryCode() + buyer.phone().nationalNumber());
    }
    return response;
  }

  /**
   *Creating empty body for capture request.
   *You can set the payment source if required.
   *
   *@return OrderRequest request with empty body
   */
  public OrderRequest buildRequestBody() {
    return new OrderRequest();
  }

  /**
   *Driver function to invoke capture payment on order.
   *Replace the order ID with the valid, approved order ID.
   *
   *@param args
   */
  public static void main(String[] args) {
    try {
      new CaptureOrder().captureOrder("REPLACE-WITH-APPORVED-ORDER-ID", true);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
//1. Import the PayPal SDK client that was created in `Set up Server-Side SDK`.
using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders;
using BraintreeHttp;

namespace Samples.CaptureIntentExamples
{
  public class CaptureOrderSample
  {

    //2. Set up your server to receive a call from the client
    /*
      Method to capture order after creation. Pass a valid, approved order ID
      as an argument to this method.
    */
    public async static Task<HttpResponse> CaptureOrder(string OrderId, bool debug = false)
    {
      var request = new OrdersCaptureRequest(OrderId);
      request.Prefer("return=representation");
      request.RequestBody(new OrderActionRequest());
      //3. Call PayPal to capture an order
      var response = await PayPalClient.client().Execute(request);
      //4. Save the capture ID to your database. Implement logic to save capture to your database for future reference.
      if (debug)
      {
        var result = response.Result<Order>();
        Console.WriteLine("Status: {0}", result.Status);
        Console.WriteLine("Order Id: {0}", result.Id);
        Console.WriteLine("Intent: {0}", result.Intent);
        Console.WriteLine("Links:");
        foreach (LinkDescription link in result.Links)
        {
          Console.WriteLine("\t{0}: {1}\tCall Type: {2}", link.Rel, link.Href, link.Method);
        }
        Console.WriteLine("Capture Ids: ");
        foreach (PurchaseUnit purchaseUnit in result.PurchaseUnits)
        {
          foreach (Capture capture in purchaseUnit.Payments.Captures)
          {
            Console.WriteLine("\t {0}", capture.Id);
          }
        }
        AmountWithBreakdown amount = result.PurchaseUnits[0].Amount;
        Console.WriteLine("Buyer:");
        Console.WriteLine("\tEmail Address: {0}\n\tName: {1}\n\tPhone Number: {2}{3}", result.Payer.EmailAddress, result.Payer.Name.FullName, result.Payer.Phone.CountryCode, result.Payer.Phone.NationalNumber);
      }

      return response;
    }

    /*
      Driver function to invoke capture payment on order.
      Replace the order ID with the valid, approved order ID.
    */
    static void Main(string[] args)
    {
      string OrderId = "REPLACE-WITH-APPORVED-ORDER-ID";
      CaptureOrder(OrderId, true).Wait();
    }
  }
}

For the full API reference, and example responses, see the Orders Capture API reference.

Note: Remember to swap the credentials and API URL from sandbox to live when going live with your integration.

On the client

Next, change the onApprove function on your client. This function now calls your server with the order ID and no longer call actions.order.capture().

onApprove: function(data) {
  return fetch('/my-server/capture-paypal-transaction', {
    headers: {
      'content-type': 'application/json'
    },
    body: JSON.stringify({
      orderID: data.orderID
    })
  }).then(function(res) {
    return res.json();
  }).then(function(details) {
    alert('Transaction funds captured from ' + details.payer_given_name);
  })
}

Now your client and server are set up to call the PayPal Orders API to capture funds from a transaction.

Feedback