DataShift
FreightAPI Reference

Shipments | Freight API

Freight API reference for shipments: book a consignment from a quote, retrieve its status and tracking, and cancel it where the carrier allows.

Create a shipment

POST
/{connectorId}/shipments

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.

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Path Parameters

connectorId*string

Database ID of the carrier connector account (from GET /connectors)

Request Body

application/json
  1. body

BookingRequest plus a required packages array. POST /{connectorId}/shipments needs the authoritative per-package weight/dimension breakdown (not just the flattened items total) so the carrier consignment payload carries one line per physical package with its own real weight, rather than an averaged weight applied to every line.

sender*
collection*

Collection address — often the same as sender but can differ (e.g. a warehouse pickup for an office-based account).

receiver*
items*
packagingCode*string

Packaging type: CT — Carton, BX — Box, SA — Satchel, PA — Pallet, EN — Envelope, CR — Crate, DR — Drum, RO — Roll, BG — Bag, PC — Piece. Sent to TNT AU as PackagingCode; TGE AU uses it to derive the shipment item description (it has no packaging-code field of its own).

Value in"CT""BX""SA""PA""EN""CR""DR""RO""BG""PC"
serviceCode*string

Carrier service code from a prior getRates call

collectionDateTime*string

Pickup ready time, in wall-clock time local to the collection address (no TZ suffix — TNT AU's own rule is "in the Collection Location", never a fixed national zone). On TNT AU must be 07:00–17:00, ≥ 120 minutes before collectionCloseTime.

Match^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$
collectionCloseTime*string

Premises close time, local to the collection address, as an hhmm string. On TNT AU must be 13:00–19:00.

Match^\d{4}$
payer*

Who is billed for this shipment.

Validation rules (returned as 400 errors[] entries with these code values):

  • PAYER_ACCOUNT_REQUIRED — accountNumber is required when type is Receiver or ThirdParty (all carriers).
  • TNT_THIRD_PARTY_UNSUPPORTED — TNT AU has no third-party billing concept; type: ThirdParty is rejected on TNT AU connectors. Bill the receiver and supply their TNT account number instead.
businessUnit?string

Selects which TGE AU business unit config (account code / ShipmentID range) to use. Ignored by carriers other than TGE AU.

Value in"IPEC""PRIORITY_AU"
dangerousGoods*boolean
dangerousGoodsDetails?

Required when dangerousGoods is true.

customerReference?string
Lengthlength <= 24
specialInstructions?string
Lengthlength <= 30
alertAddresses?array<>

TNT AU — email/SMS notifications for shipment events.

keepInStore?

TNT AU — hold shipment at depot rather than attempting delivery.

pickupBookingNumber?string

TNT AU — pre-arranged pickup booking reference

extendedWarranty?

TNT AU — declare shipment value for extended warranty coverage.

foodFreight?boolean

TNT AU — mark shipment as food freight

bexAlerts?array<>

BEX AU — email notifications for shipment events.

timeSensitive?

BEX AU — request a time-sensitive delivery. Provide either timeslot (specific appointment) or deliveryWindow (date range with optional time bounds).

pallets?

BEX AU — pallet exchange configuration for CHEP and/or LOSCAM.

customerBarcodes?array<>

BEX AU — customer-supplied barcodes to associate with the consignment (max 50 chars each)

rateId?string

Links this booking to one specific offered rate from a prior getRates call (that rate's rateId field — renamed from quoteId on the rate object; see the breaking-change note below). DataShift verifies it belongs to your tenant and matches the connector/serviceCode being booked, then uses its price/ETA/transit rather than the raw quoted* fields below. Rejected if the rate's quote is more than 48 hours old. Optional: omitting it (including a caller still sending the pre-rename quoteId field name, which is no longer read here) is treated exactly like never having rate-shopped through DataShift at all — the booking proceeds using the raw quoted* fields below, unverified. This is intentional, not an error: it's the same fallback bookings without any rate-shop call have always used. Breaking change: before this field existed, booking requests sent this same link as quoteId. That name now means something else entirely (see below) — a caller still sending the old quoteId field to link a rate will have it silently ignored rather than rejected, and should switch to rateId.

quoteId?string

The rate-shop call rateId came from (the response's top-level quoteId) — a different value from the old, pre-rename meaning of quoteId on a booking request (which used to mean what rateId means now). Optional, and only checked when rateId is also supplied — if both are given and they don't actually belong together, the booking is rejected.

quotedPriceExGstMinor?integer

Ex-GST price of the quote this was booked from, in minor currency units (cents). Only used when rateId is not supplied — informational, recorded as reported, not independently verified.

quotedGstMinor?integer

GST component, in minor units. Only used when rateId is not supplied; when omitted for an AUD price it is derived at 10% (recorded as quotedGstSource: DERIVED).

quotedPriceIncGstMinor?integer

Inc-GST price, in minor units. Only used when rateId is not supplied; when omitted for an AUD price it is quotedPriceExGstMinor + quotedGstMinor.

quotedCurrency?string
committedEta?string

The quote's ETA, echoed back at booking time: the carrier ETA string (as in RatedService.eta) or a YYYY-MM-DD date (as in RatedService.etaDate). Only used when rateId is not supplied.

quotedTransitDays?integer

The quote's transitDays (business days), echoed back at booking time. Only used when rateId is not supplied.

bookingCutoff?string

The quote's bookingCutoff, echoed back at booking time.

collectionCutoff?string

The quote's collectionCutoff, echoed back at booking time.

packages*array<>
Items1 <= items

Response Body

Booking created successfully

application/json
  1. response
orderNumber*string

Booking reference issued by the carrier.

consignmentNumber?string

Consignment/tracking number. Present immediately for some carriers (e.g. TNT AU); null for carriers that issue it asynchronously.

barcodes?array<string>

Carrier-issued barcode numbers for individual items in the consignment (BEX AU only)

shipmentId*string

Datashift shipment ID — use with GET /shipments/{id}, GET /shipments/{id}/label, and POST /shipments/{id}/print

connectorId*string
pickupStatus?string

Outcome of the connector's auto-book-pickup setting, if enabled. NOT_BOOKED if auto-booking is off — call POST /pickups to book one explicitly. FAILED means no pickup exists at the carrier — safe to retry. RECONCILE_NEEDED means the carrier accepted the pickup but DataShift failed to save the record — a real pickup exists, do NOT retry (that would book a second one); labelWarning carries the carrier's pickup reference to reconcile manually. This response's own orderNumber field above is NOT updated to reflect it, and RECONCILE_NEEDED is only ever reported here — GET /shipments/{id}'s pickupStatus has no record to compute it from and will read NOT_BOOKED instead, though its orderNumber may pick up the carrier reference later if a best-effort background sync succeeds.

Value in"NOT_BOOKED""BOOKED""FAILED""RECONCILE_NEEDED"
labelWarning?string

Present when the pickup booking failed or needs reconciliation (see pickupStatus) or the carrier returned a non-fatal warning alongside the label.

Example Request
curl -X POST 'https://datashift.com.au/api/freight/string/shipments' \  -H 'Content-Type: application/json' \  -d '{  "sender": {    "companyName": "Acme Pty Ltd",    "contactName": "Jane Smith",    "phoneAreaCode": "02",    "phoneNumber": "99999999",    "address1": "1 Test Street",    "suburb": "Sydney",    "state": "NSW",    "postcode": "2000"  },  "collection": {    "companyName": "Acme Pty Ltd",    "contactName": "Jane Smith",    "phoneAreaCode": "02",    "phoneNumber": "99999999",    "address1": "1 Test Street",    "suburb": "Sydney",    "state": "NSW",    "postcode": "2000"  },  "receiver": {    "companyName": "Test Receiver Co",    "contactName": "John Doe",    "phoneAreaCode": "03",    "phoneNumber": "88888888",    "address1": "2 Delivery Road",    "suburb": "Melbourne",    "state": "VIC",    "postcode": "3000"  },  "items": {    "count": 1,    "totalWeightKg": 5,    "maxLengthCm": 30,    "maxWidthCm": 20,    "maxHeightCm": 20  },  "packages": [    {      "count": 1,      "lengthCm": 30,      "widthCm": 20,      "heightCm": 20,      "weightKg": 5    }  ],  "packagingCode": "CT",  "serviceCode": "76",  "collectionDateTime": "2026-06-26T14:00:00",  "collectionCloseTime": "1700",  "payer": {    "type": "Sender"  },  "dangerousGoods": false,  "customerReference": "REF-001"}'
Example Response
{  "orderNumber": "SYD734506",  "consignmentNumber": "31073640400",  "shipmentId": "cm9x1a2b3c4d5e6f7g8h9i0j",  "connectorId": "conn_tnt_01"}

List shipments

GET
/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.

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Query Parameters

limit?integer

Number of shipments to return (1–200, default 50). Non-numeric values are rejected with 400.

Range1 <= value <= 200
Default50
offset?integer

Exact number of shipments to skip (default 0). Non-numeric values are rejected with 400.

Range0 <= value
Default0
status?string

Only shipments with this status

Value in"CONSIGNED""CANCELLED"
carrier?string

Comma-separated carriers, e.g. TNT_AU,TGE_AU

source?string

Only shipments booked via the API or the portal

Value in"API""PORTAL"
createdFrom?string

Inclusive lower bound on createdAt. ISO 8601 date (YYYY-MM-DD, meaning 00:00:00Z) or date-time with Z or an offset.

createdTo?string

Exclusive upper bound on createdAt. Same formats as createdFrom; must be after it.

delivered?"true"

true returns only shipments with a recorded deliveredAt. false is not supported yet (400) — omit the parameter to include undelivered shipments.

Value in"true"
customerReference?string

Exact match on customerReference (max 100 characters)

Lengthlength <= 100
search?string

Case-insensitive substring match across order number, consignment number, carrier booking reference, customer reference, receiver company, destination suburb and destination postcode (max 200 characters)

Lengthlength <= 200
sortDirection?string

Sort direction on createdAt (default desc)

Default"desc"
Value in"asc""desc"

Response Body

Shipment list

application/json
  1. response
total*integer

Total number of shipments matching the filters (may exceed the current page)

limit*integer

Page size used for this response

offset*integer

Offset used for this response

shipments*array<>
Example Request
curl -X GET 'https://datashift.com.au/api/freight/shipments'
Example Response
{  "total": 1,  "limit": 50,  "offset": 0,  "shipments": [    {      "id": "cm9x1a2b3c4d5e6f7g8h9i0j",      "carrier": "TNT_AU",      "connectorName": "TNT AU (Production)",      "orderNumber": "SYD734506",      "consignmentNumber": "31073640400",      "carrierBookingRef": null,      "customerReference": "REF-001",      "status": "CONSIGNED",      "pickupStatus": "BOOKED",      "serviceCode": "76",      "serviceDescription": "Road Express",      "source": "API",      "fromSuburb": "Sydney",      "fromPostcode": "2000",      "fromState": "NSW",      "toSuburb": "Melbourne",      "toPostcode": "3000",      "toState": "VIC",      "receiverCompany": "Test Receiver Co",      "receiverName": "John Doe",      "pieceCount": 1,      "declaredWeightKg": 5,      "declaredCubicM3": 0.012,      "quotedPriceExGstMinor": 1818,      "quotedGstMinor": 182,      "quotedPriceIncGstMinor": 2000,      "quotedCurrency": "AUD",      "committedEta": "2026-06-26T17:00:00.000Z",      "quotedTransitDays": 1,      "collectionDateTime": "2026-06-25T14:00:00",      "createdAt": "2026-06-25T04:00:00.000Z",      "manifested": true,      "manifestedAt": "2026-06-25T06:00:00.000Z",      "collectedAt": "2026-06-25T15:12:00.000Z",      "deliveredAt": null,      "dangerousGoods": false,      "payer": "Sender",      "payerAccountNumber": null,      "bookedWithWarnings": false,      "createdByUserId": null,      "quoteId": "b2c3d4e5-...",      "rateId": "a1b2c3d4-...",      "pickupReference": "SYD734506",      "carrierOrderNumber": "31073640400",      "committedEtaDate": "2026-06-26",      "committedEtaByLocalTime": "17:00",      "committedEtaSource": "CARRIER_SERVICE",      "committedEtaAt": "2026-06-26T07:00:00.000Z",      "quotedGstSource": "DERIVED",      "quotedTransitCalendarDays": 1,      "collectionWindow": {        "date": "2026-06-25",        "readyTime": "14:00",        "closeTime": "17:00",        "timezone": "Australia/Sydney"      },      "lifecycleStatus": "IN_TRANSIT",      "trackingCoverage": "MILESTONES",      "collectedAtInstant": "2026-06-25T05:12:00.000Z",      "deliveredAtInstant": null,      "collectedAtSource": "KEYWORD",      "deliveredAtSource": null,      "deliveredLocalDate": null,      "latestCarrierEtaDate": null    }  ]}

Get shipment detail

GET
/shipments/{id}

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).

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Path Parameters

id*string

Datashift shipment ID (from booking response or GET /shipments)

Response Body

Shipment detail

application/json
  1. response
shipment*
Example Request
curl -X GET 'https://datashift.com.au/api/freight/shipments/string'
Example Response
{  "shipment": {    "id": "string",    "carrier": "TNT_AU",    "connectorName": "string",    "orderNumber": "string",    "consignmentNumber": "string",    "carrierBookingRef": "string",    "customerReference": "string",    "status": "CONSIGNED",    "pickupStatus": "NOT_BOOKED",    "serviceCode": "string",    "serviceDescription": "string",    "source": "API",    "fromSuburb": "string",    "fromPostcode": "string",    "fromState": "string",    "toSuburb": "string",    "toPostcode": "string",    "toState": "string",    "receiverCompany": "string",    "receiverName": "string",    "pieceCount": 0,    "declaredWeightKg": 0,    "declaredCubicM3": 0,    "quotedPriceExGstMinor": 0,    "quotedGstMinor": 0,    "quotedPriceIncGstMinor": 0,    "quotedCurrency": "string",    "committedEta": "2019-08-24T14:15:22Z",    "quotedTransitDays": 0,    "collectionDateTime": "string",    "createdAt": "2019-08-24T14:15:22Z",    "manifested": true,    "manifestedAt": "2019-08-24T14:15:22Z",    "collectedAt": "2019-08-24T14:15:22Z",    "deliveredAt": "2019-08-24T14:15:22Z",    "dangerousGoods": true,    "payer": "Sender",    "payerAccountNumber": "string",    "bookedWithWarnings": true,    "createdByUserId": "string",    "quoteId": "string",    "rateId": "string",    "cancelledAt": "2019-08-24T14:15:22Z",    "cancelSource": "PORTAL",    "cancelReason": "string",    "cancelledByUserId": "string",    "pickupReference": "string",    "carrierOrderNumber": "string",    "committedEtaDate": "2019-08-24",    "committedEtaByLocalTime": "string",    "committedEtaSource": "CARRIER_SERVICE",    "committedEtaAt": "2019-08-24T14:15:22Z",    "quotedGstSource": "CARRIER",    "quotedTransitCalendarDays": 0,    "collectionWindow": {      "date": "string",      "readyTime": "string",      "closeTime": "string",      "timezone": "string"    },    "lifecycleStatus": "BOOKED",    "trackingCoverage": "MILESTONES",    "collectedAtInstant": "2019-08-24T14:15:22Z",    "deliveredAtInstant": "2019-08-24T14:15:22Z",    "collectedAtSource": "STRUCTURED",    "deliveredAtSource": "STRUCTURED",    "deliveredLocalDate": "2019-08-24",    "latestCarrierEtaDate": "2019-08-24",    "payerSubAccount": "string",    "payerThirdPartyAddress": {      "companyName": "string",      "contactName": "string",      "phoneAreaCode": "string",      "phoneNumber": "string",      "address1": "string",      "address2": "string",      "suburb": "string",      "state": "string",      "postcode": "string",      "email": "user@example.com"    },    "sender": {      "companyName": "string",      "contactName": "string",      "phoneAreaCode": "string",      "phoneNumber": "string",      "address1": "string",      "address2": "string",      "suburb": "string",      "state": "string",      "postcode": "string",      "email": "user@example.com"    },    "collection": {      "companyName": "string",      "contactName": "string",      "phoneAreaCode": "string",      "phoneNumber": "string",      "address1": "string",      "address2": "string",      "suburb": "string",      "state": "string",      "postcode": "string",      "email": "user@example.com"    },    "receiver": {      "companyName": "string",      "contactName": "string",      "phoneAreaCode": "string",      "phoneNumber": "string",      "address1": "string",      "address2": "string",      "suburb": "string",      "state": "string",      "postcode": "string",      "email": "user@example.com"    },    "items": {      "count": 1,      "totalWeightKg": 0,      "maxLengthCm": 0,      "maxWidthCm": 0,      "maxHeightCm": 0    },    "collectionCloseTime": "string",    "specialInstructions": "string",    "barcodes": [      "string"    ],    "bookingWarnings": [      {        "code": "string",        "message": "string"      }    ],    "labelReturnedAtBooking": true,    "bookingCutoff": "string",    "collectionCutoff": "string",    "dangerousGoodsDetails": {}  }}
GET
/track

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.

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Query Parameters

consignment*string

Carrier consignment number to look up (e.g. the consignmentNumber from a booking response)

carrier?string

Optional. Scopes the lookup to a single carrier, skipping the shipment-match and fan-out steps. Recommended when you already know the carrier.

Value in"TNT_AU""BEX_AU""TGE_AU""NLN_AU"

Response Body

Tracking result. Check supported — if false the carrier does not expose a tracking API.

application/json
  1. response
supported*boolean

false when the matched carrier does not expose a tracking API

success?booleanDeprecated

Always true on a 200 response. Kept for compatibility.

tracking?

Null if tracking is not yet available or not supported

Example Request
curl -X GET 'https://datashift.com.au/api/freight/track?consignment=string'
Example Response
{  "supported": true,  "tracking": {    "currentStatus": "In Transit",    "eta": "2026-06-30",    "deliveredAt": null,    "events": [      {        "timestamp": "2026-06-28T22:00:00Z",        "status": "In Transit",        "location": "Sydney Gateway",        "description": null,        "at": "2026-06-28T22:00:00.000Z",        "code": "IN_TRANSIT"      },      {        "timestamp": "2026-06-28T10:30:00Z",        "status": "Picked Up",        "location": "Sydney, NSW",        "description": "Shipment collected from sender",        "at": "2026-06-28T10:30:00.000Z",        "code": "PICKED_UP"      }    ],    "etaDate": "2026-06-30",    "collectedAtInstant": "2026-06-28T10:30:00.000Z",    "deliveredAtInstant": null,    "lifecycleStatus": "IN_TRANSIT",    "collectedAtSource": "MAPPED_CODE",    "deliveredAtSource": null  }}

Get shipment label

GET
/shipments/{id}/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.

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Path Parameters

id*string

Datashift shipment ID (from booking response or GET /shipments)

Response Body

PDF label

response?fileapplication/pdf
Formatbinary
Example Request
curl -X GET 'https://datashift.com.au/api/freight/shipments/string/label'
Example Response
"string"
POST
/shipments/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.

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Request Body

application/json
  1. body
ids*array<string>

Datashift shipment IDs to check. Deduplicated and capped at 100.

Items1 <= items <= 100

Response Body

Per-id eligibility, in the same (deduped) order as the request

application/json
  1. response
results*array<>

Same (deduped) order as the request ids.

carrierNotified*false

Always false — this endpoint never contacts a carrier.

Value infalse
Example Request
curl -X POST 'https://datashift.com.au/api/freight/shipments/cancel/eligibility' \  -H 'Content-Type: application/json' \  -d '{  "ids": [    "cm9x1a2b3c4d5e6f7g8h9i0j",    "cm9x1a2b3c4d5e6f7g8h9i0k"  ]}'
Example Response
{  "results": [    {      "id": "cm9x1a2b3c4d5e6f7g8h9i0j",      "eligible": true,      "warnings": []    },    {      "id": "cm9x1a2b3c4d5e6f7g8h9i0k",      "eligible": true,      "warnings": [        {          "code": "MANIFESTED",          "message": "This shipment was on a manifest already sent to the carrier. Expect a charge unless you contact the carrier."        }      ]    }  ],  "carrierNotified": false}
POST
/shipments/cancel

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.

Authorization

FreightApiKey
headerAuthorizationBearer <dsfrt_<64-hex-chars>>

API key issued from Settings → Freight → API Keys. The raw key is shown once at creation.

Request Body

application/json
  1. body
ids*array<string>
Items1 <= items <= 100
reason*string

Required free-text reason, persisted as cancelReason on the shipment.

Length3 <= length <= 200
category?string

Optional. When given, persisted as "CATEGORY: reason".

Value in"DUPLICATE""BOOKED_IN_ERROR""ORDER_CANCELLED""REBOOKED""OTHER"
acknowledgeCarrierNotNotified*true

Required, must be exactly true. Confirms you understand the carrier is not notified and, if a label was already printed, it must be destroyed.

Value intrue
acknowledgeManifested?boolean

Blanket acknowledgement: true allows every manifested shipment in the request to be cancelled. A manifested shipment not covered by this or acknowledgeManifestedIds is skipped with MANIFEST_ACK_REQUIRED.

acknowledgeManifestedIds?array<string>

Per-shipment acknowledgement: manifested shipments that may be cancelled. Preferred over acknowledgeManifested — list the ids your eligibility check showed as MANIFESTED, so a shipment manifested after that check is skipped instead of cancelled unseen.

Itemsitems <= 100

Response Body

Cancel outcome — check skipped for any ids that were not cancelled

application/json
  1. response
cancelled*array<string>

Ids that were actually cancelled.

skipped*array<>

Ids that were not cancelled, with why.

carrierNotified*false

Always false — no carrier is ever notified by this endpoint.

Value infalse
warning*string

Always present — the DataShift-only cancellation caveat as display text. Surface it to whoever triggered the cancel.

manifestedWarning?string

Present only when at least one cancelled shipment had already been manifested to the carrier.

Example Request
curl -X POST 'https://datashift.com.au/api/freight/shipments/cancel' \  -H 'Content-Type: application/json' \  -d '{  "ids": [    "cm9x1a2b3c4d5e6f7g8h9i0j"  ],  "reason": "Customer cancelled the order",  "category": "ORDER_CANCELLED",  "acknowledgeCarrierNotNotified": true}'
Example Response
{  "cancelled": [    "cm9x1a2b3c4d5e6f7g8h9i0j"  ],  "skipped": [    {      "id": "cm9x1a2b3c4d5e6f7g8h9i0k",      "code": "DELIVERED",      "message": "This shipment has already been delivered and can no longer be cancelled."    }  ],  "carrierNotified": false,  "warning": "DataShift has cancelled this shipment. The carrier has not been notified. Destroy the printed label so the freight isn't collected or invoiced."}