DataShift Logo

Shipments

post/{connectorId}/shipmentscreateShipment

Create a shipment

Submits a booking to the carrier. On success, returns an `orderNumber` and `consignmentNumber` (if assigned immediately by the carrier). **Collection time rules (TNT AU):** `collectionDateTime` must be 07:00–17:00, `collectionCloseTime` must be 13:00–19:00, and the window between them must be ≥ 120 minutes — all evaluated as wall-clock time local to the `collection` address, not a fixed national zone (a WA collection is checked against WA local time, not AEST). Violations return 400 with a structured `errors[]` list.

Parameters

NameInRequiredDescription
connectorIdpath✓Database ID of the carrier connector account (from `GET /connectors`)

Responses

201Booking created successfully
BookingResponse
400Invalid request — validation failed, the carrier rejected the input, or `rateId` could not be linked (`code: QUOTE_NOT_FOUND`: the rate does not exist for this tenant, connector and `serviceCode`, or does not belong to the supplied `quoteId`). Nothing is booked at the carrier when `QUOTE_NOT_FOUND` is returned.
Error
401Missing or invalid API key
Error
403Freight access is not active for this tenant, or the API key lacks the scope this endpoint requires
Error
404Connector not found or not active for this tenant
Error
410`code: QUOTE_EXPIRED` — the quote that `rateId` belongs to is more than 48 hours old and can no longer be linked to a booking. Nothing is booked at the carrier; request fresh rates and book with the new `rateId`.
Error
429Too many requests for this API key — see Retry-After header
Error
502Carrier API returned an error or is unavailable
Error
get/shipmentslistShipments

List shipments

Returns shipments for the authenticated tenant, sorted by `createdAt` (most recent first unless `sortDirection=asc`). Poll this endpoint to detect when `consignmentNumber` becomes available for carriers that assign it asynchronously. **Pagination:** `offset` is an exact row skip — `offset=30&limit=50` returns rows 31–80 of the filtered, sorted result. `total` counts every shipment matching the filters. The response echoes the effective `limit` and `offset`. **Filters** combine with AND. `createdFrom` is inclusive and `createdTo` exclusive; a bare date (`YYYY-MM-DD`) means 00:00:00Z that day. **Scope:** requires `bookings:read` (implied by `bookings:write`). Invalid query parameters return 400 with `errors[]` naming each field.

Parameters

NameInRequiredDescription
limitquery—Number of shipments to return (1–200, default 50). Non-numeric values are rejected with 400.
offsetquery—Exact number of shipments to skip (default 0). Non-numeric values are rejected with 400.
statusquery—Only shipments with this status
carrierquery—Comma-separated carriers, e.g. `TNT_AU,TGE_AU`
sourcequery—Only shipments booked via the API or the portal
createdFromquery—Inclusive lower bound on `createdAt`. ISO 8601 date (`YYYY-MM-DD`, meaning 00:00:00Z) or date-time with `Z` or an offset.
createdToquery—Exclusive upper bound on `createdAt`. Same formats as `createdFrom`; must be after it.
deliveredquery—`true` returns only shipments with a recorded `deliveredAt`. `false` is not supported yet (400) — omit the parameter to include undelivered shipments.
customerReferencequery—Exact match on `customerReference` (max 100 characters)
searchquery—Case-insensitive substring match across order number, consignment number, carrier booking reference, customer reference, receiver company, destination suburb and destination postcode (max 200 characters)
sortDirectionquery—Sort direction on `createdAt` (default `desc`)

Responses

200Shipment list
ShipmentListResponse
400Invalid query parameter
Error
401Missing or invalid API key
Error
403Freight access is not active for this tenant, or the API key lacks the scope this endpoint requires
Error
429Too many requests for this API key — see Retry-After header
Error
get/shipments/{id}getShipment

Get shipment detail

Returns full detail for a single shipment including sender, collection, and receiver addresses, item dimensions, and booking metadata. Requires `bookings:read` (implied by `bookings:write`).

Parameters

NameInRequiredDescription
idpath✓Datashift shipment ID (from booking response or `GET /shipments`)

Responses

200Shipment detail
ShipmentDetailResponse
401Missing or invalid API key
Error
403Freight access is not active for this tenant, or the API key lacks the scope this endpoint requires
Error
404Connector not found or not active for this tenant
Error
429Too many requests for this API key — see Retry-After header
Error
get/tracktrackByConsignment

Track by consignment number

Returns live tracking information for a shipment identified by its carrier consignment number. **Lookup strategy:** 1. If `carrier` is given, queries that carrier's connector directly — no shipment lookup, no fan-out. Use this when you already know the carrier (e.g. from your own shipment record) for a faster, unambiguous result. 2. Otherwise, searches your booked shipments for a matching `consignmentNumber`. If found, queries that carrier directly. 3. If no match in your shipments and no `carrier` given, fans out to all active carrier connectors and returns the first non-null result. **Carrier support:** TNT AU, BEX AU, and TGE AU all support tracking. TNT AU and TGE AU return proof-of-delivery (`pod`) on a delivered shipment (TGE: `signedBy` only) — see the `TrackingInfo` schema. **Polling:** Some carriers (BEX AU) process consignments asynchronously after booking. If tracking returns `supported: true` but `tracking: null`, wait 30–60 seconds and retry.

Parameters

NameInRequiredDescription
consignmentquery✓Carrier consignment number to look up (e.g. the `consignmentNumber` from a booking response)
carrierquery—Optional. Scopes the lookup to a single carrier, skipping the shipment-match and fan-out steps. Recommended when you already know the carrier.

Responses

200Tracking result. Check `supported` — if false the carrier does not expose a tracking API.
TrackingResponse
400Missing `consignment` query parameter, or `carrier` is not a recognized carrier
Error
401Missing or invalid API key
Error
403Freight access is not active for this tenant, or the API key lacks the scope this endpoint requires
Error
404Consignment not found in your shipments and no active carrier returned tracking data, or (with `carrier` given) no active connector exists for that carrier
Error
429Too many requests for this API key — see Retry-After header
Error
get/shipments/{id}/labelgetShipmentLabel

Get shipment label

Returns the PDF shipping label for a booked shipment. **Label availability:** Most carriers (including TNT AU) generate the label at booking time. If the label is not yet available, this endpoint returns 404 with `code: LABEL_NOT_AVAILABLE` — poll with exponential backoff until it becomes available. **Response format:** `application/pdf`. Save as a file or pipe directly to a label printer.

Parameters

NameInRequiredDescription
idpath✓Datashift shipment ID (from booking response or `GET /shipments`)

Responses

200PDF label
401Missing or invalid API key
Error
403Freight access is not active for this tenant, or the API key lacks the scope this endpoint requires
Error
404Shipment not found, or label not yet available from the carrier. Check `code` — `LABEL_NOT_AVAILABLE` means retry; anything else means the shipment ID is wrong.
LabelNotAvailableError
409Shipment has been cancelled in DataShift — no label is served for a cancelled shipment.
Error
429Too many requests for this API key — see Retry-After header
Error
post/shipments/cancel/eligibilitycheckShipmentCancelEligibility

Check shipment cancel eligibility

**DataShift-only cancellation — read this first.** None of DataShift's carriers (TNT AU, BEX AU (Border Express) and TGE AU) expose a cancel API today. Cancelling a shipment through DataShift only marks it cancelled in DataShift — the carrier is never called or notified, and `carrierNotified` in every response from this API is always `false`. If the label has already been printed and handed to the carrier (or is likely to be, e.g. it's on a manifest or a pickup has been booked), destroy it — cancelling here does not stop the carrier from collecting or invoicing the freight. Pure read — this endpoint never cancels anything. Call it before `POST /shipments/cancel` to show the caller what will happen: which ids are blocked (and why) and which will succeed with a warning. **Scope:** requires `bookings:read` or `bookings:cancel`. **Blocking reasons** (`results[].code` when `eligible: false`): `NOT_FOUND`, `ALREADY_CANCELLED`, `DELIVERED`, `IN_CARRIER_NETWORK` (collected, tracking-scanned, or already in transit / out for delivery / exception). **Warnings** (`results[].warnings[].code`, stack independently, only on an eligible result): `MANIFESTED` (already sent to the carrier on a manifest — expect a charge; cancelling anyway requires `acknowledgeManifestedIds` containing its id, or `acknowledgeManifested: true`, on the actual cancel call), `PICKUP_BOOKED` (a pickup is booked; informational only, some carriers auto-book pickups so this doesn't block). An id that doesn't belong to your tenant (or doesn't exist at all) comes back exactly like any other blocked id — `{ eligible: false, code: 'NOT_FOUND' }` — never a 404, so this can't be used to probe whether an id exists in another tenant.

Responses

200Per-id eligibility, in the same (deduped) order as the request
CancelEligibilityResponse
400Invalid request — validation failed or carrier rejected input
Error
401Missing or invalid API key
Error
403Freight access is not active for this tenant, or the API key lacks the scope this endpoint requires
Error
429Too many requests for this API key — see Retry-After header
Error
post/shipments/cancelcancelShipments

Cancel shipments (DataShift only)

**DataShift-only cancellation.** No carrier is called or notified — see `POST /shipments/cancel/eligibility` above for the full caveat. `carrierNotified` is always `false`. Requires the `bookings:cancel` scope specifically; `bookings:write` alone does not grant it. Runs eligibility fresh for every id (not trusting a stale client-side check). A manifested shipment is skipped with `MANIFEST_ACK_REQUIRED` unless its id is in `acknowledgeManifestedIds` or `acknowledgeManifested: true` is given. Prefer `acknowledgeManifestedIds`: it covers only the shipments you checked, so one manifested after your eligibility check is skipped rather than cancelled unseen. **Required acknowledgement:** `acknowledgeCarrierNotNotified` must be exactly `true`. Missing or `false` returns 422 `CARRIER_ACK_REQUIRED` — distinct from a generic validation 400 so you can prompt specifically for that acknowledgement. **Response:** `cancelled` (ids actually cancelled), `skipped` (ids that weren't, each with a `code` — the same blocking codes as the eligibility endpoint, plus `MANIFEST_ACK_REQUIRED`), `carrierNotified: false`, and `warning` (always present, the DataShift-only caveat as text — surface it to the end user). `manifestedWarning` is present only when at least one cancelled shipment had already been manifested.

Responses

200Cancel outcome — check `skipped` for any ids that were not cancelled
CancelShipmentsResponse
400Invalid request — validation failed or carrier rejected input
Error
401Missing or invalid API key
Error
403Freight access not active for this tenant, or the API key lacks the `bookings:cancel` scope (note: `bookings:write` alone is not sufficient)
Error
422Missing or false `acknowledgeCarrierNotNotified`
Error
429Too many requests for this API key — see Retry-After header
Error