Looking for the old docs? View our old docs site.

Tracking Guide

This guide will teach you the two ways to track packages with EasyPost.

There's two methods of tracking packages with EasyPost:

  • Provide your existing tracking number and carrier.
  • Purchase the shipping label with EasyPost, which includes a free Tracker.

Our tracking service uses webhooks to give you updates about your shipments. Refer to our webhooks guide to learn how we use webhooks to send you tracking updates.

Before You Start

  1. Sign up for an EasyPost account or log in to an existing account.
  2. Setup your webhook URLs for Test Mode and Production Mode.
  3. Grab one of our official client libraries.
  4. Choose the "Step 1" that is applicable to you:

If you haven't run through our Getting Started Guide, definitely do that before moving on to this one.


Step 1: Create a Tracker using your tracking code & carrier

To track a shipment not created with EasyPost, you simply need to create a Tracker Object. You need to pass the "tracking_code" and "carrier" to the API. The "carrier" attribute is optional, though it is best to pass it if you have it available. When the "carrier" attribute is not passed, we will auto-detect the carrier for you. If we are unable to match the tracking code to a specific carrier, we will return an error.

Here is an example of how to make a tracker object:

Creating a Tracker

POST /trackers
1curl -X POST https://api.easypost.com/v2/trackers \
2  -u "EASYPOST_API_KEY": \
3  -H 'Content-Type: application/json' \
4  -d '{
5    "tracker": {
6      "tracking_code": "EZ1000000001",
7      "carrier": "USPS"
8    }
9  }'

After a Tracker is created, we will periodically check the status of your package and notify you when its status changes. Jump to Step 2 to learn how we'll give you updates via webhooks.


Step 1: Purchase a Shipping Label and Tracking Code

To start tracking a package, there is nothing extra you need to do. Whenever you purchase a shipping label with EasyPost, we'll start automatically tracking its progress and notifying you of any updates via webhooks (more on that in step 2).

When you purchase a shipping label, we will also respond back with the tracking number for the label. You don't need to store the tracking number to get tracking updates but it is generally good practice to store it. Here's an example of purchasing a shipping label and getting a tracking number. To see all the steps for shipping a package, take a look at our Getting Started Guide.

Buying Shipment

POST /shipments/:id/buy
1curl -X POST https://api.easypost.com/v2/shipments/shp_.../buy \
2  -u "EASYPOST_API_KEY": \
3  -H 'Content-Type: application/json' \
4  -d '{
5    "rate": {
6      "id": "rate_..."
7    },
8    "insurance": "249.99"
9  }'

Step 2: Process Tracking Event Webhooks

After you purchase a shipping label or create a tracker, we will automatically start sending tracking update Events. Event Objects are sent to the webhook URLs you've configured. Updates will be sent whenever there are new details associated with the tracker. We check the status of each package more frequently once it is Out for Delivery.

The Tracker Object statuses are listed in our API Documentation.

When you purchase a label in either Test or Production mode, you will immediately get a tracking event after purchase. Test and Production mode behave slightly differently:

  • In Test Mode, you will get only one tracking event in one of the supported statuses (e.g. "in_transit", "delivered", etc.). After this update, you receive no more events in Test mode.
  • In Production Mode, you will get your first of multiple tracking events for your package. The first tracking event is status "unknown". The package stays in "unknown" until it is scanned by the carrier.

You'll know it is a tracking update event because the object "type" is "Event" and the "description" is "tracker.updated". The "result" value of Event will also contain a Tracker object that has the information about the current progress of the package. When building application logic, the "status" of Tracker object is most useful and reliable to use.

The Tracker object also contains additional information from the carrier in "tracking_details" attribute. For example, along with "in_transit" updates you may receive information that it reached a particular location (eg "Processed through Sort Facility June 01 2013 4:53 pm BELL GARDENS CA 9020"). The "tracking_details" will be an array containing both details about the current status and all previous statuses. The oldest status is the first element of the array and we append newer statuses as they come in. Order is not perfectly reliable as carrier data is occasionally incorrect. We recommend using the "status" on the Tracker object for any key business logic.

Here's an example of a tracking event webhook:

{
  "id": "evt_...",
  "object": "Event",
  "created_at": "2014-11-19T10:51:54Z",
  "updated_at": "2014-11-19T10:51:54Z",
  "description": "tracker.updated",
  "mode": "test",
  "previous_attributes": {
    "status": "unknown"
  },
  "pending_urls": [],
  "completed_urls": [],
  "result": {
    "id": "trk_...",
    "object": "Tracker",
    "mode": "test",
    "tracking_code": "EZ4000000004",
    "status": "delivered",
    "created_at": "2014-11-18T10:51:54Z",
    "updated_at": "2014-11-19T10:51:54Z",
    "signed_by": "John Tester",
    "weight": 17.6,
    "est_delivery_date": "2014-11-27T00:00:00Z",
    "shipment_id": null,
    "carrier": "UPS",
    "public_url": "https://track.easypost.com/djE7...",
    "tracking_details": [
      {
        "object": "TrackingDetail",
        "message": "BILLING INFORMATION RECEIVED",
        "status": "pre_transit",
        "datetime": "2014-11-21T14:24:00Z",
        "tracking_location": {
          "object": "TrackingLocation",
          "city": null,
          "state": null,
          "country": null,
          "zip": null
        }
      },
      {
        "object": "TrackingDetail",
        "message": "ORIGIN SCAN",
        "status": "in_transit",
        "datetime": "2014-11-21T14:48:00Z",
        "tracking_location": {
          "object": "TrackingLocation",
          "city": "SOUTH SAN FRANCISCO",
          "state": "CA",
          "country": "US",
          "zip": null
        }
      },
      {
        "object": "TrackingDetail",
        "message": "DEPARTURE SCAN",
        "status": "in_transit",
        "datetime": "2014-11-22T08:51:00Z",
        "tracking_location": {
          "object": "TrackingLocation",
          "city": "SOUTH SAN FRANCISCO",
          "state": "CA",
          "country": "US",
          "zip": null
        }
      },
      {
        "object": "TrackingDetail",
        "message": "ARRIVAL SCAN",
        "status": "in_transit",
        "datetime": "2014-11-23T09:31:00Z",
        "tracking_location": {
          "object": "TrackingLocation",
          "city": "SAN FRANCISCO",
          "state": "CA",
          "country": "US",
          "zip": null
        }
      },
      {
        "object": "TrackingDetail",
        "message": "OUT FOR DELIVERY",
        "status": "out_for_delivery",
        "datetime": "2014-11-24T08:10:00Z",
        "tracking_location": {
          "object": "TrackingLocation",
          "city": "SAN FRANCISCO",
          "state": "CA",
          "country": "US",
          "zip": null
        }
      },
      {
        "object": "TrackingDetail",
        "message": "DELIVERED",
        "status": "delivered",
        "datetime": "2014-11-19T10:51:54Z",
        "tracking_location": {
          "object": "TrackingLocation",
          "city": "SAN FRANCISCO",
          "state": "CA",
          "country": "US",
          "zip": null
        }
      }
    ]
  }
}

Step 3: Engage With Your Customers

Once you're receiving webhooks, there's a lot of ways for you to re-engage with your customers. Here's a few ideas that some of our customers use:

Tracking Details Web

Congratulations! You've just purchased a carbon offset with EasyPost! Check out our Full Reference API Documentation for more details.