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

# Monitor ETA Changes with Webhooks

> Subscribe to Terminal49 ETA change webhook events and alert your team automatically when a shipment's estimated arrival date or port of discharge shifts.

Carriers frequently revise arrival estimates as vessels encounter weather, port congestion, or schedule changes. The `shipment.estimated.arrival` event fires every time Terminal49 detects an ETA change so you can react immediately.

## Events to subscribe to

| Event                                                         | When it fires                                                           |
| ------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `shipment.estimated.arrival`                                  | Shipment-level ETA changes for the port of discharge                    |
| `container.transport.estimated.vessel_arrived`                | Container-level ETA changes for vessel arrival at the port of discharge |
| `container.transport.estimated.arrived_at_inland_destination` | Container-level ETA changes for the inland destination (rail moves)     |

## What the payload includes

When a `shipment.estimated.arrival` event fires, the `included` array contains:

* An `estimated_event` object with the new `estimated_timestamp`
* The full `shipment` object with updated `pod_eta_at` and related fields
* The `port` object for the port of discharge
* The `vessel` object when Terminal49 can identify the vessel

## Handle the webhook

Parse the incoming notification, extract the new ETA, and compare it to your stored value:

```javascript theme={null}
app.post("/webhooks/terminal49", async (req, res) => {
  const { data, included } = req.body;

  if (data.attributes.event !== "shipment.estimated.arrival") {
    return res.sendStatus(200);
  }

  const shipment = included.find((obj) => obj.type === "shipment");
  const estimatedEvent = included.find((obj) => obj.type === "estimated_event");

  const newEta = estimatedEvent.attributes.estimated_timestamp;
  const bolNumber = shipment.attributes.bill_of_lading_number;
  const portOfDischarge = shipment.attributes.port_of_discharge_name;

  // Compare against your stored ETA
  const previousEta = await getStoredEta(bolNumber);
  const changeInHours = Math.abs(
    (new Date(newEta) - new Date(previousEta)) / (1000 * 60 * 60)
  );

  if (changeInHours > 12) {
    await notifyTeam({
      message: `ETA for ${bolNumber} at ${portOfDischarge} shifted by ${Math.round(changeInHours)} hours`,
      newEta,
      previousEta,
    });
  }

  await updateStoredEta(bolNumber, newEta);

  res.sendStatus(200);
});
```

<Tip>
  ETA events can fire multiple times per day as carriers update their schedules. Filter for significant changes (e.g., more than 12 hours) to avoid alert fatigue.
</Tip>

## Inland destination ETAs

For shipments with an inland rail move, subscribe to `container.transport.estimated.arrived_at_inland_destination` as well. This event fires when the estimated arrival at the rail ramp or inland depot changes.

This is a container transport event, so the payload includes a `transport_event` object rather than an `estimated_event` object. Look for the `transport_event` in `included`, then read `attributes.timestamp` for the estimated arrival time.

## Container-level vessel arrival ETAs

Subscribe to `container.transport.estimated.vessel_arrived` when you need ETA changes at the container level. This event uses the same transport event payload shape as other `container.transport.*` events, with the estimated vessel arrival stored on the included `transport_event` object.

## Common patterns

* **Threshold alerts** — only notify when the ETA shifts by more than N hours
* **Direction tracking** — distinguish delays (ETA moved later) from early arrivals (ETA moved earlier)
* **Customer notifications** — forward ETA changes to your customers with a human-readable message
* **Planning updates** — adjust warehouse receiving schedules or drayage bookings automatically

## Related

* [Event catalog](/api-docs/webhooks/event-catalog) — full list of available events
* [Payload examples](/api-docs/useful-info/webhook-events-examples) — complete JSON payloads
* [Event timestamps](/api-docs/in-depth-guides/event-timestamps) — how Terminal49 stores and returns timestamps in UTC
