Skip to main content
A container’s journey from origin to destination passes through a predictable sequence of milestones. Terminal49 sends a webhook event for each milestone so you can build a real-time timeline without polling.

The container journey

For containers with transshipments, feeder vessels, or inland rail moves, additional milestone events fire at each intermediate point.

Events in journey order

Origin to vessel

EventMilestone
container.transport.empty_outEmpty container picked up at origin
container.transport.full_inFull container gated in at port of lading
container.transport.vessel_loadedLoaded onto vessel
container.transport.vessel_departedVessel departed port of lading

Transshipment (if applicable)

EventMilestone
container.transport.transshipment_arrivedArrived at transshipment port
container.transport.transshipment_dischargedDischarged at transshipment port
container.transport.transshipment_loadedLoaded onto next vessel
container.transport.transshipment_departedDeparted transshipment port

Destination

EventMilestone
container.transport.vessel_arrivedVessel arrived at port of discharge
container.transport.vessel_berthedVessel berthed at port of discharge
container.transport.vessel_dischargedContainer discharged from vessel
container.transport.availableAvailable for pickup
container.transport.full_outPicked up from terminal
container.transport.empty_inEmpty returned

Rail (if applicable)

EventMilestone
container.transport.rail_loadedLoaded onto rail
container.transport.rail_departedRail departed
container.transport.rail_arrivedRail arrived at inland ramp
container.transport.rail_unloadedUnloaded from rail
container.transport.arrived_at_inland_destinationArrived at final inland destination

Build a milestone timeline

Each transport event webhook includes a transport_event object in the included array with the event type, timestamp, and location:
app.post("/webhooks/terminal49", (req, res) => {
  const { data, included } = req.body;
  const event = data.attributes.event;

  if (!event.startsWith("container.transport.")) {
    return res.sendStatus(200);
  }

  const transportEvent = included.find((obj) => obj.type === "transport_event");
  const container = included.find((obj) => obj.type === "container");
  const shipment = included.find((obj) => obj.type === "shipment");

  const milestone = {
    containerNumber: container.attributes.number,
    bolNumber: shipment.attributes.bill_of_lading_number,
    event: event,
    timestamp: transportEvent.attributes.timestamp,
    timezone: transportEvent.attributes.timezone,
    location: transportEvent.attributes.location_locode,
    voyageNumber: transportEvent.attributes.voyage_number,
  };

  await saveMilestone(milestone);

  res.sendStatus(200);
});
Transport event timestamps are stored in UTC. Use the timezone field to convert to local time. See Event Timestamps for details.

Common patterns

  • Customer portal β€” display a visual timeline showing where each container is in its journey
  • Dwell time tracking β€” measure time between vessel_arrived and full_out to identify port delays
  • Transit time analysis β€” compare vessel_departed to vessel_arrived across carriers and routes
  • Exception detection β€” alert when a container has been at a milestone for longer than expected
  • Export visibility β€” track empty_out through vessel_departed for outbound shipments