🔼 Upstream - receive from 🌐
Upstream API
The Upstream API is used to retrieve data from Dockflow to your system.
Carrier cut-offs (closings) for documents, cargo, VGM and dangerous goods are only available in the
Trident Upstream API, in the shipment.cutoffs field. This API only carries cargo_opening.
Methods (pull vs push)
The upstream API is available both on pull-basis ("polling mechanism", making GET-requests periodically to Dockflow), as well as on push-basis (new data is sent to a webhook).
Polling method - example request (GET)
Replace xxxxx with your API token for authorization.
curl "https://api.dockflow.com/upstream" -H "Authorization: xxxxx"
For the reference requests below, the Authorization header placeholder will be omitted. However, make sure to include it.
Push method - example configuration
The webhook can be configured using an Automation. The automation should be configured using the web GUI, as follows:

Make sure to also ENABLE the automation in the upper-right corner after configuration.
With the push method, every APIMessage is sent as its own POST request with a JSON body: one APIMessage object per request, in the scheme described below. Respond with a 2xx status to acknowledge it. The automation can be configured to leave out the shipment object, which then gives the same result as excluding it on a polling request.
Response
The response will contain the 500 most recent datapoints available from the last 24 hours.
Content will be a JSON array of APIMessage, with following scheme:
APIMessage {
hash: string; // Unique hash of this APIMessage
type: string; // Type of APIMessage - see below
tradeflow_reference: string | null; // Tradeflow reference as known for this client (e.g. PO)
tradeflow_id: number; // Dockflow's internal id of the tradeflow
bl_bk_references: string[]; // Bill of lading and booking references of the tradeflow, can be empty
message_generated_event_date: string; // ISO Date-string of when the message was generated
created_at: string; // ISO Date-string of when the message was stored
type_x_tradeflow_id: string; // e.g. "CONTAINER_MILESTONE_744140"
type_x_tradeflow_id_x_transport_unit_id: string; // e.g. "CONTAINER_MILESTONE_744140_HAMU2416136"; ends in "_" when the message is not about one container
calculated_size_in_kb: number;
payload: (...) // Payload of the APIMessage, depending on the type - see below
}
The updates are marked into 4 categories:
- SHIPMENT_CHANGE: Updates for a shipment. Can be related to a planned shipment or booking, or a group of containers on the same journey. Examples are: Vessel Departure, Vessel Arrival, Transshipment,...
- CONTAINER_MILESTONE: Updates for a specific container and its movements. Examples are: Empty Returned, Loaded on Vessel, Gate Out, Discharge, Vessel Arrival,...
- LOCATION_UPDATE: Periodic coordinates updates for a Vessel or Truck
Examples are: Vessel MSC Sophie is now at (
51.000145lat,4.584368lng) - updated every x minutes. - BASIC_STATUS: The most low-level update. Anything that happens in a tradeflow will be recorded as a BASICSTATUS, can be related to shipment, administration or container. Data is unfiltered and data quality is not guaranteed.
Examples are: _Tradeflow creation and deactivation, new predicted arrival, loaded on vessel,...
note
Requests can be modified to filter for specific messages, please see below for Filtering the request
infoIf you are unsure which reponse type you'll need, please contact support at [email protected]
warningBASIC_STATUS messages are returned from the API, but are not actively supported as an integration type.
Reading the schemes
The schemes below use TypeScript notation:
field: string | null- the field is always present, its value can benull.field?: number- the field is left out of the JSON when it does not apply. It is not sent asnull.
New fields can be added to any message without notice. Build your integration to ignore fields it does not know instead of rejecting the message. A field marked ? only appears on some messages, so its absence in your test data does not mean it will never be sent.
The current payload version is 3 (api_message_version). Accounts that are configured on version 2 or lower receive the same payloads without the following fields: api_message_version, bl_bk_references, emission_calculation, change.terminal_location, dwell_details.combined_free_time_expires and dwell_details.storage_free_time_expires.
SHIPMENT_CHANGE
An APIMessage with type SHIPMENT_CHANGE will contain a payload in following scheme:
APIMessage {
// Some generic attributes - see above
// (...)
// Specific payload:
payload: {
type: string; // "SHIPMENT_CHANGE"
api_message_version: number; // 3
has_live_data: boolean; // Has this tradeflow received data from a live source (carrier, terminal, AIS,...), not only from API/manual input?
normalized_data_anomaly: number | null; // Data anomaly score of the tradeflow, 0 when no anomaly was detected
// Change: the actual change in the shipment data
change: {
actual: boolean; // Is the change actual (true) or predicted (false)
move_type: string; // "arrival" or "departure"
reading: string | null; // ISO Date-string of the (predicted) arrival or departure
reading_event_date_extended: ExtendedDate | null; // `reading` in local time - see generic scheme below
predicted_at: string; // ISO Date-string reading for when this change was received
location: Location; // Port of this change - see generic scheme below
terminal_location: Location | null; // Terminal within the port, when known
terminal_location_id: number | null; // Dockflow's id of that terminal
is_pol: boolean; // Is this change for the Port Of Loading?
is_final_pod: boolean; // Is this change for the final Port Of Discharge?
is_transshipment_location: boolean; // Is this change about a T/S location?
transshipment_sequence_ref?: number; // Only when is_transshipment_location is true - see PortCall below
booking_reference: string | null; // Booking reference
bill_of_lading_reference: string | null; // Bill of lading reference
cargo_opening: string | null; // Cargo opening time (cut-offs/closings: Trident API only)
vessel: Vessel | null; // Vessel data - see generic scheme below
carrier: Entity | null; // Carrier data - see generic scheme below
containers: Container[]; // Array of containers involved - see generic scheme below
emission_calculation: EmissionCalculation | null; // see generic scheme below
};
// + the full shipment data after the change above has been processed - see generic scheme below
shipment: Shipment | null;
};
}
}
CONTAINER_MILESTONE
An APIMessage with type CONTAINER_MILESTONE will contain a payload in following scheme:
APIMessage {
// Some generic attributes - see above
// (...)
// Specific payload:
payload: {
type: string; // "CONTAINER_MILESTONE"
api_message_version: number; // 3
has_live_data: boolean; // see SHIPMENT_CHANGE
normalized_data_anomaly: number | null; // see SHIPMENT_CHANGE
status_code: string; // Standardized status code for this milestone - see Status codes below
message: string; // Free-text message as received for this milestone
actual: boolean; // Is the milestone actual (true) or predicted (false)
event_date: string | null; // ISO Date-string for the milestone event
event_date_extended: ExtendedDate; // `event_date` in local time - see generic scheme below
predicted_at: string | null; // ISO Date-string reading for when this change was received
is_latest_actual: boolean; // Is this the most recent actual milestone of the container?
is_latest_actual_POI: boolean; // Is this the most recent actual milestone at a port of interest (port of loading or final port of discharge)?
location: Location | null; // Location of this milestone - see generic scheme below
is_pol: boolean; // Did this milestone happen at the Port Of Loading?
is_final_pod: boolean; // Did this milestone happen at the final Port Of Discharge?
is_transshipment_location: boolean; // Did this milestone happen at a T/S location?
transshipment_sequence_ref?: number; // Only when is_transshipment_location is true - see PortCall below
transport_unit_reference: string; // container reference (e.g. ABCD1234567)
booking_reference: string | null; // Booking reference
bill_of_lading_reference: string | null; // Bill of lading reference
carrier: Entity | null; // Carrier data - see generic scheme below
vessel: Vessel | null; // Vessel the container is on for this milestone, when applicable
// A history of predicted dates for this milestone
history: Array<{
actual: boolean; // Is the milestone actual (true) or predicted (false)
source: string; // Free-text source of this predicted date
event_date: string | null; // ISO Date-string for the milestone event
predicted_at: string; // ISO Date-string reading for when this change was received
}>;
container_details: Container | null; // see generic scheme below
emission_calculation: EmissionCalculation | null; // see generic scheme below
// + the full shipment data after this milestone was processed - see generic scheme below
shipment: Shipment | null;
// + the dwell details: always an object, each field only present when it can be calculated
dwell_details: {
demurrage_free_time_expires?: string; // calculated ISO DateTime-string after which free time on quay has expired (demurrage fees start)
detention_free_time_expires?: string; // calculated ISO DateTime-string after which free time after pick-up has expired (detention fees start)
combined_free_time_expires?: string; // calculated ISO DateTime-string after which combined demurrage and detention free time has expired
storage_free_time_expires?: string; // calculated ISO DateTime-string after which storage free time has expired
conflict_resolution?: string; // "superseded_by_combined": a combined free time rule applies, demurrage and detention above then both equal combined_free_time_expires
}
};
}
}
LOCATION_UPDATE
Location updates will contain following payload:
{
"lat": 0.28404334187508,
"lng": 9.5067262649536,
"type": "LOCATION_UPDATE",
"event_date": "2026-10-01T07:55:09Z",
"vessel_name": "DOUALA EXPRESS",
"booking_reference": "",
"bill_of_lading_reference": "15973563"
}
booking_reference and bill_of_lading_reference are always strings, and empty ("") when unknown.
Shipment types
With some APIMessage-types, the full shipment details will be included:
interface Shipment {
containers: Container[];
transport_plan_legs: TransportPlanLeg[];
is_solid: boolean; // Does the shipment have at least one known sea leg?
sequence_number?: number;
carbon_emission_proxy_calculation?: {
direct_point_to_point_km: number; // Sum of the port-to-port distances of all sea legs
result: number; // Rough CO2 estimate in tonnes
};
}
interface TransportPlanLeg {
type: string; // "SeaShipment"
carrier: Entity | null;
booking_number: string | null;
bill_of_lading_number: string | null;
sequence_number: number;
sea_shipment_legs: SeaShipmentLeg[];
}
interface SeaShipmentLeg {
carrier: Entity | null;
carrier_transport_unit: Vessel | null;
departure: PortCall;
arrival: PortCall;
}
// The departure from or arrival at one port
interface PortCall {
type: string; // "departure" or "arrival"
actual: boolean;
location: Location;
carrier: Entity | null;
carrier_transport_unit: Vessel | null;
containers: Container[];
reading_log: ReadingLog[];
internal_voyage_sequence_reference: number; // How many earlier calls with the same move type, port and vessel precede this one
is_pol: boolean; // Port Of Loading
is_final_pod: boolean; // Final Port Of Discharge
is_transshipment_location: boolean;
transshipment_sequence_ref: number | null; // Position of this transshipment port in the journey: 1 for the first T/S port after the POL, 2 for the second,... null when is_transshipment_location is false
is_prepol: boolean; // Pre-carriage stop before the actual Port Of Loading (e.g. barge or rail terminal)
is_postpod: boolean; // On-carriage stop after the actual Port Of Discharge
latest_reading: string | null; // ISO Date-string of the latest known (predicted or actual) date
latest_reading_extended: ExtendedDate | null;
latest_reading_source: string | null;
latest_reading_predicted_at: string | null;
latest_provisional_reading: string | null;
latest_confirmed_reading: string | null;
first_confirmed_reading: string | null;
first_known_reading: string | null;
}
interface ReadingLog {
reading: string; // ISO Date-string of the (predicted) arrival or departure
event_date: string; // ISO Date-string of when this reading was received - note: not the date of the event itself
actual: boolean;
source: string;
is_latest: boolean;
is_provisional: boolean; // Was this reading received before the actual departure of the vessel?
is_latest_provisional: boolean;
less_valid: boolean;
}
interface Location {
name: string;
unlocode: string | null;
timezone: string;
coordinates: Coordinates | null;
country: Country | null;
}
interface Country {
name: string;
iso_a2: string;
}
interface Coordinates {
lat: number;
lng: number;
long: number; // Same value as lng
}
interface Container {
reference: string;
container_type: string | null;
container_length: number | null;
container_is_reefer: boolean | null;
}
interface Entity {
name: string;
}
interface Vessel {
name: string;
imo_number: string | null;
mmsi_number: string | null;
}
interface ExtendedDate {
event_date_zulu: string | null; // e.g. "2026-09-27T01:24:00.000Z"
event_date_local: string | null; // e.g. "2026-09-27T02:24:00.000+01:00"
timezone_geo: string | null; // e.g. "Africa/Casablanca"
timezone_abbreviation: string | null; // e.g. "+01" or "CEST"
timezone_utc_offset_minutes: number | null; // e.g. 60
}
interface EmissionCalculation {
distance_km: number;
co2_emissions_kg: number;
ttw_kg: number; // Tank-to-wheel emissions
wtt_kg: number; // Well-to-tank emissions
calculation_configs: {
provider: string;
};
}
Status codes
Following status codes can be returned:
| Code | Description |
|---|---|
| GE | empty equipment dispatched |
| GN | gate in |
| AE | loaded on vessel |
| VD | vessel departure |
| VA | vessel arrival |
| UV | unloaded from vessel |
| GT | gate out |
| GR | empty equipment returned |
Filtering the request
Filter the request using a request parameter. These filters can be combined.
Filter for updates created since date
Use this to filter your request for recently created updates.
curl "https://api.dockflow.com/upstream?since=2022-04-15T00:48:36+00:00"
Filter for a specific tradeflow
Use this to filter your request for a specific tradeflow
curl "https://api.dockflow.com/upstream?tradeflow=PO12134567"
Filter for a specific container
Use this to filter your request for a specific container
curl "https://api.dockflow.com/upstream?container=ABCD1234567"
Filtering for a container will never return SHIPMENT_CHANGE messages.
Filter for a type of update
Use this to filter your request for a specific update type
curl "https://api.dockflow.com/upstream?type=SHIPMENT_CHANGE"
Filter for only the latest update
Use this to filter for only the latest status / updates
curl "https://api.dockflow.com/upstream?latest=true"
Exclude data from return
You might want to exclude the full shipment details from the data, as follows:
curl "https://api.dockflow.com/upstream?excludes=shipment"
The shipment field is then left out of the payload entirely.
Pagination
Append per_page=x with x a positive integer between 1 and 500 to do paginated calls.
curl "https://api.dockflow.com/upstream?per_page=500"
The resulting response will be an object with 2 keys:
{
'next_cursor': string | null;
'data': [...]
}
To query for the next set of results, use the cursor string as follows:
curl "https://api.dockflow.com/upstream?per_page=500&cursor=[next_cursor string from response]"