Skip to main content

Migrate from Cargoes Flow

A client built for Cargoes Flow can talk to Dockflow by changing two values: the base URL and the API key.

note

There is no public specification to test this surface against. The first migration runs together with Dockflow and validates the shapes on this page, including the event codes and the webhook body. Contact [email protected] to plan it.

What to change​

SettingBeforeAfter
Base URLYour Cargoes Flow hosthttps://api.dockflow.com/compat/cargoes-flow
X-DPW-ApiKeyYour Cargoes Flow keyA Dockflow API key
X-DPW-Org-TokenYour organisation tokenAccepted and ignored. It can stay.

The path /flow/api/public_tracking/v1 also works under that base, so a client that only swaps the host needs no path change.

Get a token​

  1. Sign in to the API Console and open API Keys.
  2. Click Create Key, choose the Production environment and the Downstream scope.
  3. Copy the key. It is shown only once.

See Authorization for the key format and for revoking a key.

What is covered​

RouteWhat it does
GET /shipmentsA bare array. Filters: shipmentType, status, shipmentNumber, mblNumber, containerNumber, awbNumber, search, includeUniqueContainers, _page, _limit.
POST /createShipmentsformData rows with uploadType: FORM_BY_MBL_NUMBER start tracking.
PUT /updateShipmentsSends shipper, consignee and extra fields to an existing shipment.
POST /uploadDocumentMultipart files and shipmentNumber.
GET /mapRoutes?shipmentNumber=The legs as routes. Empty until a plan exists.
GET /carrierListThe carriers Dockflow knows.

There is no delete route.

_page starts at 1. _limit defaults to 20, at most 100. The newest shipment comes first. search is an exact match on bill of lading, booking, container, reference or shipment number.

One row per shipment or per container​

One master bill of lading is one Dockflow tradeflow, with the reference CARGOES-FLOW-<MBL> and the shipment number DF<id>.

  • Without includeUniqueContainers: one row per shipment. containerNumber is the first box and containerNumbers lists all boxes.
  • With includeUniqueContainers, or with a containerNumber filter: one row per box. A row has its own events plus the events no box owns, and every row keeps the same shipmentNumber.

_limit counts shipments, so a page can hold more rows than _limit when it is expanded per box.

Answers and errors​

CaseAnswer
Create or update succeeds200 with result: SUCCESS and errorDetail: []. A create adds shipments with shipmentNumber, mblNumber and created.
A row is refused200 with result: FAILED and errorDetail[].error. Rows are all or nothing: one bad row means nothing is created or updated.
A body that is not JSON, or an invalid list parameter400 with result: FAILED.
mapRoutes for an unknown shipment404 with result: FAILED.
A refused keyThe Dockflow body {"error": "...", "status": 401}. See Authorization.

Field mapping​

Create and update​

FieldDockflow
mblNumberBill of lading reference.
bookingNumberBooking reference.
incotermIncoterms.
oceanLineCarrier SCAC when it is four letters, carrier name otherwise.
shipper, consigneePartners with that role.
shipmentReference, promisedEta, promisedEtd, shipmentTags, demurrage fieldsCustom references. They never feed the transport plan. GET /shipments reads promisedEta and promisedEtd back.

Events​

Dockflow codecode
GEgateOutEmpty
GNgateInFull
AEloadedOnVessel
VDvesselDeparture, or vesselDepartureWithContainer when the event names a container
VAvesselArrival, or vesselArrivalWithContainer when the event names a container
UVdischargeFromVessel
GTgateOutFull
GDdelivered
GRgateInEmpty

At a transshipment port the code stays the same and the name adds "at transshipment". Any other Dockflow event keeps its own code and message, with isCustomEvent: true.

Status​

  • status is ACTIVE for an active shipment and COMPLETED otherwise.
  • subStatus1 comes from the latest actual event of the table: AT_ORIGIN, IN_TRANSIT, AT_DESTINATION, DELIVERED or EMPTY_RETURNED. A transshipment event is IN_TRANSIT.
  • subStatus2 is the code of that event.
  • shipmentType is AIR_SHIPMENT for a shipment with air events and INTERMODAL_SHIPMENT otherwise.

Port fields such as firstPort, lastPort and an event's location carry UN/LOCODEs. origin and destination on a segment carry names.

Fields Dockflow adds​

shipmentType, containerNumbers, awbNumber, shipmentEvents[].containerNumber, and on each segment originPortCode, originLatitude, originLongitude, destinationLatitude and destinationLongitude.

What stays empty​

FieldValue
emissions.co2e.valuenull.
shipmentLegs.road{}.
promisedEta, promisedEtdnull in webhook bodies and on the upstream feed. Only GET /shipments fills them.
loadingPort, dischargePortnull when no call carries that port role.
segments[].transportModenull on a leg before the port of loading or after the port of discharge, and on a leg with no known vessel.
carrierScac, bookingNumber, event fieldsnull where Dockflow holds no value.

In carrierList, supportsTrackByMbl and requiresMbl are true and supportsTrackByBookingNumber is false, because create accepts only a bill of lading. All rows are INTERMODAL_SHIPMENT.

Webhooks​

Contact [email protected] to add a destination in the cargoes-flow format. You receive its signing secret once. It cannot be read again.

Each delivery is one POST whose body is the shipment object of GET /shipments, without the promised dates. The first migration validates this body. Retries, timeouts and ordering follow Webhook delivery.

HeaderValue
X-Dockflow-Signaturesha256=<hex>: HMAC-SHA256 of the exact body with your signing secret.
X-Dockflow-TimestampUnix seconds. It is not signed, so it gives no replay protection.

Verify the signature​

Compute the HMAC over the exact bytes you received, before any JSON parsing:

import hashlib, hmac

def is_authentic(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header)

How to test​

  1. Create a key with the UAT environment and the Downstream scope. It works on https://uat.dockflow.com/compat/cargoes-flow and writes to your UAT organisation. A real number is really tracked there.
  2. Create a shipment:
curl -X POST https://uat.dockflow.com/compat/cargoes-flow/createShipments \
-H "X-DPW-ApiKey: uat_acme-logistics_Zk3n1c0Q2m9..." \
-H "Content-Type: application/json" \
-d '{"uploadType":"FORM_BY_MBL_NUMBER","formData":[{"mblNumber":"ANR00001010","oceanLine":"MAEU"}]}'
  1. Read it with GET /shipments?shipmentNumber=DF74123, using the number from the answer. The import runs after the answer, so the first read can be short.
  2. To test a webhook, open the destination in the console and click Send test with the Live tradeflow scenario, naming the reference CARGOES-FLOW-<MBL> of a tradeflow that has data. The Ocean basic scenario is refused for this format.

Polling is also possible: GET /v3/upstream?format=cargoes-flow with an Upstream key returns these records. See Upstream filters.

Was this page helpful?