Skip to content

Compatibility surface

A drop-in compatibility tracking API.

Track a container, bill of lading or booking and receive the compatibility envelope, so an existing integration keeps parsing unchanged. You change the base URL and the key, nothing else.

Base URL

https://api.trackingmcp.com

The path is /compat/searates/tracking.

Authentication

?api_key=tmcp_…

The key travels in the query string as api_key, which is where a migrating client already puts it. Any Navo24 tmcp_ key works. Bearer tokens are for the native /v1 API.

GET API key
GET api.trackingmcp.com/compat/searates/tracking

Aliases served by the same handler: /compat/searates/container, /compat/searates/reference.

Query parameters

api_keystringrequired

Your Navo24 API key (tmcp_ prefix). Create one in the developer portal.

numberstringrequired

Container number (4 letters and 7 digits), bill of lading, or booking number. Upper-cased and trimmed server-side. The kind is detected from the reference, and metadata.number echoes what you sent. Send type to declare the kind yourself.

typestring

Accepts the following types: CT (container), BL (bill of lading), BK (booking).

carrierstring

Force resolution on a specific operating line by SCAC (four letters). Naming a different line than the stored one drops the prior-voyage data and re-resolves on the requested carrier.

Response schema

176 fields

Nested exactly as the JSON is. Open a branch to read its fields; hover a name for the full dot-path.

statusstring

success on a data-bearing reply, error otherwise. An error is still HTTP 200 (see Errors).

messagestring

OK on a normal reply. On an error it carries the machine code. On a success it can carry one short sentence explaining why a reference is untrackable.

dataobject

Exactly seven keys, always the same seven. The API version is disclosed in response headers, never as an eighth key here.

metadataobject

Everything about the ANSWER rather than the shipment: what resolved, where it came from, how fresh it is, and what it cost you.

typestring

Which identifier resolved: CT container, BL bill of lading, BK booking.

numberstring

The reference exactly as you queried it, upper-cased.

sealinestring

SCAC of the operating line. Falls back to the container prefix when the stored carrier is unresolved and the prefix names a known line, and to the literal auto when even that is unknown.

sealine_namestring

Human carrier name, or the literal Unknown when no line has been resolved. Never null.

statusstring

Shipment status: PLANNED, IN_TRANSIT, DELIVERED or UNKNOWN. See the shipment status table.

is_status_from_sealineboolean

Always false, and deliberately so: our status is derived from the carrier events we hold, not lifted from a carrier status string. Reporting true would misattribute a value we computed.

from_cacheboolean

Always false. The store is polled continuously and served live rather than as a stale cache hit.

updated_atstring | null

When we last wrote this record, in UTC. Null means we hold no write timestamp, which happens only on a record that has never been polled.

cache_expiresstring | null

updated_at plus 12 hours, in UTC. Null whenever updated_at is null.

api_callsobject

Your call allowance on the plan behind this key: the total, what you have used, what is left.

totalinteger | null

Call cap for the key. NULL MEANS UNCAPPED, which is the common case. It does not mean zero.

usedinteger

Calls consumed in the current period. Always a real number.

remaininginteger | null

Calls left, or null when uncapped.

unique_shipmentsobject

Same three counters for unique shipments, which is the dimension we meter on. Same null rule.

totalnumber

The allowance on your plan.

usednumber

How much of it is spent.

remainingnumber

What is left. It is the figure to alert on.

locations[]object[]

Every place the payload references, deduplicated. Events and route points point here by id.

idinteger

One-based id, referenced by events and route points.

namestring

Port or place name, cleaned of a trailing country suffix where a carrier appended one.

statestring | null

State or province. Null when our port reference data holds none for this place.

countrystring | null

English country name. Null when we could not determine the country at all.

country_codestring | null

ISO 3166-1 alpha-2. Derived from the UN/LOCODE prefix when the reference data is silent.

locodestring | null

Full 5-character UN/LOCODE. NULL MEANS THE CARRIER GAVE A PLACE NAME ONLY and we could not resolve it to a code, not that the place is unknown.

latnumber | null

Latitude. Null when the place is unresolved in our port reference data.

lngnumber | null

Longitude. Null on the same condition as lat.

timezonestring | null

IANA zone for the port. This is the clock every event date is printed on. Null when the port is unplaced, in which case that event date is the carrier value as filed.

facilities[]object[]

Terminals, depots and yards, deduplicated by name. A place with no UN/LOCODE whose name reads as a terminal or an operator is filed here rather than entering locations.

idinteger

One-based id, referenced by an event facility.

namestring

Terminal or depot name as the carrier reported it.

country_codestring | null

ISO 3166-1 alpha-2 of the event that introduced the facility. Null when that event carried no country.

locodenull

Always null today: carriers give us the facility name only. Present so the shape matches.

bic_codenull

Always null today, for the same reason as locode.

smdg_codenull

Always null today, for the same reason as locode.

latnull

Always null today. Facility coordinates are not published by the carriers we read.

lngnull

Always null today, for the same reason as lat.

code_sourcestring

Which registry the facility code came from, for example BIC or SMDG, so a code is never read against the wrong scheme.

routeobject

The legs in order. Each carries its two endpoints, its geometry and its vessel.

prepolobject

The inland origin move before the sea leg: the first gate or pickup event ahead of the first load or departure. Falls back to the pol location with a null date when there is no inland origin move.

locationinteger | null

Index into locations. Null only when we hold no place for that point at all.

datestring | null

The true UTC instant of that point, YYYY-MM-DD HH:MM:SS. Same basis as every event date here, so the two halves of a payload can never disagree. The API this surface replaces prints port-local in this field, so a field by field comparison differs by the port offset: read date_local for the quay clock. Null on a prepol that fell back to the pol location because the shipment has no inland origin move.

date_localstring | null

The port wall clock for the same moment, YYYY-MM-DD HH:MM:SS, no offset. A departure from Shanghai at 03:00 on the quay shows date 2026-09-12 19:00:00 and date_local 2026-09-13 03:00:00. Null when we do not hold the port zone for that move, and never back-computed from a guessed zone.

utc_offset_minutesnumber | null

Minutes to add to date to reach date_local, so the pair is self describing. Null when unknown.

timezonestring | null

IANA zone of the port, such as Asia/Shanghai. The stable companion to the offset, which alone cannot name the zone or survive a DST change. Null when unresolved.

actualboolean | null

True once the move has occurred. Null on a prepol that fell back to the pol location.

polobject

Port of loading, anchored on the vessel departure and falling back to the first load. A feeder or rail pre-carriage never anchors it: the leg starts where the carrier names its port of loading.

locationinteger | null

Index into locations. Null only when we hold no place for that point at all.

datestring | null

The true UTC instant of that point, YYYY-MM-DD HH:MM:SS. Same basis as every event date here, so the two halves of a payload can never disagree. The API this surface replaces prints port-local in this field, so a field by field comparison differs by the port offset: read date_local for the quay clock. NULL MEANS THE CARRIER HAS NOT FILED THE MOVE YET, not that it did not happen.

date_localstring | null

The port wall clock for the same moment, YYYY-MM-DD HH:MM:SS, no offset. A departure from Shanghai at 03:00 on the quay shows date 2026-09-12 19:00:00 and date_local 2026-09-13 03:00:00. Null when we do not hold the port zone for that move, and never back-computed from a guessed zone.

utc_offset_minutesnumber | null

Minutes to add to date to reach date_local, so the pair is self describing. Null when unknown.

timezonestring | null

IANA zone of the port, such as Asia/Shanghai. The stable companion to the offset, which alone cannot name the zone or survive a DST change. Null when unresolved.

actualboolean | null

True once the milestone has occurred.

podobject

Port of discharge, which is where the box leaves the ship and is NOT the inland destination on a door move. Anchored on the last vessel discharge the box never sails away from.

locationinteger | null

Index into locations. Null only when we hold no place for that point at all.

datestring | null

The true UTC instant of that point, YYYY-MM-DD HH:MM:SS. Same basis as every event date here, so the two halves of a payload can never disagree. The API this surface replaces prints port-local in this field, so a field by field comparison differs by the port offset: read date_local for the quay clock. NULL MEANS THE CARRIER HAS NOT FILED THE MOVE YET, not that it did not happen.

date_localstring | null

The port wall clock for the same moment, YYYY-MM-DD HH:MM:SS, no offset. A departure from Shanghai at 03:00 on the quay shows date 2026-09-12 19:00:00 and date_local 2026-09-13 03:00:00. Null when we do not hold the port zone for that move, and never back-computed from a guessed zone.

utc_offset_minutesnumber | null

Minutes to add to date to reach date_local, so the pair is self describing. Null when unknown.

timezonestring | null

IANA zone of the port, such as Asia/Shanghai. The stable companion to the offset, which alone cannot name the zone or survive a DST change. Null when unresolved.

actualboolean | null

True once the milestone has occurred.

predictive_etastring | null

Predicted arrival at the port of discharge, on pod only. Once the arrival is actual there is nothing left to predict, so it equals the recorded arrival rather than a frozen pre-arrival estimate. Null when we hold no estimate.

postpodobject

The inland destination move after the final discharge: the last availability or gate event past the port of discharge. Falls back to pod when there is no on-carriage move.

locationinteger | null

Index into locations. Null only when we hold no place for that point at all.

datestring | null

The true UTC instant of that point, YYYY-MM-DD HH:MM:SS. Same basis as every event date here, so the two halves of a payload can never disagree. The API this surface replaces prints port-local in this field, so a field by field comparison differs by the port offset: read date_local for the quay clock. Null on a postpod that fell back to pod because there is no on-carriage move.

date_localstring | null

The port wall clock for the same moment, YYYY-MM-DD HH:MM:SS, no offset. A departure from Shanghai at 03:00 on the quay shows date 2026-09-12 19:00:00 and date_local 2026-09-13 03:00:00. Null when we do not hold the port zone for that move, and never back-computed from a guessed zone.

utc_offset_minutesnumber | null

Minutes to add to date to reach date_local, so the pair is self describing. Null when unknown.

timezonestring | null

IANA zone of the port, such as Asia/Shanghai. The stable companion to the offset, which alone cannot name the zone or survive a DST change. Null when unresolved.

actualboolean | null

True once the milestone has occurred.

vessels[]object[]

Every hull the timeline names, deduplicated by IMO and by canonical name.

idinteger

One-based id, referenced by an event vessel.

namestring

Vessel name. Where two sources disagree we emit the fuller spelling, so a name is never silently truncated.

imointeger | null

IMO number. Null when the carrier named the ship but gave no IMO.

call_signstring | null

Call sign. Null when we hold no particulars for this hull.

mmsiinteger | null

MMSI. Null on the same condition as call_sign.

flagstring | null

Flag as an ISO 3166-1 alpha-2 code, derived from the MMSI when the stored flag is absent. Null when neither is available.

containers[]object[]

One entry per box. A container lookup returns one. A bill of lading or booking returns every box on the manifest, never a truncated list.

numberstring

Container number.

iso_codestring | null

ISO 6346 size and type code. Null when the carrier did not publish one, or when a multi-box bill of lading cannot attribute the parent equipment to one box.

size_typestring | null

Human size and type, normalised so one box type reads one way across carriers. The ISO code is read first and the carrier short code second, and the two tables are held identical on every shared key, so a value such as 40RH renders "40' Reefer" whichever of the two fields the carrier populated. An unrecognised carrier value is passed through untouched rather than guessed at. Null on the same condition as iso_code.

statusstring

Shipment status for this box, same vocabulary as metadata.status.

is_status_from_sealineboolean

Always false, for the reason given on metadata.is_status_from_sealine.

events_mirroredboolean

A provenance disclosure, not a formatting flag. True when this box carries a timeline copied from a sibling on the same bill of lading rather than one sourced for this box. A box whose events were fetched in their own request is false even when its dates match a sibling.

events[]object[]

The milestone timeline, chronological, with a journey-stage tie-break so a run of same-timestamp estimates cannot read as a gate-out before the ship has arrived.

order_idinteger

One-based position in this timeline, renumbered after duplicate records are removed. A repeated milestone at one place is not a duplicate and keeps its own number (see the duplicates note).

locationinteger | null

Index into locations. Null when the carrier reported no place, or reported only a terminal, which is filed as the facility instead.

facilityinteger | null

Index into facilities. Null when the carrier named no terminal.

descriptionstring

The carrier own wording for the move where we hold it, otherwise a generic label for the code. The carrier sentence wins deliberately: a code-derived label discards a fact the line already stated.

event_typestring | null

EQUIPMENT or TRANSPORT, derived from the code: arrivals and departures are TRANSPORT, every equipment move is EQUIPMENT. Null only on the transshipment delay notice, which carries no family.

event_codestring | null

The movement code, drawn from a CLOSED vocabulary of sixteen values and never anything else. Full list in the event code table below. NULL IS A NORMAL VALUE on an ordinary movement, not an error and not only the transshipment delay: it means we hold no code from this closed set for that move, and the incumbent withholds a code on the same kind of row. Read the description when the code is null. The row is never dropped for it.

statusstring

The milestone this event represents. Full vocabulary in the status code table below. Never null.

datestring

The true UTC instant of the event, YYYY-MM-DD HH:MM:SS. This is the primary date on every surface, so a value never depends on which clock the carrier reported it in. The port wall clock rides alongside in event_local_datetime.

event_local_datetimestring | null

The port local wall clock for the same event, YYYY-MM-DDTHH:MM:SS, no offset. A vessel that departs Yantian at 14:15 on the quay shows date 06:15:00 UTC and event_local_datetime T14:15:00. Null until the carrier connector reports a placeable port.

utc_offset_minutesnumber | null

Minutes to add to date to reach event_local_datetime, so the pair is self describing. Null when unknown.

event_timezonestring | null

IANA zone of the port, such as Asia/Shanghai. The stable companion to the offset, which alone cannot name the zone or survive a DST change. Null when unresolved.

actualboolean

True once the milestone has occurred, false while it is a forecast. Reconciled to be monotonic: everything at or before the latest actual event is actual, so the sequence never reads as out of order.

is_date_from_sealineboolean

Always true: every date on this surface comes from the carrier filing, not from an inference of ours.

is_additional_eventboolean

Always false. We do not synthesise events.

typestring

sea or land. VESSEL and BARGE ride water, RAIL and TRUCK ride land.

transport_typestring | null

VESSEL, RAIL, TRUCK or BARGE. Null only on the transshipment delay notice. See the conveyance table for how TRUCK is used as a fallback.

vesselinteger | null

Index into vessels. NULL ON EVERY LAND MOVE by construction, so a rail or truck leg can never claim to ride a ship, and null on a sea move where the carrier named no hull and the timeline names more than one.

voyagestring | null

Voyage number. Nulled alongside vessel on a land move, and null when the carrier filed none.

dcsa_event_codestring

The DCSA code for the same event, so a client already speaking the standard needs no mapping table. Present on every event.

dcsa_event_familystring

Which DCSA family the code belongs to: EQUIPMENT, TRANSPORT or SHIPMENT.

empty_indicatorstring

EMPTY or LADEN, on equipment events. Null when the carrier did not report the fill state: the standard has no unknown value and we do not invent one, and this is not an end-of-shipment signal.

route_dataobject | null

Map payload: plotted legs, the current pin and live AIS. Null when we hold no plottable route. Additive, and safe to ignore if you only consume the timeline.

route[]object[]

Plotted legs, port to port, each with its sea lane or land path.

patharray[]

Points as [lat, lng] pairs, in that order.

typestring

SEA or LAND for the leg.

vesselobject | null

The hull that ran the leg. Null on a land leg, and on a sea leg where no hull is known.

transport_typestring

The mode carrying the leg, for example VESSEL or TRUCK, when the carrier names it. Null when it does not.

fromobject

Where the leg starts.

namestring

Human-readable name.

statestring

State, province or region of the port, when the gazetteer holds one.

countrystring

Country name.

country_codestring

ISO 3166-1 alpha-2 country code.

locodestring

UN/LOCODE of the place.

latnumber

Latitude.

lngnumber

Longitude.

timezonestring

IANA time zone of the place. Null when we could not resolve the port.

toobject

Where the leg ends.

namestring

Human-readable name.

statestring

State, province or region of the port, when the gazetteer holds one.

countrystring

Country name.

country_codestring

ISO 3166-1 alpha-2 country code.

locodestring

UN/LOCODE of the place.

latnumber

Latitude.

lngnumber

Longitude.

timezonestring

IANA time zone of the place. Null when we could not resolve the port.

pinarray | null

Current position as [lat, lng]. Null when we hold no position for the carrying vessel.

aisobject | null

Live vessel block. Null when no vessel is under way for this shipment.

dataobject

The AIS-shaped payload. It is nested under a data key because that is the layout of the API this surface is compatible with, not because it is a second envelope.

arrival_portobject

The arrival call these dates describe.

codestring | null

The 3-letter port code, which is the UN/LOCODE with its country prefix removed and is NOT itself a UN/LOCODE. Kept for compatibility.

locodestring | null

Additive to the incumbent shape: the full 5-character UN/LOCODE, so a consumer keying on UN/LOCODE can match this block. Null when the port is unresolved.

date_labelstring | null

ETA, ETD, ATA or ATD, saying which kind of time the sibling date is.

datestring

The date of the call, as a port wall-clock string with no offset, which is the layout this block has always used. Read date_label to know whether it is an estimate or an actual.

country_codestring

ISO 3166-1 alpha-2 country code.

vesselobject

The hull these dates belong to.

imonumber

IMO number of the vessel.

flagstring

Flag state of the vessel, as a two-letter code. Null when we hold none.

mmsinumber

Vessel MMSI. Null when we hold none.

namestring

Human-readable name.

call_signstring

Vessel radio call sign. Null when we hold none.

last_eventobject

The most recent vessel move behind these dates.

datestring

When it happened, as a port wall-clock string without an offset, which is the layout this block has always used.

voyagestring | null

Carrier voyage number, when published. Null otherwise.

descriptionstring

The carrier own phrasing for the event, falling back to our word for the code.

updated_atstring

When this AIS block was last rebuilt.

departure_portobject

The departure call these dates describe.

codestring

The short port code, as above. Read locode for the standard one.

locodestring

UN/LOCODE of the place.

datestring

The date of the call, in the same wall-clock layout. Read date_label before treating it as an actual.

date_labelstring

Which kind of date the neighbouring value is: ETA, ETD, ATA or ATD. Read it before treating a date as an actual.

country_codestring

ISO 3166-1 alpha-2 country code.

discharge_portobject

The discharge call these dates describe.

codestring

The short port code, as above. Read locode for the standard one.

locodestring

UN/LOCODE of the place.

datestring

The date of the sea discharge, in the same wall-clock layout. Read date_label before treating it as an actual.

date_labelstring

Which kind of date the neighbouring value is: ETA, ETD, ATA or ATD. Read it before treating a date as an actual.

country_codestring

ISO 3166-1 alpha-2 country code.

namestring

Human-readable name.

last_vessel_positionobject

The most recent fix for the hull, with the time it was taken.

latnumber

Latitude.

lngnumber

Longitude.

updated_atstring

When the fix was taken.

statusstring

Whether the AIS block carries data, and why not when it does not.

sourceobject

Provenance for the geometry and the AIS, so you can tell computed geometry from provider geometry.

providerstring

Machine name of the producer.

provider_namestring

Display name of the producer.

route_geometrystring

How the drawn line was produced, for example trackingmcp_computed.

aisstring

Which vessel-position source fed the AIS block.

notestring

One sentence of provenance in plain language.

pin_sourcestring

How the pin was placed: ais_vessel_position from a real fix, route_reckoning when computed along the route, or a port when the box is sitting at one.

What changes, and what does not

Your parser does not change. The envelope, the field names, the normalised locations, facilities and vessels arrays, the route block and the milestone vocabulary are all reproduced. Three things change: the base URL, the api_key you send, and the fact that the data underneath is ours. Two behaviours are worth reading before you cut over: our nulls are documented field by field below, and the differences we know about are stated on this page rather than left for you to find.

Cold lookups

A reference we have never seen is registered and resolved live. The request is held until real data lands, usually two to four seconds, with a ceiling of twenty-five seconds. If nothing resolves inside that window you get NO_TRACKING_INFO, and a retry a moment later normally succeeds because the resolution keeps running in the background. A not-found is never charged against your allowance, so you can retry freely.

Which clock the dates use

Every event date, every route date and the AIS block are printed as the true UTC instant, formatted YYYY-MM-DD HH:MM:SS with no offset. This is the same basis on the native API and this compatibility one, so no value depends on which clock a carrier reported it in. The port local wall clock rides alongside each event in event_local_datetime, together with utc_offset_minutes and event_timezone, so you can show quay time without re-deriving it. Each of the four route points carries the same three companions under the names date_local, utc_offset_minutes and timezone, so route.pol can be compared against a port-local system without a timezone table on your side. If a port could not be placed the three stay null rather than being derived, so a null there means we do not know, never assume UTC. metadata.updated_at and metadata.cache_expires are our own bookkeeping and stay in UTC too.

Repeated milestones, and which duplicates we remove

A repeated status at one place is NOT treated as a duplicate. A vessel calling the same port twice, or an arrival and a berthing hours apart, is two real movements, and both rows are returned, exactly as the incumbent returns them. Two different movement codes can also fold onto one milestone at one place, and both of those rows are returned too. Only two things are removed, and both are records rather than movements. First, two events at the SAME instant and the same milestone and place, which is one physical move reported twice by two event families. Second, an unlocated copy of an event we also hold with a resolved UN/LOCODE, which is a bookkeeping artefact rather than a second call. Where a pair does fold we keep the located row, then the actual or the later one, and order_id is renumbered afterwards. UNKN and LTS never fold at all, because neither is a once-per-journey milestone.

Versioning

Versions are dates. Pin one with the API-Version request header (X-API-Version and Navo-API-Version are accepted aliases) and your response shape is held. An unpinned request always resolves to the oldest supported version, never the newest, so a deploy can never move an existing integration onto a new shape. The resolved version is echoed on every response, and an unrecognised value never blocks a request: it falls back and returns API-Version-Warning naming what was sent and what was served. One shape difference exists between the two published versions today: 2026-08-04 spells the unclassified milestone UNKN, and 2027-02-01 spells the same value UNK. Everything else is identical, including the seven top-level keys.

Event codes

Every value containers[].events[].event_code can carry, and there are exactly sixteen. The vocabulary is CLOSED: a movement we hold under some other code is emitted with event_code null rather than under a name this list does not contain, because a code outside the list is the one thing a migrating parser cannot be expected to handle. Null is an ordinary outcome on an ordinary movement, not a marker for the transshipment delay alone, and the incumbent withholds a code on the same kind of row. When the code is null, read description: the row still carries its wording, its place, its date, its status and its actual flag, so no movement is lost. Note that the code and the milestone are different questions. The code says what the carrier did; status says where on the journey it happened, and several codes reach one milestone.

CodeMeaningUsual milestone
ARRIVessel arrival.VAT at a hub, VAD at the port of discharge, LTS on an inland leg.
DEPAVessel departure.VDL at the loading port, VDT at a hub, LTS on an inland leg.
LOADContainer loaded on the vessel.CLL on the first load, CLT afterwards, LTS on an inland leg.
DISCContainer discharged from the vessel.CDT at a transshipment port, CDD at the final one.
GTINContainer gate in. Our internal DROP token is emitted as GTIN, which is the only gate-in code this vocabulary has.CGI laden, CER empty, LTS on an inland leg.
GTOTContainer gate out.CEP when empty, CGO when laden at the destination.
PICKContainer picked up.CPS at the shipper, CGO past the port of discharge, CEP on a merchant-haulage empty pickup.
RELSReleased. Carries both the carrier release and the availability-to-collect notice.UNKN: neither is a positional milestone.
STUFContainer stuffed. The long spelling STUFF is emitted as STUF, which is how the wire spells it.UNKN.
STRPContainer stripped.UNKN.
RECEReceived.UNKN.
CONFConfirmed.UNKN.
CUSRCustoms release.UNKN.
CUSICustoms inspection.UNKN.
ISSUIssued.UNKN.
INSPInspected.UNKN.
nullNo code from the closed set applies. Availability for delivery is the common case, and the transshipment delay notice is a second one. Fall back to description.The milestone is still emitted: TSD on the delay notice, and the ordinary positional milestone otherwise.

Size and type

How containers[].size_type is rendered. Two carrier fields can carry the box type, the ISO code and a short code, and both are read against the same vocabulary so one physical box cannot read two ways depending on which field the line happened to populate. The ISO code is consulted first. A code in neither table is passed through as the carrier wrote it rather than guessed at.

Carrier valuesize_type
22G1, 22G0, 20G120' Dry Standard
20DV, 20GP20' Dry Standard
42G1, 42G0, 40G140' Dry Standard
40DV, 40GP40' Dry Standard
45G1, 45G040' High Cube Dry
40HC, 40HQ, 45GP40' High Cube Dry
L5G145' High Cube Dry
45HC45' High Cube Dry
22R1, 20RF20' Reefer
42R1, 40RF, 40RH40' Reefer. 40RH is a carrier short code rather than a valid ISO 6346 size type, and its second character encodes the 8 foot nominal height, so it is not a high cube. Carriers do file it in the ISO field, so it is recognised there as well as in the short-code field.
45R140' High Cube Reefer
22T120' Tank
22KL, 22K020' Tank for Liquids and Gases
42T140' Tank
22U1, 20U120' Open Top
42U140' Open Top
45U140' High Cube Open Top
22P120' Flat Rack
22P320' Flat Collapsible
42P140' Flat Rack

Milestone status codes

Every value containers[].events[].status can carry. The vocabulary is position-aware: one movement code means a different milestone before the loading port, at the loading port, at a transshipment hub, at the port of discharge and on an inland move past it. Two rules do most of the work. Cargo state, not journey position, separates the gate pairs, so an empty release is never confused with a laden gate-out and an empty return is never confused with a laden gate-in. And sea milestones are ordinal rather than matched on UN/LOCODE, so a shipment with a missing port code still splits correctly instead of collapsing into transshipments.

CodeMeaningWhen we emit itCaveat
CPSContainer picked up at the shipper.A pickup event before or at the port of loading.The same physical move at the destination is the laden gate-out (CGO). A pickup on a leg the carrier reports as rail, truck or barge is LTS.
CEPEmpty container released to the shipper.A gate-out the carrier reports as EMPTY, wherever it happens, including an unlocated depot. Also a gate-out at the loading port when no cargo state was reported.One wording-driven exception: an empty pickup the carrier calls merchant haulage is the release to the shipper (CEP), while a carrier-haulage empty pickup at a depot stays CPS. Nothing else infers CEP from position alone.
CGILaden gate-in at the port of loading.A gate-in that is laden, or that carries no cargo state, before the box reaches its destination. Also an arrival at the loading port, including a road or rail arrival there.A laden gate-in on an explicitly inland leg is LTS, not CGI.
CLLContainer loaded on the vessel at the port of loading.The first load of the itinerary.Ordinal, not matched on UN/LOCODE, so a shipment with a missing port code still splits correctly. An explicitly inland load is LTS.
VDLVessel departed the port of loading.The first departure of the itinerary.Ordinal, same rule as CLL. An explicitly inland departure is LTS.
VATVessel arrived at a transshipment hub.Any vessel arrival that is not the last sea arrival of the itinerary.An arrival before the first load, or after the final discharge, is land-side by construction and codes LTS. VAT and VAD are vessel concepts, and a box on a train is at neither.
CDTContainer discharged at a transshipment port.Any discharge the box later sails away from, and any discharge the carrier itself words as a transshipment.A discharge is the final one only when no sea load or departure follows it. A box discharged at a hub and still waiting for its onward vessel stays CDT, so an arrival is never announced a month early in the wrong country.
TSDTransshipment delay.A status-only row carrying no movement: no event code, no event family, no conveyance, type sea. Recognised from the carrier exact wording on a row carrying no classifiable code, which covers both an uncoded notice and the DELAY code some lines file.It is not a discharge. It can appear beside a CDT at the same instant and place, because they are two separate facts.
CLTContainer loaded at a transshipment hub.Any load that is not the first of the itinerary.
VDTVessel departed a transshipment hub.Any departure that is not the first of the itinerary.
BTSBarge transshipment: the barge or feeder leg serving an inland port.Only where the carrier own wording names both a barge or feeder and an inland port.Deliberately biased to precision. Where a feeder IS the carriage rather than an ancillary leg, the ordinary ocean codes apply, so some genuine barge legs read CLT, VDT or CDD instead. Neither the conveyance nor the journey position reproduces this code, and we do not guess it.
VADVessel arrived at the port of discharge.The last sea arrival of the itinerary, and only when the box never sails again after it.
CDDContainer discharged at the final port of discharge.The last discharge with no onward sea leg after it. An availability notice at the destination folds onto the same milestone.Two of our movement codes can reach this milestone at one port. Where they land on the same instant that is one physical discharge reported twice and it is folded to a single row; where they land on different instants they are two facts and both rows are returned (see the duplicates note).
CGOLaden gate-out at the destination.A gate-out or pickup once the box is at or past the port of discharge.Cargo state decides the gate pairs, not position: an EMPTY gate-out is a release (CEP) wherever it occurs, and only a laden or unstated one at the destination is CGO.
CDCContainer delivered to the consignee.Only where the carrier entire statement is the delivery itself, matched against a short list of unambiguous phrases.Narrow on purpose, and this is a difference worth knowing. Measured against captured carrier envelopes, a broader positional or wording rule rewrites hundreds of correct empty returns into a wrong code, so a delivery whose wording is indistinguishable from a gate-out or an empty return keeps that code instead. We would rather under-emit CDC than write a wrong value into your database.
CEREmpty container returned.A gate-in the carrier reports as EMPTY, anywhere. Also a gate-in with no cargo state once the box is at or past the destination.The carrier explicit indicator wins where it exists. Most rows carry none, and an EMPTY stated only in the carrier prose is honoured as well.
LTSInland transport stage: land pre-carriage or on-carriage.Any load, discharge, departure, gate move or arrival on a leg the carrier explicitly reports as rail, truck or barge. Also a gate-out or arrival before the box reaches its loading port, and an arrival after the port of discharge.LTS is a category of inland movement, not a once-per-journey milestone. Several LTS rows at one place are normal (an inland origin routinely files both an arrival and a departure) and they are never collapsed onto each other.
UNKNNo milestone definition applies to this event.A gate move at a sea transshipment hub or at no place at all, and ancillary codes with no evidenced milestone: stuffing, stripping, customs inspection, customs release, release and availability notices.The spelling is version-dependent. Version 2026-08-04 emits the four-letter UNKN and version 2027-02-01 emits the three-letter UNK for the same value. An unpinned request keeps UNKN. Either way the row keeps its date, its place and the carrier own description: we would rather carry an unclassified row than force a wrong milestone onto it.

type and transport_type

These two fields are the pair most migrations map first, and they derive from the same signal, so an event can never read as land while claiming a vessel. An explicit conveyance from the carrier always wins. Where the carrier reports none in a structured field we read its own event wording on an unambiguous whole-word match, and where there is no signal at all a vessel operation is sea and everything else is land.

transport_typetypeWhen we emit it
VESSELseaAn ocean leg. Also the default for a load, discharge, departure or arrival where the carrier reports no mode.
BARGEseaA barge or inland-waterway leg. It rides water, so it is typed sea, and it legitimately names its hull.
RAILlandAn intermodal rail leg, reported by the carrier either in a structured mode field or unambiguously in its own event wording.
TRUCKlandA road leg, and also the fallback for any land-side move where no mode was reported. Read it as not a sea leg rather than as a claim that a truck was used.
nullseaOnly on the transshipment delay notice (TSD), which carries no conveyance at all.

The route block

Four anchor points. On a bill of lading that expanded into per-box timelines the route is derived from the union of those timelines, so it can only ever cite a date you can find elsewhere in the same payload. Each point carries location, date and actual, and only pod carries predictive_eta.

PointWhat it isHow we resolve it
prepolThe inland origin move before the sea leg.The first gate or pickup event ahead of the first load or departure. Falls back to the pol location, with a null date and a null actual, when there is no inland origin move.
polPort of loading.Anchored on the vessel departure, falling back to the first load. The departure is preferred because a door or rail origin files an inland load first, which would otherwise put the loading port inland and the departure date days early.
podPort of discharge: where the box leaves the ship.The last vessel discharge the box never sails away from, and never a discharge the carrier itself calls a transshipment. This is NOT the inland destination on a door or ramp move: that belongs to postpod.
postpodThe inland destination move after the final discharge.The last availability or gate event past the port of discharge. On a multi-box bill of lading this is the last box back to the depot, which is what closes the demurrage clock. Falls back to pod when there is no on-carriage move.

Shipment status

The value carried by metadata.status and by containers[].status.

ValueMeaning
PLANNEDBooked, not yet departed.
IN_TRANSITEverything from the origin port through discharge, availability and customs hold.
DELIVEREDDelivered, or returned empty.
UNKNOWNNothing has resolved yet, or the booking was cancelled.

Errors

This surface follows the incumbent convention: a not-found or still-resolving reference is HTTP 200 with { "status": "error" } and a machine code in message, never a 4xx. Only transport-level failures use a 4xx status, and those carry prose in message with data null.

NO_TRACKING_INFO200

A well-formed reference with no data yet: not found on the identified line, or still resolving. Retry shortly. The body is { "status": "error", "message": "NO_TRACKING_INFO", "data": {} } plus an additive detail string, which strict parsers can ignore.

WRONG_NUMBER200

The reference has been determined invalid. Same envelope, and the machine code again rides in message rather than in the HTTP status. Where a container number fails its ISO 6346 check digit, detail names the corrected number when one exists.

message carries prose, not a code400

No number (or container) was supplied. data is null.

message carries prose, not a code401

The api_key is missing, unknown, revoked or expired. data is null.

message carries prose, not a code403

The entitlement on this key has expired. data is null.

message carries prose, not a code429

The per-organisation burst throttle tripped, or the plan allowance is spent. data is null.

Machine-readable spec

The full schema, including the milestone status enum above, is published as OpenAPI 3.1 at /compat/openapi.json. Import it into Postman or Insomnia, or generate a typed client with openapi-generator.

curl 'https://api.trackingmcp.com/compat/searates/tracking?api_key=tmcp_YOUR_API_KEY&number=MEDU1234562&type=BK&carrier=COSU'
Response
{
  "status": "success",
  "message": "OK",
  "data": {
    "metadata": {
      "type": "CT",
      "number": "ONEU1234567",
      "sealine": "ONEY",
      "sealine_name": "ONE",
      "status": "DELIVERED",
      "is_status_from_sealine": false,
      "from_cache": false,
      "updated_at": "2026-08-19 10:16:04",
      "cache_expires": "2026-08-19 15:25:18",
      "api_calls": {
        "total": 10000,
        "used": 438,
        "remaining": 9562
      },
      "unique_shipments": {
        "total": 650,
        "used": 61,
        "remaining": 589
      }
    },
    "locations": [
      {
        "id": 1,
        "name": "Lagos",
        "state": null,
        "country": "Nigeria",
        "country_code": "NG",
        "locode": "NGLOS",
        "lat": 6.43427,
        "lng": 3.34088,
        "timezone": "Africa/Lagos"
      },
      {
        "id": 2,
        "name": "Apapa",
        "state": null,
        "country": "Nigeria",
        "country_code": "NG",
        "locode": "NGAPP",
        "lat": 6.43427,
        "lng": 3.34088,
        "timezone": "Africa/Lagos"
      }
    ],
    "facilities": [
      {
        "id": 1,
        "name": "SIFAX CONTAINER TERMINAL",
        "country_code": "NG",
        "locode": "NGLOS",
        "bic_code": null,
        "smdg_code": null,
        "lat": null,
        "lng": null,
        "code_source": "derived"
      }
    ],
    "route": {
      "prepol": {
        "location": 1,
        "date": "2026-05-01 09:00:00",
        "date_local": "2026-05-01 10:00:00",
        "utc_offset_minutes": 60,
        "timezone": "Africa/Lagos",
        "actual": true
      },
      "pol": {
        "location": 2,
        "date": "2026-05-30 00:30:00",
        "date_local": "2026-05-30 01:30:00",
        "utc_offset_minutes": 60,
        "timezone": "Africa/Lagos",
        "actual": true
      },
      "pod": {
        "location": 4,
        "date": "2026-06-27 04:23:00",
        "date_local": "2026-06-27 11:23:00",
        "utc_offset_minutes": 420,
        "timezone": "Asia/Ho_Chi_Minh",
        "actual": true,
        "predictive_eta": "2026-06-27 04:23:00"
      },
      "postpod": {
        "location": 6,
        "date": "2026-07-04 08:19:00",
        "date_local": "2026-07-04 15:19:00",
        "utc_offset_minutes": 420,
        "timezone": null,
        "actual": true
      }
    },
    "vessels": [
      {
        "id": 1,
        "name": "ONE PRESENCE",
        "imo": 9444273,
        "call_sign": null,
        "mmsi": 563290200,
        "flag": "SG"
      }
    ],
    "containers": [
      {
        "number": "ONEU1234567",
        "iso_code": "45G1",
        "size_type": "40' High Cube Dry",
        "status": "DELIVERED",
        "is_status_from_sealine": false,
        "events_mirrored": false,
        "events": [
          {
            "order_id": 1,
            "location": 1,
            "facility": 1,
            "description": "Empty Container Release to Shipper",
            "event_type": "EQUIPMENT",
            "event_code": "GTOT",
            "dcsa_event_code": "GTOT",
            "dcsa_event_family": "EQUIPMENT",
            "empty_indicator": "EMPTY",
            "status": "CEP",
            "date": "2026-05-01 09:00:00",
            "event_local_datetime": "2026-05-01T10:00:00",
            "utc_offset_minutes": 60,
            "event_timezone": "Africa/Lagos",
            "actual": true,
            "is_date_from_sealine": true,
            "is_additional_event": false,
            "type": "land",
            "transport_type": "TRUCK",
            "vessel": null,
            "voyage": null
          },
          {
            "order_id": 2,
            "location": 2,
            "facility": null,
            "description": "Gate In to Outbound Terminal",
            "event_type": "EQUIPMENT",
            "event_code": "GTIN",
            "dcsa_event_code": "GTIN",
            "dcsa_event_family": "EQUIPMENT",
            "empty_indicator": null,
            "status": "CGI",
            "date": "2026-05-06 15:54:00",
            "event_local_datetime": "2026-05-06T16:54:00",
            "utc_offset_minutes": 60,
            "event_timezone": "Africa/Lagos",
            "actual": true,
            "is_date_from_sealine": true,
            "is_additional_event": false,
            "type": "land",
            "transport_type": "TRUCK",
            "vessel": null,
            "voyage": null
          }
        ]
      }
    ],
    "route_data": {
      "route": [
        {
          "path": [
            [
              6.439312000000001,
              3.3588620000000446
            ],
            [
              6.448505,
              3.358891999999969
            ]
          ],
          "type": "LAND",
          "transport_type": "TRUCK",
          "from": {
            "name": "Lagos",
            "state": "Lagos State",
            "country": "Nigeria",
            "country_code": "NG",
            "locode": "NGLOS",
            "lat": 6.4395,
            "lng": 3.3585,
            "timezone": "Africa/Lagos"
          },
          "to": {
            "name": "Apapa",
            "state": "Lagos State",
            "country": "Nigeria",
            "country_code": "NG",
            "locode": "NGAPP",
            "lat": 6.4488,
            "lng": 3.35901,
            "timezone": "Africa/Lagos"
          },
          "vessel": null
        },
        {
          "path": [
            [
              6.4488,
              3.3590000000000373
            ],
            [
              6.041325,
              3.1174062499999877
            ],
            [
              5.633849999999999,
              2.875812499999938
            ]
          ],
          "type": "SEA",
          "transport_type": "VESSEL",
          "from": {
            "name": "Apapa",
            "state": "Lagos State",
            "country": "Nigeria",
            "country_code": "NG",
            "locode": "NGAPP",
            "lat": 6.4488,
            "lng": 3.35901,
            "timezone": "Africa/Lagos"
          },
          "to": {
            "name": "Singapore",
            "state": null,
            "country": "Singapore",
            "country_code": "SG",
            "locode": "SGSIN",
            "lat": 1.28967,
            "lng": 103.85007,
            "timezone": "Asia/Singapore"
          },
          "vessel": {
            "name": "ONE PRESENCE",
            "imo": 9444273,
            "call_sign": "9VMY9",
            "mmsi": 563290200,
            "flag": "SG"
          }
        }
      ],
      "pin": [
        27.9392
      ],
      "source": {
        "provider": "trackingmcp",
        "provider_name": "TrackingMCP",
        "route_geometry": "trackingmcp_computed",
        "ais": "trackingmcp_vessel_positions",
        "note": "Route geometry is computed by TrackingMCP; AIS position is from TrackingMCP vessel tracking."
      },
      "pin_source": "vessel_position",
      "ais": {
        "data": {
          "vessel": {
            "imo": 9629914,
            "flag": "JP",
            "mmsi": 431225000,
            "name": "ONE CONTRIBUTION",
            "call_sign": "7KPZ"
          },
          "last_event": {
            "date": "2026-07-04 08:19:00",
            "voyage": null,
            "description": "Container gate in"
          },
          "updated_at": "2026-08-19 10:16:04",
          "arrival_port": {
            "code": "TYO",
            "locode": "JPTYO",
            "date": "2026-08-08 06:00:00",
            "date_label": "ETA",
            "country_code": "JP"
          },
          "departure_port": {
            "code": "CMP",
            "locode": "VNCMP",
            "date": "2026-06-29 01:08:00",
            "date_label": "ATD",
            "country_code": "VN"
          },
          "discharge_port": {
            "code": "CMP",
            "locode": "VNCMP",
            "date": "2026-06-27 13:18:00",
            "date_label": "ATA",
            "country_code": "VN",
            "name": "Cai Mep"
          },
          "last_vessel_position": {
            "lat": 27.9392,
            "lng": 121.9139,
            "updated_at": "2026-08-19 10:16:16"
          }
        },
        "status": "OK"
      }
    }
  }
}

This endpoint reproduces a published interface so customers can migrate without rewriting their integration. Every field meaning on this page is derived from our own implementation. The tracking data is our own.