> ## Documentation Index
> Fetch the complete documentation index at: https://terminal49-mintlify-f6b8cc32.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# List Shipments and Containers

> List tracked shipments and containers via the Terminal49 API, filter results by status, and retrieve the tracking data your integration needs.

In this tutorial, you will list the shipment and container records created from your tracking requests.

Use this step after you have created at least one tracking request.

## Shipment and container data in Terminal49

After Terminal49 accepts a tracking request, it starts collecting available data from carriers and terminals. You can retrieve the latest stored data at any time with the Shipments and Containers endpoints.

Use these endpoints for on-demand lookups. For ongoing status monitoring, use webhooks instead of polling.

## Which object holds which field?

Tracking data is split across two resources. If you query the wrong endpoint you will not see the field you expect — for example, `pod_eta_at` is **not** returned by `GET /containers` because it lives on the shipment.

| Field                                                                    | Object      | Endpoint                                                                                                |
| ------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------- |
| `pod_eta_at` — current ETA at the port of discharge                      | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `pod_original_eta_at` — first ETA reported by the carrier                | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `destination_eta_at` — ETA at the final destination (carrier view)       | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `pod_ata_at` — actual arrival at the port of discharge                   | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `bill_of_lading_number`                                                  | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `port_of_lading_name` / `port_of_discharge_name`                         | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `shipping_line_scac` / `shipping_line_name`                              | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `ref_numbers`                                                            | `shipment`  | `GET /shipments/{id}`                                                                                   |
| `number` — container number                                              | `container` | `GET /containers/{id}`                                                                                  |
| `pod_arrived_at` / `pod_discharged_at`                                   | `container` | `GET /containers/{id}`                                                                                  |
| `pod_full_out_at` — gated out of the port terminal                       | `container` | `GET /containers/{id}`                                                                                  |
| `empty_terminated_at` — empty returned                                   | `container` | `GET /containers/{id}`                                                                                  |
| `pickup_lfd` — last free day                                             | `container` | `GET /containers/{id}`                                                                                  |
| `holds_at_pod_terminal` / `fees_at_pod_terminal`                         | `container` | `GET /containers/{id}`                                                                                  |
| `available_for_pickup` / `availability_known`                            | `container` | `GET /containers/{id}`                                                                                  |
| `ind_eta_at` / `ind_ata_at` — rail carrier ETA/ATA at inland destination | `container` | `GET /containers/{id}` (see [Rail integration guide](/api-docs/in-depth-guides/rail-integration-guide)) |

### Fetching shipment fields alongside a container

If you already have a container ID (or are filtering by container number) and want the shipment ETA fields in the same response, use the `include` query parameter to embed the related shipment:

```bash theme={null}
curl "https://api.terminal49.com/v2/containers/{id}?include=shipment" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Authorization: Token YOUR_API_KEY"
```

The shipment record — including `pod_eta_at`, `pod_original_eta_at`, and `destination_eta_at` — is returned in the top-level `included` array. See [Include related resources](/api-docs/in-depth-guides/including-resources) for the full syntax.

## Authentication

As in the previous steps, every request sends your API key in the `Authorization` header:

```http theme={null}
Authorization: Token YOUR_API_KEY
```

If you don't have an API key yet, get one from the [developer portal](https://app.terminal49.com/developers/api-keys) as described in [Start Here](/api-docs/getting-started/start-here).

## List all your tracked shipments

If your tracking request was successful, you will now be able to list your tracked shipments. Replace `YOUR_API_KEY` with your API key:

```bash theme={null}
curl "https://api.terminal49.com/v2/shipments" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Authorization: Token YOUR_API_KEY"
```

Sometimes it takes a few minutes for a new tracking request to appear as a shipment.

Copy the response into a text editor so you can inspect it while continuing the tutorial.

<Info>
  Responses follow the JSON:API format, which is why they are larger and more
  structured than plain JSON. See the JSON:API note in [Track Shipments and
  Containers](/api-docs/getting-started/tracking-shipments-and-containers#anatomy-of-a-tracking-request-response)
  for tips on parsing it.
</Info>

## Inspect the shipment response

The `/shipments` response returns an array of `shipment` objects. Each shipment includes attributes, relationships to related records, and a `self` link.

For clarity, some fields have been replaced with ellipses (`...`), and inline comments call out the key fields.

The **data** attribute contains an array of objects. Each object is of type `shipment` and includes attributes such as bill of lading number and port of lading. Each shipment object also has relationships to structured data objects like ports and terminals, as well as a list of containers on the shipment.

You can access these structured elements through the API. Terminal49 cleans and enhances the data from the shipping line, so you get a pre-defined object for each port, terminal, and other entity.

```jsonc theme={null}
{
  "data": [
    {
      /*  this is an internal id that you can use to query the API directly, i.e by hitting https://api.terminal49.com/v2/shipments/123456789 */
      "id": "123456789",
      // the object type is a shipment, per below.
      "type": "shipment",
      "attributes": {
        // Your BOL number that you used in the tracking request
        "bill_of_lading_number": "99999999",
        ...
        "shipping_line_scac": "MAEU",
        "shipping_line_name": "Maersk",
        "port_of_lading_locode": "INVTZ",
        "port_of_lading_name": "Visakhapatnam",
        ...
      },
      "relationships": {

        "port_of_lading": {
          "data": {
            "id": "bde5465a-1160-4fde-a026-74df9c362f65",
            "type": "port"
          }
        },
        "port_of_discharge": {
          "data": {
            "id": "3d892622-def8-4155-94c5-91d91dc42219",
            "type": "port"
          }
        },
        "pod_terminal": {
          "data": {
            "id": "99e1f6ba-a514-4355-8517-b4720bdc5f33",
            "type": "terminal"
          }
        },
        "destination": {
          "data": null
        },
        "containers": {
          "data": [
            {
              "id": "593f3782-cc24-46a9-a6ce-b2f1dbf3b6b9",
              "type": "container"
            }
          ]
        }
      },
      "links": {
        // this is a link to this specific shipment in the API.
        "self": "/v2/shipments/7f8c52b2-c255-4252-8a82-f279061fc847"
      }
    },
    ...
    ],
  ...
}
```

## Sample code: listing tracked shipments in a Google Sheet

Below is code written in Google App Script that lists the current shipments into the current sheet of a spreadsheet. App Script is very similar to Javascript.

Because Google App Script does not have native JSON:API support, you need to parse the JSON directly, making this example an ideal real world application of the API.

```javascript theme={null}
function listTrackedShipments(){
  // first we construct the request.
  var options = {
    "method" : "GET",
    "headers" : {
      "content-type": "application/vnd.api+json",
      "authorization" : "Token YOUR_API_KEY"
    },
      "payload" : ""
   };


  try {
    // note that URLFetchApp is a function of Google App Script, not a standard JS function.
    var response = UrlFetchApp.fetch("https://api.terminal49.com/v2/shipments", options);
    var json = response.getContentText();
    var shipments = JSON.parse(json)["data"];
    var shipment_values = [];
    shipment_values = extractShipmentValues(shipments);
    listShipmentValues(shipment_values);
  } catch (error){
    //In JS you would use console.log(), but App Script uses Logger.log().
    Logger.log("error communicating with t49 / shipments: " + error);
  }
}


function extractShipmentValues(shipments){
  var shipment_values = [];
  shipments.forEach(function(shipment){
      // iterating through the shipments.
    shipment_values.push(extractShipmentData(shipment));
  });
  return shipment_values;
}

function extractShipmentData(shipment){
   var shipment_val = [];
   //for each shipment I'm extracting some of the key info i want to display.
   shipment_val.push(shipment["attributes"]["shipping_line_scac"],
                      shipment["attributes"]["shipping_line_name"],
                      shipment["attributes"]["bill_of_lading_number"],
                      shipment["attributes"]["pod_vessel_name"],
                      shipment["attributes"]["port_of_lading_name"],
                      shipment["attributes"]["pol_etd_at"],
                      shipment["attributes"]["pol_atd_at"],
                      shipment["attributes"]["port_of_discharge_name"],
                      shipment["attributes"]["pod_eta_at"],
                      shipment["attributes"]["pod_ata_at"],
                      shipment["relationships"]["containers"]["data"].length,
                      shipment["id"]
                    );
  return shipment_val;
}


function listShipmentValues(shipment_values){
// now, list the data in the spreadsheet.
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var homesheet =   ss.getActiveSheet();
  var STARTING_ROW = 1;
  var MAX_TRACKED = 500;
  try {
    // clear the contents of the sheet first.
    homesheet.getRange(STARTING_ROW,1,MAX_TRACKED,shipment_values[0].length).clearContent();
    // now insert all the shipment values directly into the sheet.
    homesheet.getRange(STARTING_ROW,1,shipment_values.length,shipment_values[0].length).setValues(shipment_values);
  } catch (error){
    Logger.log("there was an error in listShipmentValues: " + error);
  }
}
```

## List all your tracked containers

You can also list out all of your containers. Container data includes terminal availability, last free day, holds, fees, and other logistical information that you might use for drayage operations at port.

<Tip>
  To learn how to use holds and fees data to determine if a container is ready
  for pickup, see [Container Holds, Fees, and Release
  Readiness](/api-docs/in-depth-guides/holds-and-fees).
</Tip>

Replace `YOUR_API_KEY` with your API key:

```bash theme={null}
curl "https://api.terminal49.com/v2/containers" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Authorization: Token YOUR_API_KEY"
```

We suggest copying the response into a text editor so you can examine it while continuing the tutorial.

## Anatomy of containers JSON response

Now that you've got a list of containers, let's examine the response you've received. The example below is partial: it shows a single container object from the `data` array, with some fields omitted and inline comments calling out the key fields.

```jsonc theme={null}
// We have an array of objects in the data returned.
  "data": [
    {
      //
      "id": "internalid",
      // this object is of type Container.
      "type": "container",
      "attributes": {

        // Here is your container number
        "number": "OOLU-xxxx",
        // Seal Numbers aren't always returned by the carrier.
        "seal_number": null,
        "created_at": "2020-09-13T19:16:47Z",
        "equipment_type": "reefer",
        "equipment_length": null,
        "equipment_height": null,
        "weight_in_lbs": 54807,

        "fees_at_pod_terminal": [],
        "holds_at_pod_terminal": [],
        // here is your last free day.
        "pickup_lfd": "2020-09-17T07:00:00Z",
        "pickup_appointment_at": null,
        "availability_known": true,
        "available_for_pickup": false,
        "pod_arrived_at": "2020-09-13T22:05:00Z",
        "pod_discharged_at": "2020-09-15T05:27:00Z",
        "location_at_pod_terminal": "CC1-162-B-3(Deck)",
        "final_destination_full_out_at": null,
        "pod_full_out_at": "2020-09-18T10:30:00Z",
        "empty_terminated_at": null
      },
      "relationships": {
        // linking back to the shipment object, found above.
        "shipment": {
          "data": {
            "id": "894befec-e7e2-4e48-ab97-xxxxxxxxx",
            "type": "shipment"
          }
        },
        "pod_terminal": {
          "data": {
            "id": "39d09f18-cf98-445b-b6dc-xxxxxxxxx",
            "type": "terminal"
          }
        },
        ...
      }
    },
    ...
```

## Next up: receive status updates

You can now list your tracked shipments and containers on demand. The final step is to register a webhook so Terminal49 pushes updates to you as they happen.

<Card title="Receive status updates" icon="bell" href="/api-docs/getting-started/receive-status-updates">
  Register a webhook endpoint and handle your first notification.
</Card>
