> ## Documentation Index
> Fetch the complete documentation index at: https://apidocs.dyspach.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Shipment structure

> The one structure every shipment push uses, as JSON fields or file columns.

There is a single published structure for shipments. You choose how to deliver it —
[as a JSON batch](/api-reference/import-shipments) or [as a file](/api-reference/import-shipments-file) —
but the fields are the same either way, and they are the same for every organisation.

* **JSON**: each shipment is an object with these field names; its goods lines go in `items`.
* **File**: each column header is the same name, and there is **one row per goods line** —
  repeat the shipment columns on each line of a multi-line shipment, and keep the lines of
  a shipment together. `.csv` and `.xlsx` only; re-save `.xls` before sending.

Column order does not matter and optional columns may be left out entirely. A column we
do not publish is rejected rather than ignored, so a typo surfaces immediately instead of
silently dropping data.

<Note>
  Download a starter file: [shipments-template.csv](/templates/shipments-template.csv) —
  the header row, with one example shipment.
</Note>

## Identity

<ParamField body="shipmentId" type="string" required>
  Your connote / consignment number, up to 255 characters. This identifies the shipment
  permanently: **sending it again updates that shipment** instead of creating a second
  one, and replaces its goods lines with the ones in the new push. Matching ignores case.
</ParamField>

<ParamField body="customerId" type="string">
  The customer this shipment belongs to, using the customer code configured in Dyspach —
  the same code you pass in `general.customerIds` when quoting.

  This is the link between the shipment and the customer at billing time. A shipment
  carrying a code nobody recognises still imports, but it will not be billed to anyone,
  so it is worth getting right.
</ParamField>

## Origin

`originPostCode`, `originSuburb`, `originState` and `originCountryCode` are **required** —
together they must resolve to a serviceable location, or the shipment is rejected with
`Origin Zone(s) not found`.

| Field                    | Type    | Notes                                       |
| ------------------------ | ------- | ------------------------------------------- |
| `originPostCode`         | string  | **Required**                                |
| `originSuburb`           | string  | **Required**                                |
| `originState`            | string  | **Required.** State/region code, e.g. `VIC` |
| `originCountryCode`      | string  | **Required.** ISO country code, e.g. `AU`   |
| `originCompanyName`      | string  |                                             |
| `originContactName`      | string  |                                             |
| `originContactPhone`     | string  |                                             |
| `originContactEmail`     | string  |                                             |
| `originAddressStreet1`   | string  |                                             |
| `originAddressStreet2`   | string  |                                             |
| `originAddressStreet3`   | string  |                                             |
| `originLocationType`     | string  | e.g. `Residential`, `Business`              |
| `originRequiresTailLift` | boolean | `Yes` / `No` in a file                      |

## Destination

Same four required fields, and rejected the same way (`Destination Zone(s) not found`).

| Field                              | Type    | Notes        |
| ---------------------------------- | ------- | ------------ |
| `destinationPostCode`              | string  | **Required** |
| `destinationSuburb`                | string  | **Required** |
| `destinationState`                 | string  | **Required** |
| `destinationCountryCode`           | string  | **Required** |
| `destinationCompanyName`           | string  |              |
| `destinationContactName`           | string  |              |
| `destinationContactPhone`          | string  |              |
| `destinationContactEmail`          | string  |              |
| `destinationAddressStreet1`        | string  |              |
| `destinationAddressStreet2`        | string  |              |
| `destinationAddressStreet3`        | string  |              |
| `destinationLocationType`          | string  |              |
| `destinationRequiresTailLift`      | boolean |              |
| `destinationGivesAuthorityToLeave` | boolean |              |
| `destinationSignatureOnGlass`      | boolean |              |

## Dates and commercials

| Field                   | Type      | Notes                                                                           |
| ----------------------- | --------- | ------------------------------------------------------------------------------- |
| `quoteDate`             | date-time | When the shipment was booked/manifested. Defaults to the import date if omitted |
| `pickupDate`            | date-time |                                                                                 |
| `completedDate`         | date-time |                                                                                 |
| `expectedCompletedDate` | date-time |                                                                                 |
| `rateCardAlias`         | string    | The service / rate card the shipment went on, as configured in Dyspach          |
| `totalCostReceived`     | number    | The cost you were charged, if you pass one through                              |
| `customField1`          | string    | Free-text slot, kept for compatibility with file uploads                        |
| `customField2`          | string    |                                                                                 |
| `customField3`          | string    |                                                                                 |

## Goods

Every shipment needs at least one goods line — at most 500, and at most 10,000 across a
whole JSON batch (a file has no line limit beyond its 50 MB size). In JSON they are the
`items` array; in a file, each line is its own row.

<ParamField body="itemType" type="string" required>
  What the line is — `Carton`, `Pallet`, `Satchel`, and so on. A row with no `itemType`
  contributes no goods line at all, which is why it is required.
</ParamField>

| Field                  | Type    | Notes                                                   |
| ---------------------- | ------- | ------------------------------------------------------- |
| `itemId`               | string  | Your reference for the line (SKU, item number)          |
| `itemQuantity`         | number  | Defaults to 1                                           |
| `itemPalletSpaces`     | number  |                                                         |
| `itemLength`           | number  | In your organisation's configured dimension unit        |
| `itemWidth`            | number  |                                                         |
| `itemHeight`           | number  |                                                         |
| `itemWeight`           | number  |                                                         |
| `itemChargeableWeight` | number  | Pass through if you have it; otherwise it is calculated |
| `itemVolumetricWeight` | number  |                                                         |
| `itemValue`            | number  |                                                         |
| `dangerousGoods`       | boolean |                                                         |

## Custom fields

Your customer's carrier may configure extra fields on shipments or goods. They are
addressed **by name**, exactly as configured:

* **JSON** — a `customFields` object on the shipment, and another on each item:

  ```json theme={null}
  {
    "shipmentId": "CONN-88213",
    "customFields": { "Purchase Order": "PO-99187" },
    "items": [
      { "itemType": "Pallet", "customFields": { "Batch Number": "B-2291" } }
    ]
  }
  ```

* **File** — a column per field, prefixed `CF:` for shipment-level and `ITEM_CF:` for
  goods-level:

  ```csv theme={null}
  shipmentId,...,itemType,CF:Purchase Order,ITEM_CF:Batch Number
  CONN-88213,...,Pallet,PO-99187,B-2291
  ```

A field name that is not configured for that organisation is rejected — you will not
silently lose the value. Fields marked **mandatory** must carry a value or the whole
shipment is rejected with `Missing mandatory custom field(s): …`.

## Value formats

<AccordionGroup>
  <Accordion title="Booleans">
    In JSON, use real booleans (`true` / `false`). **In a file, write `Yes` or `No`** —
    a file cell containing `true` is read as "not yes", which is almost never what you
    meant.
  </Accordion>

  <Accordion title="Dates">
    ISO-8601, e.g. `2026-08-14T02:15:00Z`. Dates without a time are accepted.
  </Accordion>

  <Accordion title="Numbers">
    Plain decimals — `412.55`. No currency symbols, no thousands separators.
  </Accordion>

  <Accordion title="Multi-line shipments in a file">
    Repeat the shipment columns on every row of the shipment and keep those rows
    together. Rows are grouped by consecutive matching `shipmentId`:

    ```csv theme={null}
    shipmentId,originSuburb,...,itemType,itemQuantity
    CONN-88213,Melbourne,...,Pallet,2
    CONN-88213,Melbourne,...,Carton,6
    CONN-88214,Melbourne,...,Satchel,1
    ```

    A blank `shipmentId` is not carried down from the row above — it is rejected with
    `No Shipment ID found`.
  </Accordion>
</AccordionGroup>
