Introduction

The PayPal Tracking API a robust, simple to use API for adding and updating shipment tracking details to PayPal transactions.

With over 325 million active users worldwide, PayPal is currently the largest online payment system provider.

PayPal supports over 200+ countries and facilitates online payment transfer between two parties that may be located across the world.

PayPal also provides a plethora of features that are built around making the system safer and easier to use.

One such service is, being able to add shipment tracking information to a PayPal transaction, which offers peace of mind to buyers by allowing tracking for their orders.

This is also very important for sellers in order to avoid potential funding holds by PayPal.  They will often use tracking and delivery confirmation to release funds that are being held.  Without PayPal tracking available, your funds could be held for a longer period of time.

To make this feature more accessible for merchants and their custom applications, PayPal recently introduced a REST API interface to add, update, or fetch tracking data related to a transaction.

In this tutorial, we will see how easy it is to integrate the PayPal Tracking API in PHP application.

Are You Using WooCommerce?

If so, then you don’t have to write a single line of code. Simplify this process with our PayPal for WooCommerce Shipment Tracking plugin!

Before You Get Started

To properly follow along with this tutorial, I highly suggest you to set-up a sandbox account for PayPal and create a PayPal application linked to your sandbox seller account.

PayPal Tracking API Access Token

An Access token is your gate pass to PayPal’s REST API and it is used to authenticate users who are trying to access the PayPal API.

Client ID and Secret:

To get the access token we need to make a POST request to api.sandbox.paypal.com/v1 with our PayPal application’s client_id and secret.

If you have created a PayPal app as suggested earlier, you will find the client_id and secret in your application’s detail page.

PayPal Tracking API in PHP -Paypal Client ID and Secret Optimized

Note down both the Client Id and Secret somewhere safe as we will be needing them shortly.

Fetch Access Token Using Curl and PHP:

Curl is a library that is used to make HTTP requests in PHP.

As curl comes bundled with a standard PHP installation, we will be using curl to make HTTP requests.

We can get an access token from PayPal Tracking API using the Client Id and Secret.

 

/**
* fetch_access_token.php
* Fetch Access / Bearer Token from PayPal
*/


$curl = curl_init();

$url = "https://api.sandbox.paypal.com/v1/oauth2/token";
$clientId = "your client Id";
$secret = "your secret key";

curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
//We need to send grant_type=client_credentials in POST Request Body
CURLOPT_POSTFIELDS => "grant_type=client_credentials",
//Setting Basic Authentication using Client ID and Secret
CURLOPT_USERPWD => $clientId.":".$secret,
// This specific header needs to be set for the API call to work
CURLOPT_HTTPHEADER => array("Content-Type: application/x-www-form-urlencoded"),)
); 

//make API request
$result = curl_exec($curl);

//close connection
curl_close($curl);

//convert json response into PHP associative array
$response = json_decode($result, true);

echo $response['access_token'];


 

Explanation:

The piece of code displayed above fetches the access token by:

  1. Using the curl_setopt_array() function to build a custom curl object that will be used to make the API call.
  2. The custom curl object specifies that we are making a POST request with our Client Id and Secret as the username and password to authenticate ourselves.
  3. We also need to pass a grant_type field as a request parameter with the value set to client_credentials. This field authenticates our request for the access token.
  4. I also observed that the PayPal API fails to recognize our request parameters if the content-type of the request is not set to application/x-www-form-urlencoded.
  5. We then, finally, execute the API request by calling curl_exec().
Output:

Go ahead and execute the code in a terminal by running php fetch_access_token.php.

The output should be something similar to the result shown below.

$ php fetch_access_token.php
A21AAHaObeWnZI27tYFAEsV5CeA24GZfY2Fay2o5GIzgp7WlKrs2zEPG4Ja1LAl81KpCUb6eudTg-WNQc3QLMma_o7nAL2E5g

PayPal Tracking API Needs Transaction IDs

To proceed further in this tutorial, you will need the transaction IDs to which we will add tracking formation.

Now, if you’re looking to add tracking for your transactions, I assume that you already have a system in place to fetch these transaction IDs.

If not, then you can use the Transaction Search API provided by PayPal.

Transactions on your PayPal account can be fetched by making a GET request to api.sandbox.paypal.com/v1/reporting/transactions.

Here is an example; you can adapt this example to fit your specific implementation.

/**
 * fetch_transactions_list.php
* Fetch A List of all transactions */ //start date to filter transactions from $start_date = '2020-05-01T00:00:00-0700'; //end date to filter transactions from $end_date = '2020-05-30T23:59:59-0700'; //The access token we obtained in the previous sections $access_token = 'your access token'; $curl = curl_init(); /** * Build custom Curl Object */ curl_setopt_array($curl, array( CURLOPT_URL => "https://api.sandbox.paypal.com/v1/reporting/transactions?start_date={$start_date}&end_date={$end_date}", CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => "", CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_HTTPHEADER => array( "Authorization: Bearer {$access_token}" ), )); $response = curl_exec($curl); curl_close($curl); echo $response;
Explanation:

The PayPal Transaction Search API is quite intuitive and easy to use.

You only need three things to fetch transactions on your account:

  1. Start Date: The starting date from which the API filters records. The date should be in ISO 8601 format.
  2. End Date: The API tries to fetch all records before this date. Note that the difference in the start date and end date should not be more than 30 days.
  3. Access Token: The access token that we obtained in the previous section needs to be passed as an Authorization header with the HTTP request.
Output:

If you run php fetch_transactions_list.php, you should see the transaction_id of each transaction listed in the output.

$ php fetch_transactions_list.php | jq
{
  "transaction_details": [
    {
      "transaction_info": {
        "paypal_account_id": "YPMA23MQQ4RJ6",
        "transaction_id": "5XY08023GD049274R",
        "transaction_event_code": "T0000",
        "transaction_initiation_date": "2020-05-18T13:04:08+0000",
        "transaction_updated_date": "2020-05-18T13:04:08+0000",
        "transaction_amount": {
          "currency_code": "USD",
          "value": "500.00"
        },
        "fee_amount": {
          "currency_code": "USD",
          "value": "-14.80"
        },
        "transaction_status": "S",
        "ending_balance": {
          "currency_code": "USD",
          "value": "5533.45"
        },
        "available_balance": {
          "currency_code": "USD",
          "value": "5533.45"
        },
        "protection_eligibility": "01"
      }
    }
  ],
  "account_number": "LS7T79XPW3766",
  "start_date": "2020-05-01T07:00:00+0000",
  "end_date": "2020-05-19T00:59:59+0000",
  "last_refreshed_datetime": "2020-05-19T00:59:59+0000",
  "page": 1,
  "total_items": 3,
  "total_pages": 1,
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v1/reporting/transactions?start_date=2020-05-01T00%3A00%3A00-0700&end_date=2020-05-30T23%3A59%3A59-0700&page_size=100&page=1",
      "rel": "self",
      "method": "GET"
    }
  ]
}

Add Tracking Information to a PayPal Transaction

Now that we have an access token and transaction Ids, we can start adding tracking information to our transactions.

The tracking data should contain the following information:

  1. Transaction ID: The PayPal Transaction ID is a mandatory field that you need to pass.
  2. Tracking Number: The tracking number of the shipment. You can exclude this if you don’t have a tracking number.
  3. Status: Refers to the current state of the shipment. The most common values are SHIPPED, ON_HOLD, DELIVERED, CANCELLED.
  4. Carrier: The carrier of shipment. For Example, FedEx, DHL, etc. PayPal recognizes over 100+ carriers from around the world. Check out the supported carriers here.

I’ve gone ahead and created a transaction by sending some money from my buyer account to my merchant account.

New Transaction

We will take this transaction as an example to add, update, and view tracking information.

PayPal Tracking API exposes the /v1/shipping/trackers-batch API endpoint, using which you can add tracking information for multiple transactions in one go.

Note that, for the request to succeed, we need to make a POST request with the required input parameters.

/**
 * File: add_tracking_info.php
 * Add tracking information to one or more transactions
 */


$curl = curl_init();

//API Endpoint
$url = 'https://api.sandbox.paypal.com/v1/shipping/trackers-batch';

//tracking info
$tracker = array( 'transaction_id' => '5XY08023GD049274R',
                  'tracking_number' => '443844607698',
                  'status' => 'SHIPPED',
                  'carrier' => 'FEDEX');

// The trackers array, the API can handle multiple transactions at a time.
$trackers = array('trackers' => array($tracker));

$access_token = 'your access token';

curl_setopt_array($curl, array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "POST",
    CURLOPT_POSTFIELDS => json_encode($trackers),
    CURLOPT_HTTPHEADER => array(
    "Authorization: Bearer {$access_token}",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);

curl_close($curl);

echo $response;
Explanation:

In the example shown above, we build an array of arrays ($trackers) filled with one or more tracker objects and pass the $trackers array in JSON format with the request.

Also, note that we specify our curl object to make a POST request, and indicate that the content being passed is JSON by using the Content-type header field.

Most importantly, we also pass our access token with the Authorization header in the request.

 

Output:

Note that the API response contains a links section that has endpoints for viewing (GET) and updating (PUT) the tracking information we just created.

We will be using this GET and PUT APIs in the upcoming sections.

Also, the API returns a 201 CREATED status code on successful execution.

Any other status code implies a failure, and the error message will be available in the $response object.

$ php add_tracking_info.php | jq
{
  "tracker_identifiers": [
    {
      "transaction_id": "5XY08023GD049274R",
      "tracking_number": "443844607698",
      "links": [
        {
          "href": "https://api.sandbox.paypal.com/v1/shipping/trackers/5XY08023GD049274R-443844607698",
          "rel": "self",
          "method": "GET",
          "encType": "application/json"
        },
        {
          "href": "https://api.sandbox.paypal.com/v1/shipping/trackers/5XY08023GD049274R-443844607698",
          "rel": "replace",
          "method": "PUT",
          "encType": "application/json"
        }
      ]
    }
  ],
  "errors": [],
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v1/shipping/trackers-batch",
      "rel": "self",
      "method": "POST",
      "encType": "application/json"
    }
  ]
}

If you go look at the specific transaction on the PayPal website, you should see the newly added tracking information show up.

Tracking Added

View Tracking Information

After adding the tracking information to our transaction, we can now fetch it using the GET API endpoint we got during the previous section.

The PayPal Tracking GET API is in the format api.sandbox.paypal.com/v1/shipping/trackers/{transaction_id}-{tracking_number}.

Needless to say, we will be making a GET request this time.


/**
 * File: fetch_tracking_information.php
 * Fetch tracking information related to a transaction
 */

$curl = curl_init();

$access_token = 'your access token';


curl_setopt_array($curl, array(
    CURLOPT_URL => "https://api.sandbox.paypal.com/v1/shipping/trackers/5XY08023GD049274R-443844607698",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
    CURLOPT_HTTPHEADER => array(
    "Authorization: Bearer {$access_token}"
  ),
));

$response = curl_exec($curl);

curl_close($curl);

echo $response;

Explanation:

The code snippet displayed above is a simple one.

It makes a GET request to api.sandbox.paypal.com/v1/shipping/trackers/{transaction_id}-{tracking_number} and passes the access_token to authenticate the request.

Output:

The API response contains useful information such as tracking_number, carrier, status, and transaciton_id.

$ php fetch_tracking_information.php | jq
{
  "transaction_id": "5XY08023GD049274R",
  "tracking_number": "443844607698",
  "status": "SHIPPED",
  "carrier": "FEDEX",
  "notify_buyer": false,
  "links": [
    {
      "href": "https://api.sandbox.paypal.com/v1/shipping/trackers/5XY08023GD049274R-443844607698",
      "rel": "self",
      "encType": "application/json"
    },
    {
      "href": "https://api.sandbox.paypal.com/v1/shipping/trackers/5XY08023GD049274R-443844607698",
      "rel": "replace",
      "method": "PUT",
      "encType": "application/json"
    },
    {
      "href": "https://api.sandbox.paypal.com/v1/shipping/trackers-batch",
      "rel": "create",
      "method": "POST",
      "encType": "application/json"
    }
  ]
}

Update Tracking Information

To update tracking information related to a transaction, we need to make a PUT request to api.sandbox.paypal.com/v1/shipping/trackers/{transaction_number}-{tracking_id}.

Here, we can update the tracking_number, carrier, and status of the shipment. However, trying to update the transaction_number will simply not work.

/**
 * File: update_tracking_info.php
 * Add tracking information to one or more transactions
 */


$curl = curl_init();

//API Endpoint
$url = 'https://api.sandbox.paypal.com/v1/shipping/trackers/5XY08023GD049274R-443844607698';

//tracking info
$tracker = array( 'tracking_number' => '443844607698',
                  'status' => 'ON_HOLD',
                  'carrier' => 'FEDEX');

$access_token = 'your access token';

curl_setopt_array($curl, array(
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "PUT",
    CURLOPT_POSTFIELDS => json_encode($tracker),
    CURLOPT_HTTPHEADER => array(
    "Authorization: Bearer {$access_token}",
    "Content-Type: application/json"
  ),
));

$response = curl_exec($curl);

$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

curl_close($curl);

if ($httpCode === 204) {
    echo "\nTracking info updated\n";
} else {
    echo "\nThere was an error";
    echo $response;
}

Explanation:

The code sample presented above does the following:

  1. Builds an associative array ($tracker) that contains the key, value pairs of the information we’re trying to update.
  2. Adds an Authorization header field which includes our access token for authentication.
  3. Makes a PUT request to the update API endpoint.
  4. Finally, executes the HTTP request and checks for a response status code of 204 No Content, which signifies that the request was processed without any errors.
Careful when You Update the Tracking Number!

The format of the Tracking Update API is v1/shipping/trackers/{transaction_id}-{tracking_number}.

We can see that the URL is dynamic as it depends on a variable property, tracking_number.

Therefore, if you’re storing the URL somewhere like a database, whenever you update the tracking number, you also need to update your endpoint URL.

However, the ideal implementation is to always build the API endpoint dynamically using the transaction Id and tracking number.

Output:
$ php update_tracking_information.php

Tracking info updated

The update should immediately reflect in the merchant account as well.

Tracking Updated

Conclusion

We’re done! We saw how easy it is to integrate PayPal Tracking API in PHP.

Although PayPal Tracking API does not strictly conform to the RESTful standards (Dynamic resource URL?!), it sure is effortless to use.

The example shown here is a novel way of integrating the PayPal Tracking API in PHP.

However, it should form a solid base for you to understand the logic behind the integration process.

Feel free to share your thoughts or questions in the comment section below. I will try my best to answer them.

Need Additional Help?

Schedule a live meeting with Drew Angell, PayPal Certified Developer, and get all of your questions or concerns answered.