Public one-off lookup
Resolve a single container, bill of lading or booking without an account. No key required. Rate-limited, and intended for a quick check rather than a portfolio.
Request body
Container number (4 letters + 7 digits), bill of lading, or booking reference.
Optional client-side guess: container_id, bill_of_lading or booking_number. The server refines it and returns what it actually resolved.
Optional SCAC hint. Omit it and we resolve the line ourselves.
Response schema
57 fields
Nested exactly as the JSON is. Open a branch to read its fields; hover a name for the full dot-path.
The response contract this build answers, as a date. Pin it in your client and nothing in the shape below moves under you.
False on a non-hit. The HTTP status is still 200, so branch on this and not on the status code.
data
The payload. Everything an endpoint returns sits under this key.
The container number, bill of lading or booking this record tracks.
What the identifier is. The keyed surface uses container_id, bill_of_lading or booking; the public tracker returns booking_number for the third.
Carrier SCAC.
Carrier name.
Current normalised status of the shipment. Ocean lifecycle order: discharged, available, delivered, returned_empty. Two values end a shipment, delivered and returned_empty, and returned_empty outranks delivered.
Arrival time (ISO 8601). Null when the carrier publishes none and we cannot predict one.
True when the ETA is still a forecast, false when it is the actual arrival, null when there is no ETA at all. Never read a date alone as a promise.
Origin code (airport IATA or UN/LOCODE).
Destination code (airport IATA or UN/LOCODE).
vessel
Vessel currently carrying the container, or null when we hold neither a name nor an IMO. Its lat and lng are always null here; the keyed endpoints carry the live position under vessel_position.
Human-readable name.
Latitude.
Longitude.
Milestone timeline, oldest to newest.
events[]
The carrier own phrasing for the event, falling back to our word for the code.
UN/LOCODE for the event, or null when the carrier gave no place.
Machine-readable event code, for example LOAD, DISC, GTIN, GTOT, ARRI, DEPA. Null when the carrier sent none.
UN/LOCODE port code. On a tracking event it is canonicalised, and null when the carrier named no port.
Event timestamp (ISO 8601), or null when the carrier gave none.
True when the event happened. False means it is planned or estimated, so never read it as a fact.
equipment
Equipment and cargo particulars, present only when the line publishes at least one of them. Absent entirely on a line that publishes none, which is not the same as a block full of nulls.
Equipment size and type as the carrier writes it, for example 40HC.
ISO 6346 size and type code as the carrier filed it, for example 45G1. Null when the carrier stated none.
Carrier seal on the box. Null unless the carrier publishes it, which most do not on a track response.
The scope of the move the carrier is performing, for example port to port or door to door. Null when unstated.
Verified gross mass, kilograms. Null until the shipper files a VGM and the carrier publishes it.
Gross weight of the loaded box, kilograms. Null when the carrier publishes none.
Pieces inside the box. Null when the carrier publishes no cargo particulars.
Unit the package count is in, for example CTN or PLT. Null with the count.
Cargo volume, cubic metres. Null when the carrier publishes none.
A special handling requirement filed on the shipment, for example a reefer set point. Null when none.
The particulars we asked for and this carrier does not publish. Read it as "the line does not expose this", never as "the shipment has none".
observability
Which of the four lenses we can offer on this shipment, and how many are active.
lenses
actuals (carrier milestones), position (the vessel), plan (a schedule) and probability (a confidence figure).
True when we hold carrier milestones.
True when we hold a vessel.
On LoadingMCP, the computed load plan. Inside a tracking observability lens, true when we hold a schedule for the shipment.
True when the ETA can carry a confidence figure.
How many of the four lenses are present.
line_correction
Present only when you named one carrier and the reference turned out to belong to another: what you searched, and what we found it under. Absent on a normal answer.
The SCAC you named.
That line by name.
The SCAC the reference actually belongs to.
That line by name.
The one sentence to show a user on a non-hit, already written for that purpose.
diagnosis
Why there is no answer, machine-readable, on every non-hit. It is the difference between a mistyped number and a real reference the line has not published yet.
What the reference was read as: container, bl or booking.
Whether a container number passes the ISO 6346 check digit: valid, invalid, or not_applicable on a bill of lading or booking.
The registered owner behind the prefix, when the prefix is registered. Null when it is not.
What that owner is: carrier, leasing, soc for a shipper-owned box, or unknown.
Our best single explanation: check_digit_typo, incomplete_reference, carrier_no_live_events, leased_needs_bl, soc_needs_bl, house_bl or unidentified_line.
What to do about it, in one sentence you can show a user as is.
Corrected container numbers, present only on a check-digit typo. At most two, and each one passes the check digit.
Errors
A failure on an open endpoint answers { "ok": false } with a human-readable message. Branch on the status code.
The body carried no reference. Open endpoints answer { "ok": false, "message": … } rather than the coded envelope.
We could not resolve the reference with any line. The message explains what we tried, and suggests a corrected check digit when the number is one digit off.
Over the per-IP daily cap. The body carries "gated": true. Anything portfolio-shaped belongs on the keyed surface.
curl -X POST 'https://api.trackingmcp.com/v1/track/public' \
-H "Content-Type: application/json" \
-d '{"reference":"MEDU1234562"}' const res = await fetch("https://api.trackingmcp.com/v1/track/public", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
"reference": "MEDU1234562"
})
});
const data = await res.json(); import requests
res = requests.post(
"https://api.trackingmcp.com/v1/track/public",
json={
"reference": "MEDU1234562"
},
)
data = res.json() {
"api_version": "2026-08-04",
"ok": true,
"data": {
"identifier": "MEDU1234562",
"identifier_type": "container_id",
"carrier_code": "MSCU",
"carrier_name": "MSC",
"status": "in_transit",
"eta": "2026-07-03T06:00:00Z",
"eta_is_estimated": true,
"origin": "Ningbo",
"destination": "Rotterdam",
"vessel": {
"name": "MSC TERESA",
"lat": null,
"lng": null
},
"events": [
{
"description": "Loaded on vessel",
"location": "Ningbo",
"event_code": "LOAD",
"unlocode": "CNNGB",
"datetime": "2026-06-18T22:10:00Z",
"actual": true
}
],
"equipment": {
"size_type": "40HC",
"iso_code": "45G1",
"seal_number": null,
"move_type": "CY/CY",
"vgm_kg": null,
"gross_weight_kg": 24680,
"package_count": 1120,
"package_unit": "CTN",
"measurement_cbm": null,
"service_requirement": null
},
"not_published_by_carrier": [
"seal_number"
],
"observability": {
"lenses": {
"actuals": true,
"position": true,
"plan": true,
"probability": true
},
"active_count": 4
}
},
"line_correction": {
"searched_code": "HLCU",
"searched_name": "Hapag-Lloyd",
"found_code": "MSCU",
"found_name": "MSC"
}
} This preview uses documented example data and makes no live request. Get a key to run live.