PayPal Checkout

Update Order Details

For increased flexibility when obtaining payments from buyers, you can update the transaction after it has been set up. This allows you to:

  • Determine additional amounts, including shipping and tax.
  • Capture a different total amount, without needing the buyer to re-approve the transaction.
  • Update fields, such as shipping address, after collecting them from the buyer.

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

1. Update the script tag

If you are updating the final amount of the transaction after the buyer approves the payment, or if you are updating other amount fields, such as shipping or tax, change the PayPal script tag to pass commit=false.

<script
  src="https://www.paypal.com/sdk/js?client-id=CLIENT_ID&commit=false">
</script>

This shows a Continue button during the buyer checkout experience rather than a Pay Now button, indicating to the buyer that the amount or other details might change before they complete the transaction.

Note: Using commit=false reduces the number of Smart Payment Buttons that are shown to your buyer, since not all funding sources can be used when modifying the transaction. When possible, determine the final amount before the buyer approves the transaction on PayPal, and avoid using PATCH.

2. Patch the transaction

Before you capture the funds from the transaction, call the PayPal Orders API on your server with the order ID. You can pass in a different amount, invoice_id, and custom_id. See the following code sample for the list of fields that you can modify.

  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 patch the order
  4. Handle any errors from the call
  5. 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 patch the order
  patch = http.post(PAYPAL_ORDER_API + orderID, {
    method: 'PATCH',
    headers: {
      Accept:        `application/json`,
      Authorization: `Bearer ${ auth.access_token }`
    },
    data: {
      op:    'replace',
      path:  '/purchase_units/@reference_id==\'default\'/amount',
      value: {
        currency_code: 'USD',
        value:         '500.00'
      }
    }
  });

  // 4. Handle any errors from the call
  if (patch.error) {
    return response.send(500);
  }

  // 5. Return a successful response to the client
  response.send(200);
}
curl -v -X PATCH https://api.sandbox.paypal.com/v2/checkout/orders/5O190127TN364715T \
-H "Content-Type: application/json" \
-H "Authorization: Bearer Access-Token" \
-d '[
  {
"op": "add",
"path": "/purchase_units/@reference_id=='PUHF'/invoice_id",
"value": {
  "integration_artifact": "INV-HighFashions"
}
  }
]'
// 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 the Server SDK`.
/**
 *
 * PayPal HTTP client dependency
 */
const payPalClient = require('../Common/payPalClient');

module.exports = async function patchOrder(request, response) {

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

  // 3. Call PayPal to patch the transaction
  const request = new checkoutNodeJssdk.orders.OrdersPatchRequest(orderId);
  request.requestBody([
        {
            "op": "replace",
            "path": "/intent",
            "value": "CAPTURE"
        },
        {
            "op": "replace",
            "path": "/purchase_units/@reference_id=='PUHF'/amount",
            "value": {
                "currency_code": "USD",
                "value": "200.00",
                "breakdown": {
                    "item_total": {
                        "currency_code": "USD",
                        "value": "180.00"
                    },
                    "tax_total": {
                        "currency_code": "USD",
                        "value": "20.00"
                    }
                }
            }
        }
    ]);
  try {
    const response = await payPalClient.client().execute(request);
  } catch (err) {

    // 4. Handle any errors from the call
    console.error(err);
  }
   // 5. Return a successful response to the client
  response.send(200);
<?php
namespace Sample;
require __DIR__ . '/vendor/autoload.php';

//1. Import the PayPal SDK client that was created in `Set up the Server SDK`.
use Sample\PayPalClient;
use PayPalCheckoutSdk\Orders\OrdersPatchRequest;
use PayPalCheckoutSdk\Orders\OrdersGetRequest;
class PatchOrder
{

    // 2. Set up your server to receive a call from the client
    public static function patchOrder($orderId)
    {
        // 3. Call PayPal to patch the transaction details
        $client = PayPalClient::client();
        $request = new OrdersPatchRequest($orderId);
        $request->body = PatchOrder::buildRequestBody();
        $client->execute($request);
        $response = $client->execute(new OrdersGetRequest($orderId));
        print "Status Code: {$response->statusCode}\n";
        print "Status: {$response->result->status}\n";
        print "Order ID: {$response->result->id}\n";
        print "Intent: {$response->result->intent}\n";
        print "Links:\n";
        foreach($response->result->links as $link)
        {
            print "\t{$link->rel}: {$link->href}\tCall Type: {$link->method}\n";
        }
        print "Gross Amount: {$response->result->purchase_units[0]->amount->currency_code} {$response->result->purchase_units[0]->amount->value}\n";
        // To toggle printing the whole response body comment/uncomment below line
        echo json_encode($response->result, JSON_PRETTY_PRINT), "\n";
    }

    /*
    *
    * Build sample PATCH request
    */
    private static function buildRequestBody()
    {
        return array (
            0 =>
                array (
                    'op' => 'replace',
                    'path' => '/intent',
                    'value' => 'CAPTURE',
                ),
            1 =>
                array (
                    'op' => 'replace',
                    'path' => '/purchase_units/@reference_id==\'PUHF\'/amount',
                    'value' =>
                        array (
                            'currency_code' => 'USD',
                            'value' => '200.00',
                            'breakdown' =>
                                array (
                                    'item_total' =>
                                        array (
                                            'currency_code' => 'USD',
                                            'value' => '180.00',
                                        ),
                                    'tax_total' =>
                                        array (
                                            'currency_code' => 'USD',
                                            'value' => '20.00',
                                        ),
                                ),
                        ),
                ),
        );
    }
}

if (!count(debug_backtrace()))
{
    print "Before PATCH:\n";
    $createdOrder = CreateOrder::createOrder(true)->result;
    print "\nAfter PATCH (Changed Intent and Amount):\n";
    PatchOrder::patchOrder($createdOrder->id);
}
# 1. Import the PayPal SDK client that was created in `Set up the Server SDK`.
from sample import PayPalClient
from paypalcheckoutsdk.orders import OrdersPatchRequest, OrdersGetRequest
import json

class PatchOrder(PayPalClient):

    #2. Set up your server to receive a call from the client
    def patch_order(self, order_id):
        """Method to patch order"""
        request = OrdersPatchRequest(order_id)
        request.request_body(self.build_request_body())
        #3. Call PayPal to patch the transaction
        self.client.execute(request)
        response = self.client.execute(OrdersGetRequest(order.id))
        print 'Order ID: ', response.result.id
        print 'Intent: ', response.result.intent
        print 'Links:'
        for link in response.result.links:
            print('\t{}: {}\tCall Type: {}'.format(link.rel, link.href, link.method))
        print 'Gross Amount: {} {}'.format(response.result.purchase_units[0].amount.currency_code,
                                           response.result.purchase_units[0].amount.value)
        json_data = self.object_to_json(response.result)
        print "json_data: ", json.dumps(json_data,indent=4)

    @staticmethod
    def build_request_body():
        """Method to create body for patching the order. Returns a list of patches."""
        return \
            [
                {
                    "op": "replace",
                    "path": "/intent",
                    "value": "CAPTURE"
                },
                {
                    "op": "replace",
                    "path": "/purchase_units/@reference_id=='PUHF'/amount",
                    "value": {
                        "currency_code": "USD",
                        "value": "200.00",
                        "breakdown": {
                            "item_total": {
                                "currency_code": "USD",
                                "value": "180.00"
                            },
                            "tax_total": {
                                "currency_code": "USD",
                                "value": "20.00"
                            }
                        }
                    }
                }
            ]

if __name__ == "__main__":
    PatchOrder().patch_order('REPLACE-WITH-VALID-ORDER-ID')
# 1. Import the PayPal SDK client that was created in `Set up the Server SDK`.
require_relative '../paypal_client'

include PayPalCheckoutSdk::Orders

module Samples
  class PatchOrder

    #2. Set up your server to receive a call from the client
    # Use this function to patch an order.
    # PATCH is supported for a specific set of fields.
    # Refer to the Orders API reference for more information.
    def patch_order(order_id)
      body = [{
        op:'replace',
        path:"/purchase_units/@reference_id=='PUHF'/description",
        value:'Sporting goods description'
      },
      {
        op: 'replace',
        path: "/purchase_units/@reference_id=='PUHF'/custom_id",
        value: 'CUST-ID-HighFashions'
        }
      ]
      request = OrdersPatchRequest::new(order_id)
      request.request_body(body)
      #3. Call PayPal to patch the transaction
      response = PayPalClient::client::execute(request)
      return response
    end
  end
end

# Driver function that calls the PATCH order
if __FILE__ == $0
  begin
    patch_response = Samples::PatchOrder::new::patch_order('REPLACE-WITH-VALID-ORDER-ID')
  end
end
package com.paypal;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONObject;

import com.braintreepayments.http.HttpResponse;
import com.braintreepayments.http.serializer.Json;
import com.paypal.orders.AmountBreakdown;
import com.paypal.orders.AmountWithBreakdown;
import com.paypal.orders.LinkDescription;
import com.paypal.orders.Money;
import com.paypal.orders.Order;
import com.paypal.orders.OrdersGetRequest;
import com.paypal.orders.OrdersPatchRequest;
import com.paypal.orders.Patch;

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

    //2. Set up your server to receive a call from the client
    /**
     * Method to patch order
     *
     * @throws IOException Exceptions from API, if any
     */
    public void patchOrder(String orderId) throws IOException {
        OrdersPatchRequest request = new OrdersPatchRequest(orderId);
        request.requestBody(buildRequestBody());
        client().execute(request);
        OrdersGetRequest getRequest = new OrdersGetRequest(orderId);
        //3. Call PayPal to patch the transaction
        HttpResponse<Order> response = client.execute(getRequest);
        System.out.println("After Patch:");
        System.out.println("Order ID: " + response.result().id());
        System.out.println("Intent: " + response.result().intent());
        System.out.println("Links: ");
        for (LinkDescription link : response.result().links()) {
            System.out.println("\t" + link.rel() + ": " + link.href() + "\tCall Type: " + link.method());
        }
        System.out.println("Gross Amount: " + response.result().purchaseUnits().get(0).amount().currencyCode() + " "
                + response.result().purchaseUnits().get(0).amount().value());
        System.out.println("Full response body:");
        System.out.println(new JSONObject(new Json().serialize(response.result())).toString(4));
    }

    /**
     * Method to create body for patching the order.
     *
     * @return List<Patch> list of patches to be made
     * @throws IOException
     */
    private List<Patch> buildRequestBody() throws IOException {
        List<Patch> patches = new ArrayList<>();
        patches.add(new Patch().op("replace").path("/intent").value("CAPTURE"));
        patches.add(new Patch().op("replace").path("/purchase_units/@reference_id=='PUHF'/amount")
                .value(new AmountWithBreakdown().currencyCode("USD").value("200.00")
                        .breakdown(new AmountBreakdown().itemTotal(new Money().currencyCode("USD").value("180.00"))
                                .taxTotal(new Money().currencyCode("USD").value("20.00")))));
        return patches;
    }

    public static void main(String[] args) throws IOException {
        new PatchOrder().patchOrder("REPLACE-WITH-VALID-ORDER-ID");
    }
}
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

//1. Import the PayPal SDK client that was created in `Set up the Server SDK`.
using BraintreeHttp;
using PayPalCheckoutSdk.Core;
using PayPalCheckoutSdk.Orders;

namespace Samples
{
    public class PatchOrderSample
    {

        //2. Set up your server to receive a call from the client
        /*
            Use this method to patch an order by passing the order ID.
         */
        public async static Task<HttpResponse> PatchOrder(string orderId, bool debug = false)
        {
            var request = new OrdersPatchRequest<Object>(orderId);
            request.RequestBody(BuildPatchRequest());
            //3. Call PayPal to patch the transaction
            var response = await PayPalClient.client().Execute(request);
            if(debug)
            {
                var ordersGetRequest= new OrdersGetRequest(orderId);
                response = await PayPalClient.client().Execute(ordersGetRequest);
                var result = response.Result<Order>();
                Console.WriteLine("Retrieved Order Status After Patch");
                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);
                }
                AmountWithBreakdown amount = result.PurchaseUnits[0].Amount;
                Console.WriteLine("Total Amount: {0} {1}", amount.CurrencyCode, amount.Value);
                Console.WriteLine("Response JSON: \n {0}", PayPalClient.ObjectToJSONString(result));
            }
            return response;
        }

         /**
            Use this method to build the PATCH request body.
         */
         private static List<Patch<Object>> BuildPatchRequest()
         {
             var patches = new List<Patch<Object>>
             {
                 new Patch<Object>
                 {
                     Op= "replace",
                     Path= "/intent",
                     Value= "CAPTURE"

                 },
                 new Patch<Object>
                 {
                     Op= "replace",
                     Path= "/purchase_units/@reference_id=='PUHF'/description",
                     Value= "Physical Goods"

                 }

             };
             return patches;
         }

        /*
            This driver method invokes the patchOrder function with order ID
            to patch an order details.

            To get the new order ID, the sample uses createOrder to create a new order
            and then uses the newly-created order ID.
         */
         static void Main(string[] args)
         {
             PatchOrder("REPLACE-WITH-VALID-ORDER-ID", true).Wait();
         }
    }

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

3. Test and go live

Follow the steps in the basic integration to test your integration and go live.