# Track a shipment in real-time

## Overview

Tracking a shipment in real time on your platform consists of creating an object to track the shipment and setting up an endpoint for webhooks.

Kublau uses this tracking object, called a **Tracker**, to track and handle all the states of the shipment until it’s delivered.

The tracker will be updated periodically based on when the carrier provides Kublau with new tracking information. This information can be consumed by using our [webhooks](https://docs.kublau.com/kublau-docs/api/webhooks).

## Get our GraphQL Playground running

To follow along the the steps in this guide we'll provide an interactive environment for Ruby, Python and Node. You can also use GraphQL directly with our [GraphQL Playground](https://docs.kublau.com/kublau-docs/api/playground).

## **Create a Tracker using your tracking code & carrier**

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

{% tabs %}
{% tab title="GraphQL" %}

```graphql
mutation trackerCreate($input: TrackerCreateInput!) {
  trackerCreate(input: $input) {
    tracker {
      id
      trackingCode
      status
      estimatedDeliveryAt
      deliveredAt
      carrier
      checkpoints {
        id
        message
        status
        scannedAt
      }
    }
    trackerUserErrors {
      code
      message
      field
    }
  }
}
```

{% endtab %}

{% tab title="GraphQL Query Variables" %}

```javascript
{
  "input": {
    "trackingCode": "K1000000003",
    "carrier": "ESTAFETA",
    "async": false
  }
}
```

{% endtab %}

{% tab title="Ruby" %}
[Run Ruby example on online REPL.](https://repl.it/@pabloco/Tracking-a-shipment-Ruby)
{% endtab %}

{% tab title="Python" %}
[Run Python example on online REPL.](https://repl.it/@pabloco/Tracking-a-shipment-Python)
{% endtab %}

{% tab title="Node" %}
[Run Node example on online REPL](https://repl.it/@pabloco/Tracking-a-shipment-Nodejs).
{% endtab %}
{% endtabs %}

```javascript
{
  "data": {
    "trackerCreate": {
      "tracker": {
        "id": "gid://kublau/Tracker/1592e6a0-7679-43aa-bc24-9b51960fbdc6",
        "trackingCode": "K1000000003",
        "status": "IN_TRANSIT",
        "estimatedDeliveryAt": null,
        "deliveredAt": null,
        "carrier": "ESTAFETA",
        "checkpoints": [
          {
            "id": "gid://kublau/Checkpoint/c23c60b2-7c53-41da-901a-70c9a2e56f4b",
            "message": "Desconocido",
            "status": "UNKNOWN",
            "scannedAt": "2020-05-20T19:56:46-05:00"
          },
          {
            "id": "gid://kublau/Checkpoint/dee3510f-59fa-4b3e-8f24-c005b012a997",
            "message": "Pendiente",
            "status": "PENDING",
            "scannedAt": "2020-05-21T00:56:46-05:00"
          },
          {
            "id": "gid://kublau/Checkpoint/27abb796-5c7f-4dd0-b37e-d05796625937",
            "message": "Recogido",
            "status": "PICKED_UP",
            "scannedAt": "2020-05-21T05:56:46-05:00"
          },
          {
            "id": "gid://kublau/Checkpoint/e5b8fcb5-f56a-4281-9d2d-6549ac96d6d3",
            "message": "En transito",
            "status": "IN_TRANSIT",
            "scannedAt": "2020-05-21T10:56:46-05:00"
          }
        ]
      },
      "trackerUserErrors": []
    }
  }
}
```

The **Tracker** object contains both the current information about the package as well as previous updates. All of the previous updates are stored in the `checkpoints` array. Each **Checkpoint** object contains the `status`, the `message` from the carrier and the scan time.

### Tracking status values

The `status` field in Tracker can have several values. Below is a list of these statuses with an explanation.

{% content-ref url="tracking-a-shipment-in-real-time/tracker-tracking-status" %}
[tracker-tracking-status](https://docs.kublau.com/kublau-docs/guides/tracking-a-shipment-in-real-time/tracker-tracking-status)
{% endcontent-ref %}

### Test Tracking Codes

Sometimes you may want to simulate specific tracking *statuses* (e.g. `OUT_FOR_DELIVERY`) within your application to test how your application responds. Kublau has a set of test tracking codes that, when sent to the API, respond with specific tracking `statuses`. The information that are sent by these test trackers will contain canned information.

{% hint style="info" %}
These testing tracking codes will only work using a test API Key.
{% endhint %}

| Tracking Code | Status                 |
| ------------- | ---------------------- |
| K1000000000   | UNKNOWN                |
| K1000000001   | PENDING                |
| K1000000002   | PICKED\_UP             |
| K1000000003   | OUT\_FOR\_DELIVERY     |
| K1000000004   | IN\_TRANSIT            |
| K1000000005   | DELIVERED              |
| K1000000006   | AVAILABLE\_FOR\_PICKUP |
| K1000000007   | RETURN\_TO\_SENDER     |
| K1000000008   | ATTEMPT\_FAILURE       |

## **Creating trackers in sync/async mode**

Trackers are by default created in async mode if the `async` argument for `trackerCreate` is empty. We list their differences in the following table:

| trackerCreate mode     | Sync mode                                                                                    | Async mode                                                                                                                                                                                                                                                                                                                          |
| ---------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The API returns        | A full up-to-date view of the tracker                                                        | An empty tracker with UNKNOWN status                                                                                                                                                                                                                                                                                                |
| API Response time      | Varies per carrier. Most carriers will see 15 to 30 seconds.                                 | From a hundred milliseconds to a couple of seconds.                                                                                                                                                                                                                                                                                 |
| API async value        | "async": false                                                                               | "async": true or leave empty (default value is true).                                                                                                                                                                                                                                                                               |
| When to use?           | When you care about the value of certain attribute of the tracker in the response right now. | <ul><li>When you don't care about the information of the tracker in the response right now.</li><li>When you only want Kublau to start tracking this shipment for you.</li><li>When you are okay with waiting for that information on a webhook. (2 mins avg. to first TRACKER\_UPDATE webhook after trackerCreate call).</li></ul> |
| Sends update webhooks? | Yes                                                                                          | Yes                                                                                                                                                                                                                                                                                                                                 |

## **Process Tracking Event Webhooks**

After you create a tracker, we will automatically start sending `TRACKER_UPDATED` events. Event Objects are sent to the webhook URLs you’ve configured. Updates will only be sent when there is a status change for the package (e.g. a package changes from "Out for Delivery" to "Delivered").

You’ll know it is a tracking update event because the **topic** is `TRACKER_UPDATED`. The `data` value of Event will 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.

### Create a webhook endpoint

Add a new endpoint in your application. You can act on certain events by checking the `type` field of the event object sent in the request body.

We include example webhook implementations so you can follow along:

{% tabs %}
{% tab title="Ruby" %}
[Run Ruby example on online REPL.](https://repl.it/@pabloco/Webhook-endpoint-Ruby)
{% endtab %}

{% tab title="Python" %}
[Run Python example on online REPL.](https://repl.it/@pabloco/Webhook-endpoint-Python)
{% endtab %}

{% tab title="Node" %}
[Run Node example on online REPL](https://repl.it/@pabloco/Webhook-endpoint-Node).
{% endtab %}
{% endtabs %}

{% hint style="info" %}
You can get the **REPL's public URL** for testing on the top right side of editor. It should look something like: **`https://Webhook-endpoint-LANG--USERNAME.repl.co`**.

Then, you need to append the **`/webhook`** path at the end:**`https://Webhook-endpoint-LANG--USERNAME.repl.co/webhook`**
{% endhint %}

### Create a webhook on our Dashboard

You can configure your webhooks using the Kublau dashboard:

1. From your Kublau dashboard, go to **Settings** > **Developer**.
2. In the **Webhooks** section, click **Create a webhook**.
3. Input the URL where you want to receive notifications. Which if you're following along is the [REPL's public URL](#create-a-webhook-endpoint).
4. Select the `TRACKER_UPATED` topic.

After you've created a webhook, you're presented with a secret to [validate its authenticity](https://docs.kublau.com/kublau-docs/api/webhooks#verifying-webhooks).

### Testing webhooks <a href="#testing-webhooks" id="testing-webhooks"></a>

For testing webhooks, you can use:

* Any of the language specific [REPL's above](#create-a-webhook-endpoint).
* Run a local server
* Use a publicly available service such as [Beeceptor](https://beeceptor.com/).

If you decide to run a server locally, then you need to make it publicly available using a service such as [**Pagekite**](https://pagekite.net/) or [**ngrok**](https://ngrok.com/). The following URLs do not work as endpoints for webhooks:

* Localhost
* Internal network
* Domains like `www.example.com`
* Kublau domains such as `kublau.com` and `api.kublau.com`

To test your webhook from the Kublau dashboard:

1. Go to the **Webhooks** section in **Settings** > **Developer**.
2. Click the **Test** button next to the webhook that you want to test.
3. Select the `TRACKER_UPDATED` **topic**.

An example webhook is sent to the configured webhook URL.

## Deploy your webhook endpoint

When you are ready to deploy your webhook endpoint to production there are a couple things you need to do:

1. Use your live mode API keys and not your test mode keys.
2. Configure your production webhook endpoint in the Dashboard.

That’s it! Your application is ready to accept live updates for a shipment. For more information [about our webhooks](https://docs.kublau.com/kublau-docs/api/webhooks).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.kublau.com/kublau-docs/guides/tracking-a-shipment-in-real-time.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
