π½ Downstream API - send to π
Base URL:
https://api.dockflow.com/v3(orhttps://uat.dockflow.com/v3for the sandbox)
Endpointsβ
| Method | Path | Description |
|---|---|---|
| POST | /downstream/tradeflows | Create a tradeflow or update an existing one. Accepts a single object or an array. |
| DELETE | /downstream/tradeflows/{tradeflow_reference} | Deactivate a tradeflow.?hard=true β permanently delete. |
1 Β· Create / update tradeflows POST /downstream/tradeflowsβ
Payload formatβ
A single JSON object or an array of objects.
{
"tradeflow_reference": "PO4564268", // required
// Tracking references β string OR array
"container_reference": [
{
"reference": "ABCD1234567",
"custom_properties": {
"requires_inspection": true,
"quality_check_date": "2025-05-01"
}
},
{
"reference": "EFGH7654321",
"custom_properties": {
"requires_inspection": true,
"quality_check_date": "2025-05-01"
}
}
],
"container_references_complete": true,
"bill_of_lading_reference": "ANR00001010",
"booking_reference": ["94512540", "94512888"],
// Tradeflow status
"active": true, // optional
// Carrier name
"carrier_name": "Maersk", // optional
"carrier_scac": "MAEU", // optional
// Partner shortcuts
"customer_name": "Fruit Maker EXIM International",
"customer_reference": "PO_12345_CUST", // optional
"partners": [
{
"name": "Best Forwarder BV",
"role": "forwarder",
"reference": "PO_4564268",
"lead_contact": "[email protected]" // optional - email of lead contact at partner
}
],
"partners_complete": false,
// Team assignment
"team_name": "Sales Team EMEA", // optional
// Lead contact - individual responsible for this tradeflow
"lead_contact": "[email protected]", // optional - email or full name
// Voyage metadata
"port_of_loading": "BEANR",
"port_of_discharge": "USLAX",
"estimated_time_of_departure": "2025-05-14T12:00:00Z",
// or - when vessel has already departed
"actual_time_of_departure": "2025-05-14T12:00:00Z",
"estimated_time_of_arrival": "2025-06-06T22:00:00Z",
// or - when vessel has already arrived
"actual_time_of_arrival": "2025-06-06T22:00:00Z",
"vessel": "Maersk SOPHIE",
"incoterms": "FOB",
"references": {
"house_bill_of_lading": "hbl_123456789", // optional house bill of lading reference
"delivery_location": "Factory yard 12345", // optional, stored as a free-text reference
"delivery_event_date": "2021-08-24T15:00:25+00:00" // optional, stored as a free-text reference
},
// Optional self-defined events
"events": [
{
"message": "delivery at client",
"container_reference": "ABCD1234567",
"location_name": "BEANR", // 5-character UN/LOCODE; any other value leaves the event without a location
"event_date": "2025-05-12T08:34:00Z",
"actual": true // whether the event already happened β or is scheduled
}
],
// Per-tradeflow / per-container free-time overrides (PATCH, append-only)
"free_time_overrides": [
{ "dwell_type": "equipment_free_time_in_port", "free_days": 14 },
{ "dwell_type": "equipment_free_time_out_of_port", "free_days": 7,
"container_reference": "ABCD1234567" }
],
// NEW Β· Arbitrary key-value pairs defined by you
"custom_references": {
"invoice_number": "INV-12345",
"priority": 2,
"quality_check_date": "2025-05-01",
"requires_inspection": true
}
}
custom_references β what & whyβ
| Field | Type | Description |
|---|---|---|
custom_references | object | A free-form dictionary whose keys are fully user-defined. Each value should be a string, number, boolean, or ISO-8601 date. Use it for anything that doesnβt fit the prescribed schema (e.g. internal IDs, workflow flags, etc.). |
- Values are stored as text. Use flat values only; do not nest objects or arrays.
- Keys are case-sensitive. A key you have not used before is created for your organisation.
- Sending
nullor an empty string for a key removes that property from the tradeflow; the stringsnulland#nullare ignored.
Complete-list flagsβ
| Flag | Applies to | Effect when true |
|---|---|---|
container_references_complete | container_reference[] | Containers not listed are removed. |
bill_of_lading_references_complete | bill_of_lading_reference[] | Same logic. |
booking_references_complete | booking_reference[] | Same logic. |
partners_complete | partners[] | Partners not listed are removed. |
If a _complete flag is omitted, the list is merged instead of replaced.
Partner inputβ
customer_nameβ quick way to add one partner with rolecustomer.partnersβ full array that supports multiple roles and references. Both inputs may be combined.
Team assignmentβ
team_nameβ assigns an existing team to the tradeflow.- Must be an existing team (minimum 3 characters)
- First searches your organization, then partner organizations involved in the tradeflow
- Case-insensitive matching (e.g., "Sales Team EMEA" matches "sales team emea")
- If no matching team is found in any involved organization, the field is silently ignored
Lead contactβ
A lead contact is the individual user accountable for a tradeflow. They appear in the "My Tradeflows" view and receive assignment notifications. See the Lead Contact guide for the full feature overview.
lead_contacton the tradeflow root β the person responsible for the whole shipment on your side.lead_contacton a partner object β the person responsible at that partner organization.
Accepted values (in order of reliability):
| Format | Example | Notes |
|---|---|---|
[email protected] | Recommended β unambiguous exact match | |
| Full name | Sophie Dupont | Matched against first_name + last_name, word separators are flexible |
Matching rules:
- Must resolve to an existing user within your organization (for the root-level field) or the partner organization (for the partner-level field).
- If the user belongs to a different entity than the one being set, the lead contact is also propagated to that entity's tradeflow record.
- If no user matches, the field is silently ignored β the tradeflow is still created/updated without a lead contact.
Free time overridesβ
Per-tradeflow and per-container overrides for free-time monitoring (demurrage, detention, storage, electricity). Useful when a contract grants a one-off extension or grace period that should win over the global free-time rules.
| Field | Type | Required | Description |
|---|---|---|---|
dwell_type | string (enum) | yes | One of the 5 modern dwell types - see list below. |
free_days | integer β₯ 0 | yes* | Number of free days for this override. Required unless cancelled: true. Zero is valid. |
container_reference | string | no | ISO 6346 container reference. If present and valid, the override is scoped to that container. If absent, the override is tradeflow-wide. |
cancelled | boolean | no | When true, cancels the override at this scope. free_days is ignored. |
Accepted dwell_type values:
equipment_free_time_in_port- equipment free time at the portequipment_free_time_out_of_port- equipment free time after gate-outequipment_free_time_combined- combined pool (carriers like Evergreen, or Maersk on some lanes)storage_free_time- terminal storage above carrier demurrageelectricity_free_time- reefer electricity free time
Semantics:
- PATCH, append-only. Listed scopes are upserted; unlisted scopes are untouched. Re-posting the same value is a no-op (idempotent). An empty array
[]is also a no-op. - Scope precedence. A per-container override wins over a tradeflow-wide override for that container; tradeflow-wide applies to all other containers. A cancellation at one scope does not affect the override at the other scope.
- Cancellation. Send
{ "dwell_type": "...", "cancelled": true }(optionally with acontainer_reference) to clear the override at that exact scope. - Pre-creation. A per-container override may be authored before the container is added to the tradeflow; it is picked up automatically once the container appears.
- Effective downstream. Once accepted, the override is reflected in the upstream API output, in graph-tp transport plans, and in the free-time-exceeded flag generation (typically within a few minutes due to the cron's cooldown).
Invalid entries (unknown dwell_type β the older names destination_demurrage and destination_detention are not accepted, non-numeric or negative free_days) are silently skipped. A malformed container_reference is ignored and the entry is treated as tradeflow-wide.
Response 202 Acceptedβ
Processing is asynchronous. The response acknowledges each queued item:
{
"status": "queued",
"tradeflows": [
{
"tradeflow_reference": "PO4564268",
"warnings": []
}
]
}
warnings is reserved for soft-fail feedback and is currently always empty β a value that fails a
soft-fail rule is ignored silently. To see what Dockflow did with a payload, open the tradeflow in
the app and use Download βΈ Download V3 API, or read it back from
the upstream API. Hard-fail rules are reported synchronously as
400 Bad Request.
2 Β· Remove tradeflows DELETE /downstream/tradeflows/{tradeflow_reference}β
| Action | How |
|---|---|
| Deactivate (preferred) | DELETE /downstream/tradeflows/PO4564268 β same effect as posting "active": false. |
| Permanent delete | DELETE /downstream/tradeflows/PO4564268?hard=true |
Returns 204 No Content on success.
Bulk deleteβ
Using * as the tradeflow_reference deactivates every tradeflow of the organisation the token
belongs to. Add ?hard=true for permanent deletion.
DELETE /downstream/tradeflows/*
| Environment | Behaviour |
|---|---|
| UAT | Allowed as-is. |
| Production | Requires ?confirm=PRODUCTION. Without it the call is refused with 400 Bad Request; every accepted production bulk delete is logged. When the organisation has no tradeflows, the call returns 404. |
Validation rulesβ
The request is accepted with 202 Accepted as long as the body is valid JSON and is an object or an
array of objects; otherwise it is refused with 400 Bad Request. Everything else is processed after
the response, and an invalid value is skipped silently while the rest of the payload is applied.
Check the outcome in the app or via the upstream API.
tradeflow_reference is required. An item without a usable (non-blank) reference is not imported.
Values that are skipped silently:
container_referencenot matching^[A-Z]{4}[0-9]{7}$after upper-casing and removing spaces and hyphens.- Empty strings or null values inside array fields.
- Dates that cannot be parsed (use ISO-8601, or
YYYYMMDDforestimated_time_of_arrival). port_of_loading/port_of_dischargethat are not a 2-letter ISO country code or a 5-character UN/LOCODE.carrier_nameorcarrier_scacshorter than 4 characters.customer_nameshorter than 2 characters; partnernameof 2 characters or fewer.incotermsof 2 characters or fewer.- Bill of lading and booking references shorter than 5 characters.
team_nameshorter than 3 characters or not matching an existing team.lead_contactthat matches no existing user.- Unknown top-level properties (outside
custom_references). - On the UAT host,
customer_nameandpartnersare not processed.
When active is omitted, an inactive tradeflow is reactivated only if its arrival is in the future,
or, with no arrival date, if it was created within the last two months. "active": false deactivates it.
Error codesβ
| Status | Meaning |
|---|---|
| 400 Bad Request | Body is not valid JSON, or not an object or array. Also Token format invalid. |
| 401 Unauthorized | Missing or malformed Authorization header, or unknown token. |
| 403 Forbidden | Token environment does not match the host (prod_ vs uat_), or the token is revoked. |
| 404 Not Found | Tradeflow not found on delete. |
| 500 Internal Server Error | Unexpected error during processing. |
Questions or feedback? Create an issue in the public repository or contact Dockflow support.