Upcoming sailings
Published sailings between two ports, soonest departure first. One entry per carrier offer, so two lines selling the same ship appear as two sailings, each with its own deadlines. Routing comes with the schedule; the field table says what each part means. Every schedule time (departure, arrival, cut-offs, leg times, the window) is the local time of its own port, written without a timezone offset, the way the line publishes it; the two stamps that say when we read or saw something (retrieved_at, last_changed_at, as_of, checked_at) are UTC instants with an offset. It never answers 404: a lane with nothing in the window is a 200 with an empty sailings list. Paged: follow the next link until it is null. By default one routing per departure; routings=all adds the other routings the line publishes. This endpoint needs an API key: send it as Authorization: Bearer. It keeps its /public path, so an existing integration adds the header and changes nothing else.
Counted: 1 call for each answer that carries data. Free: a search that found nothing (200 with an empty sailings list), the following pages of a search fetched through its next link, and any refusal or error. See how calls are counted.
Query parameters
Origin port UN/LOCODE, e.g. CNSHA
Destination port UN/LOCODE, e.g. NLRTM
First departure date to consider, YYYY-MM-DD, matched against each sailing's port-local departure date; today or later, default today.
Window length in weeks from from: 4, 8 or 12, default 4.
One or more four-character SCAC codes, comma-separated or repeated; omitted means every carrier.
true for sailings with transshipment, false for direct sailings only, omitted for both; any other value is refused.
Only sailings new to us, or whose published departure or arrival moved, since this moment; pass back your last as_of.
all returns every routing the line published for each departure, not just the main one.
Sailings per page, 1 to 500, default 100; a value outside the range is refused, not clamped.
An opaque continuation token that next already carries; omit it on the first page and never build or edit it.
Response schema
71 fields
Nested exactly as the JSON is. Open a branch to read its fields; hover a name for the full dot-path.
True on every answer that carries data; an error answers false with error instead.
data
The lane, the window used, the per-line summary and this page of sailings.
The origin UN/LOCODE this answer was built for, which can be the canonical code rather than the one you sent.
The origin port's name, or its UN/LOCODE where we hold no name.
The destination UN/LOCODE this answer was built for, canonical in the same way as origin.
The destination port's name, or its UN/LOCODE where we hold no name.
Start of the window, 00:00 of the first departure date considered, port-local with no offset like published_departure.
End of the window, exclusive, in the same form as from: from plus weeks times seven days.
The window length in weeks this answer used.
How many sailings are on this page, not in the whole window.
One entry per line across the whole answer, most sailings first, on the first page only (null on later pages).
carriers[]
The line's SCAC, the same code its sailings carry in carrier_code.
The line's name, as on its sailings.
How many of this line's sailings the whole answer holds across every page, counted exactly as without routings=all.
This line's last departure in your window, port-local, or null when it has none there.
How this line's answer stands for the lane: ok, no_service, timeout, failed, not_attempted or not_supported.
When the line last confirmed this lane (its newest sailing here, or when we asked it), in UTC, or null when we hold no such date.
Kept for existing clients, read status instead; paused means two timeouts in a row, so we wait six hours before asking again.
True when the live search ran and every listed line is ok, no_service or not_supported, false when a missing sailing may be a gap, null when carriers is null.
The transshipment filter as we read it, or null for both kinds.
The changed_since you sent, as we read it, or null when the whole window was served.
The last departure anyone has filed on this lane, whatever your window and filters, port-local, or null when none.
Pass this back as changed_since on your next poll; it is taken before the read, so a delta can repeat a sailing but never skips one.
Port names for every hub code in transship_via on this page.
The page size this answer used: the limit you sent, or 100.
The next page's request, cursor included: follow it while present and stop only when it is null, never on a short or empty page.
This page's sailings, soonest departure first, in a stable order so paging neither drops nor repeats one.
sailings[]
The key to store this sailing under; it stays the same when the line moves the dates.
The line's SCAC; with a carrier filter, the code you asked for.
The line's trading name, or null where we hold none; program against carrier_code.
The line's own name for the service loop, as published, or null; not comparable across carriers.
The ship's name, TBN when the line has not named one yet, or null when it gave no ship.
The line's voyage number, or null when it has not assigned one.
The ship's IMO number, or null when we cannot say for certain which ship this is.
vessel
Particulars of the ship in vessel_imo, or null when we hold none for it.
Nominal capacity in TEU; read it with teu_estimated.
True when teu is derived from deadweight rather than published for the ship.
Flag state as a country name, as the vessel register spells it.
Year the ship was built, from the vessel register.
Ship's length in metres, from the vessel register.
Departure as the line publishes it, in the origin port's local time, with no offset; do not convert it.
Arrival as the line publishes it, in the destination port's local time, with no offset, or null when not published.
minute when the line published a departure time, day when only a date (the 00:00 is ours), null when unknown.
The same as departure_precision, for published_arrival.
Container yard cut-off, port-local with no offset; cutoffs holds every deadline and cutoff_status explains a null.
Documentation cut-off, port-local with no offset; cutoffs holds every deadline and cutoff_status explains a null.
VGM (verified gross mass) cut-off, port-local with no offset; cutoffs holds every deadline and cutoff_status explains a null.
Every deadline the line published for this sailing, or null when we hold none (see cutoff_status).
cutoffs[]
Normalised deadline code (DCSA where one exists, X- prefixed otherwise); filter and compare on this.
The deadline in the local time of its port, with no offset.
The line's own wording for the deadline, to show a person, or null when we hold none.
Why cut-offs are present or null: published, not_published (the line publishes none), or not_held (we hold none from this line; ask it directly).
When we last saw the line move the published departure or arrival, in UTC, or null if never; changed_since filters on this.
With routings=all only: true for an extra routing of the departure, false for its main one.
When the line last confirmed this sailing to us, in UTC; never older than 14 days.
The line's own transit time in days, or null when not published.
True when the box changes ship, false when it does not, null when we cannot tell.
Hub UN/LOCODEs on a transshipment, null otherwise.
The routing as the line filed it, one entry per leg in order, or null when we hold none (not the same as direct).
route_legs[]
Position of the leg in the routing, from 1.
The leg's departure port: a UN/LOCODE, or the line's own code where we hold no translation.
The departure port's name, or null where we hold none.
The leg's arrival port: a UN/LOCODE, or the line's own code where we hold no translation.
The arrival port's name, or null where we hold none.
The ship on this leg, TBN when not yet named, or null when the leg has no ship (see mode).
What the leg travels on: water and feeder are ships, rail, truck, barge and inland are not transshipment, unknown is a ship not yet named.
The line's voyage number for this leg, or null when not assigned.
The line's own service name for this leg, or null when not given.
Departure in the local time of this leg's port, with no offset.
Arrival in the local time of this leg's port, with no offset.
known when is_transshipment is true or false, unknown when it is null.
Errors
Every refusal is { "ok": false, "error": { "code", "message", "parameter"? } }. The code is stable and safe to branch on, the message is a sentence for a person, and parameter names the input at fault where one input is at fault. No refusal or error is counted as a call. This endpoint never answers 404. A lane with nothing in the window, or a filter that matches nothing, is not an error: it answers 200 with an empty sailings list, which is a true answer about the filter rather than about the lane, and is not counted either.
origin or destination was not given. `parameter` names the missing half, and neither when both are absent.
from is not a calendar date as YYYY-MM-DD, is not a real date (2026-02-30), carries a time or an offset, is more than a century ahead, or was given twice. `parameter` is from.
from is before today UTC. Schedules are forward-looking, so a past window is refused rather than quietly returning nothing. `parameter` is from.
weeks is not a window we can honour, or was given twice. `parameter` is weeks.
A value in carrier is not four characters of capitals and digits. The message lists the offending values, clipped. `parameter` is carrier.
transshipment is something other than true or false. Deliberately strict: 1, yes and TRUE are refused rather than half-accepted. `parameter` is transshipment.
changed_since is not a date or an instant in the formats above, is not a real date or time, is before 1970-01-01, or was given twice. `parameter` is changed_since.
changed_since is later than now. Refused rather than answered with an empty list, which would read as a lane that never changes. `parameter` is changed_since.
limit is not a whole number from 1 to 500. `parameter` is limit.
cursor cannot be read. Start the lane again without it. `parameter` is cursor.
A query we refuse before reading anything, free.
The key is missing, unknown, revoked or past its own expiry date. Not counted.
SchedulesMCP is not connected to your account. Not counted.
FORBIDDEN: the account has no Schedules access.
QUOTA_EXCEEDED: the account's call quota for the month, or the key's daily limit, is spent.
Too many requests in a short window. Wait Retry-After seconds. Not counted.
The read failed on our side. Nothing was filtered out, so a retry is safe.
Access could not be checked just now, so the request was not run. Retry after Retry-After. Not counted.
Per-line status: carriers
Each line gets a status, so zero sailings is no longer ambiguous: no_service (does not sail this window), timeout or failed (asked, no answer), not_attempted (not confirmed for this window), not_supported (no source). Check it before telling a person there are no sailings.
Is the answer complete: complete
true: the live search ran and every listed line is ok, no_service or not_supported. false: some line's answer may be incomplete (its status says which), or the live search did not run (never with transshipment) or was held back by our limits.
Is the routing known: routing_status
known: we can tell whether the box changes ship (direct, or via a named hub). unknown: we cannot, and is_transshipment is null.
Every routing a line publishes: routings=all
Adds the other routings the line publishes for the same departure, each marked is_alternative; without it the answer is unchanged. Use it to check ETD and ETA against the line's site or to choose a connection; priced as a normal search, and transshipment filters each routing on its own legs.
curl 'https://api.schedulesmcp.com/public/schedules?origin=CNSHA&destination=BRSSZ&weeks=4&transshipment=true&limit=2' \
-H "Authorization: Bearer smcp_YOUR_API_KEY"const res = await fetch("https://api.schedulesmcp.com/public/schedules?origin=CNSHA&destination=BRSSZ&weeks=4&transshipment=true&limit=2", {
headers: {
"Authorization": "Bearer smcp_YOUR_API_KEY"
}
});
const data = await res.json();import requests
res = requests.get(
"https://api.schedulesmcp.com/public/schedules?origin=CNSHA&destination=BRSSZ&weeks=4&transshipment=true&limit=2",
headers={"Authorization": "Bearer smcp_YOUR_API_KEY"},
)
data = res.json() {
"ok": true,
"data": {
"origin": "CNSHA",
"destination": "BRSSZ",
"origin_name": "Shanghai",
"destination_name": "Santos",
"from": "2026-10-15T00:00:00",
"to": "2026-11-12T00:00:00",
"weeks": 4,
"count": 2,
"carriers": [
{
"carrier_code": "CMDU",
"carrier_name": "CMA CGM",
"count": 6,
"latest_departure": "2026-11-09T16:00:00",
"status": "ok",
"checked_at": "2026-10-15T14:53:53.693+00:00"
},
{
"carrier_code": "MSCU",
"carrier_name": "Mediterranean Shipping Company (MSC)",
"count": 4,
"latest_departure": "2026-11-07T18:00:00",
"status": "ok",
"checked_at": "2026-10-15T13:27:49.497+00:00"
},
{
"carrier_code": "HDMU",
"carrier_name": "HMM",
"count": 3,
"latest_departure": "2026-11-04T12:00:00",
"status": "ok",
"checked_at": "2026-10-15T15:38:15.79+00:00"
},
{
"carrier_code": "HLCU",
"carrier_name": "Hapag-Lloyd",
"count": 3,
"latest_departure": "2026-11-09T13:00:00",
"status": "ok",
"checked_at": "2026-10-15T07:38:14.918+00:00"
}
],
"complete": false,
"transshipment": true,
"changed_since": null,
"latest_departure_held": "2027-04-30T10:30:00",
"as_of": "2026-10-15T18:30:05.234Z",
"next": "https://api.schedulesmcp.com/public/schedules?origin=CNSHA&destination=BRSSZ&weeks=4&transshipment=true&limit=2&cursor=MjAyNi0xMC0xOFQwNzowMDowMCswMDowMHw5YjI1YjA1MC0yMjc3LTQ0MjQtOTA0NS03NTZhYzE0OGQ5M2F8MTc5MjA4OTAwNTc4MnxJVjFSZ08zcEc2MlI4TENEQ2Q2c01oU3lDUHpqVkZDV1pfODJOMVFNaUVBfDIwMjYtMTAtMTh-fjNhQmFQbkVQYXJP",
"limit": 2,
"via_port_names": {
"COCTG": "Cartagena",
"ESVLC": "Valencia"
},
"sailings": [
{
"sailing_id": "dc4ce3a5-76f8-403d-acfe-67d650531281",
"carrier_code": "HLCU",
"carrier_name": "Hapag-Lloyd",
"service_name": "US2",
"vessel_name": "OSAKA EXPRESS",
"voyage_number": "640E",
"published_departure": "2026-10-16T13:00:00",
"published_arrival": "2026-12-05T13:00:00",
"departure_precision": "minute",
"arrival_precision": "minute",
"cy_cutoff": "2026-10-15T07:00:00",
"doc_cutoff": "2026-10-15T07:00:00",
"vgm_cutoff": "2026-10-15T01:00:00",
"is_transshipment": true,
"transship_via": [
"COCTG"
],
"transit_days": 50,
"route_legs": [
{
"leg": 1,
"from": "CNSHA",
"from_name": null,
"to": "COCTG",
"to_name": null,
"vessel": "OSAKA EXPRESS",
"mode": "water",
"voyage": "640E",
"service": "US2",
"departure": "2026-10-16T13:00:00",
"arrival": "2026-11-09T15:00:00"
},
{
"leg": 2,
"from": "COCTG",
"from_name": null,
"to": "BRSSZ",
"to_name": null,
"vessel": "JAZAN",
"mode": "water",
"voyage": "2644S",
"service": "GS1",
"departure": "2026-11-17T00:00:00",
"arrival": "2026-12-05T13:00:00"
}
],
"routing_status": "known",
"cutoffs": [
{
"type": "FCO",
"at": "2026-10-15T07:00:00",
"label": null
},
{
"type": "DCO",
"at": "2026-10-15T07:00:00",
"label": null
},
{
"type": "VCO",
"at": "2026-10-15T01:00:00",
"label": null
}
],
"cutoff_status": "published",
"last_changed_at": "2026-09-29T07:44:18.780979+00:00",
"retrieved_at": "2026-10-05T23:29:52.787+00:00",
"vessel_imo": "9320697",
"vessel": {
"teu": 8164,
"teu_estimated": false,
"flag": "Liberia",
"year_built": 2007,
"length_m": 335.47
}
},
{
"sailing_id": "9b25b050-2277-4424-9045-756ac148d93a",
"carrier_code": "MSCU",
"carrier_name": "Mediterranean Shipping Company (MSC)",
"service_name": "JADE SERVICE",
"vessel_name": "MSC CELESTINO MARESCA",
"voyage_number": "GJ640W",
"published_departure": "2026-10-18T07:00:00",
"published_arrival": "2026-12-16T01:00:00",
"departure_precision": "minute",
"arrival_precision": "minute",
"cy_cutoff": "2026-10-13T22:00:00",
"doc_cutoff": "2026-10-12T07:00:00",
"vgm_cutoff": "2026-10-13T22:00:00",
"is_transshipment": true,
"transship_via": [
"ESVLC"
],
"transit_days": 59,
"route_legs": [
{
"leg": 1,
"from": "CNSHA",
"from_name": "SHANGHAI",
"to": "ESVLC",
"to_name": "VALENCIA",
"vessel": "MSC CELESTINO MARESCA",
"mode": "water",
"voyage": "GJ640W",
"service": "JADE SERVICE",
"departure": "2026-10-18T07:00:00",
"arrival": "2026-11-25T18:30:00"
},
{
"leg": 2,
"from": "ESVLC",
"from_name": "VALENCIA",
"to": "BRSSZ",
"to_name": "SANTOS",
"vessel": "MSC MARIA MARILYN X",
"mode": "water",
"voyage": "MM647A",
"service": "WEST MED TO SAEC",
"departure": "2026-11-26T20:00:00",
"arrival": "2026-12-16T01:00:00"
}
],
"routing_status": "known",
"cutoffs": [
{
"type": "FCO",
"at": "2026-10-13T22:00:00",
"label": null
},
{
"type": "DCO",
"at": "2026-10-12T07:00:00",
"label": null
},
{
"type": "VCO",
"at": "2026-10-13T22:00:00",
"label": null
},
{
"type": "X-RCO",
"at": "2026-10-13T22:00:00",
"label": null
},
{
"type": "X-HCO",
"at": "2026-10-07T00:00:00",
"label": null
}
],
"cutoff_status": "published",
"last_changed_at": null,
"retrieved_at": "2026-10-15T13:27:49.497+00:00",
"vessel_imo": "9930040",
"vessel": {
"teu": 21445,
"teu_estimated": false,
"flag": null,
"year_built": 2023,
"length_m": 399.99
}
}
]
}
}