---
title: "Book a multi-stops FTL shipment"
method: POST
path: "/freights/booking/multi-stops"
tags: ["Multi-Stops"]
---

# Book a multi-stops FTL shipment

`POST /freights/booking/multi-stops`

## Request

- Base URL: `https://stg.wearewarp.com/api/v1`
- URL: `https://stg.wearewarp.com/api/v1/freights/booking/multi-stops`
- Auth: API key in header `apikey`

Book a multi-stop FTL shipment using a previous multi-stops quote ID.

This endpoint creates an order with multiple shipments (legs), each representing a pickup-to-delivery segment within the overall route. All stops that were included in the original quote must be used in the booking.

**Requirements:**
- A valid, unexpired multi-stops `quoteId` from `/freights/quote/multi-stops`
- At least 2 shipments (otherwise use the standard `/freights/booking` endpoint), at most 19
- All zipcodes from the original quote must appear in the booking shipments
- Within each shipment, `pickupInfo.stopIndex` must be less than `deliveryInfo.stopIndex`
- Addresses must be US: `state` is the 2-letter code and `zipcode` is 5-digit or ZIP+4
- `windowTime` / `appointmentInfo` `from` and `to` are strings in the format `YYYY-MM-DDTHH:mm:ss` with optional milliseconds (up to 3 digits) and an optional trailing `Z` (e.g. `2026-03-15T08:00:00Z` or `2026-03-15T08:00:00.000Z`); time zone offsets such as `+07:00` are not accepted
- Items follow the same limits as the multi-stops quote (height <= 85, length <= 636, width <= 102, quantity 1-9999, totalWeight <= 80000, 1-100 items per shipment)

**Validation:** every validation error (including a missing required field) is returned as 400 `invalid_field_data` with the failing field in the message.

**How stopIndex works:**
- `stopIndex` is a relative sorting key that determines the order the driver visits each stop
- Values don't need to be contiguous (e.g., 0, 5, 10 is valid)
- Same `stopIndex` value means the driver visits the same physical location once for multiple tasks
- Example: A route LA → Dallas → NYC with pickup at Dallas and delivery at Dallas:
  - Shipment 1: pickup (stopIndex: 0, LA) → delivery (stopIndex: 1, Dallas)
  - Shipment 2: pickup (stopIndex: 2, Dallas) → delivery (stopIndex: 3, NYC)

**Request parameters**

| Name                                   | Type                     | Required/Optional | Description                                                                |
|----------------------------------------|--------------------------|-------------------|----------------------------------------------------------------------------|
| quoteId                                | String                   | Required          | The quote ID from a previous multi-stops quote request.                    |
| shipments                              | Array<**Shipment**>      | Required          | List of shipment legs (min 2, max 19).                                     |
| shipments[].pickupInfo                 | **MultiStopsStopInfo**   | Required          | Pickup stop details including stopIndex.                                   |
| shipments[].deliveryInfo               | **MultiStopsStopInfo**   | Required          | Delivery stop details including stopIndex.                                 |
| shipments[].listItems                  | Array<**Item**>          | Required          | Commodities for this leg.                                                  |
| shipments[].pickupServices             | Array<**ServiceOption**> | Optional          | Pickup services for this leg.                                              |
| shipments[].deliveryServices           | Array<**ServiceOption**> | Optional          | Delivery services for this leg.                                            |
| shipments[].additionalServices         | Array<**ServiceOption**> | Optional          | Additional services for this leg.                                          |
| shipmentType                           | String                   | Optional          | Only `FTL` is accepted (default: FTL); any other value is rejected with 400. |
| vehicleType                            | Object                   | Optional          | Vehicle type specification.                                                |

<br/>
**MultiStopsStopInfo** extends StopInfo with:

| Name        | Type    | Required/Optional | Description                                                              |
|-------------|---------|-------------------|--------------------------------------------------------------------------|
| stopIndex   | Number  | Required          | Integer (0-999). Relative order of this stop in the route.               |
| All fields from StopInfo (contactName, contactPhone, address, windowTime, instructions, refNum, etc.) |||

<br/>
**Response**

| Name                          | Type   | Description                                   |
|-------------------------------|--------|-----------------------------------------------|
| message                       | String | Result message (e.g. "Success").               |
| trackingNumber                | String | The tracking number of the order (same as orderNumber). |
| orderId                       | String | The ID of the created order.                   |
| orderNumber                   | String | The display number of the order.               |
| shipments                     | Array  | List of created shipments.                     |
| shipments[].trackingNumber    | String | Tracking number for this shipment (currently the shipment code, same as shipmentNumber). |
| shipments[].shipmentId        | String | ID of the shipment.                            |
| shipments[].shipmentNumber    | String | Display number of the shipment.                |
| shipments[].refNum            | String | Reference numbers.                             |

## Request body

- MultiStopsBookingBody
  - `quoteId` string, required: Quote ID from a previous multi-stops quote request
  - `shipments` MultiStopsShipmentInput[], required: List of shipment legs (min 2, max 19). Each shipment has its own pickup and delivery with stopIndex.
    - `pickupInfo` MultiStopsStopInfo, required
      - `stopIndex` integer, required: Relative order of this stop in the route (0-999). Same value = same physical stop.
      - `locationName` string
      - `contactName` string
      - `contactPhone` string
      - `phoneExtension` string
      - `contactEmail` string
      - `address` Address, required
        - `street2` string
        - `street` string, required
        - `city` string, required
        - `state` string, required
        - `zipcode` string, required
      - `requiresAppointment` boolean
      - `appointmentInfo` TimeWindow
        - `from` string, date-time, required: Starting time of the window in ISO format
        - `to` string, date-time, required: Ending time of the window in ISO format
      - `windowTime` TimeWindow, required
        - `from` string, date-time, required: Starting time of the window in ISO format
        - `to` string, date-time, required: Ending time of the window in ISO format
      - `instructions` string
      - `refNum` string
    - `deliveryInfo` MultiStopsStopInfo, required
      - `stopIndex` integer, required: Relative order of this stop in the route (0-999). Same value = same physical stop.
      - `locationName` string
      - `contactName` string
      - `contactPhone` string
      - `phoneExtension` string
      - `contactEmail` string
      - `address` Address, required
        - `street2` string
        - `street` string, required
        - `city` string, required
        - `state` string, required
        - `zipcode` string, required
      - `requiresAppointment` boolean
      - `appointmentInfo` TimeWindow
        - `from` string, date-time, required: Starting time of the window in ISO format
        - `to` string, date-time, required: Ending time of the window in ISO format
      - `windowTime` TimeWindow, required
        - `from` string, date-time, required: Starting time of the window in ISO format
        - `to` string, date-time, required: Ending time of the window in ISO format
      - `instructions` string
      - `refNum` string
    - `listItems` BookShipmentItem[], required: 1 to 100 items. Bounds: height 0.1-85, length 0.1-636, width 0.1-102, quantity 1-9999, totalWeight 0.01-80000.
      - `name` string
      - `height` number, required: Maximum 108 on POST /freights/booking; maximum 85 on POST /freights/freight-quote, /freights/book and the multi-stops endpoints (checked on the raw value, whatever the sizeUnit).
      - `length` number, required
      - `width` number, required
      - `sizeUnit` 'IN' | 'FT', required
      - `totalWeight` number, required
      - `weightUnit` 'lbs' | 'kgs', required
      - `quantity` integer, required
      - `packaging` string: Packaging unit of the line item (e.g. Pallet). Defaults to Pallet.
      - `temperature_limit` object: Temperature-controlled (reefer) freight is NOT supported yet by the quote endpoints: POST /freights/quote rejects any non-zero min/max and POST /freights/freight-quote rejects the field entirely with 400 `Reefer Shipment is not supported yet!`. Omit this field unless instructed otherwise by WARP.
        - `min` number: Minimum temperature.
        - `max` number: Maximum temperature.
      - `stackable` boolean
      - `notes` string
      - `freightClass` string: NMFC freight class of the line item (e.g. 70).
      - `barcodes` string[]
    - `pickupServices` PickupService[]
      - `quantity` number, required
      - `service` 'photo-required-pickup' | 'liftgate-pickup' | 'convention-trade-show-pickup' | 'inside-pickup' | 'limited-access-pickup' | 'residential-pickup' | 'construction-site-pickup' | 'pickup-appointment' | 'pickup-layover' | 'detention-shipper' | 'drop-empty' | 'driver-assist-pickup' | 'drop-and-hook-pickup' | 'inside-pickup-upstairs-mezzanine-trash-removal' | 'inside-pickup-back-side-of-the-house' | 'inside-pickup-living-space-garage', required: Pickup service options
    - `deliveryServices` DeliveryService[]
      - `quantity` number, required
      - `service` 'photo-required-delivery' | 'liftgate-delivery' | 'convention-trade-show-delivery' | 'inside-delivery' | 'limited-access-delivery' | 'residential-delivery' | 'construction-site-delivery' | 'delivery-appointment' | 'delivery-layover' | 'lumper' | 'detention-receiver' | 'redelivery' | 'drop-loaded' | 'driver-assist-delivery' | 'drop-and-hook-delivery' | 'inside-delivery-upstairs-mezzanine-trash-removal' | 'inside-delivery-back-side-of-the-house' | 'inside-delivery-living-space-garage', required: Delivery service options
    - `additionalServices` AdditionalService[]
      - `quantity` number, required
      - `service` 'photo-required' | 'sort-n-seg' | 'extra-stop' | 'extra-miles' | 'driver-assist' | 'notify' | 'check_calls' | 'otp_late_fee' | 'otd_late_fee' | 'carrier_otp' | 'carrier_otd' | 'tonu' | 'miscellaneous' | 'deduction' | 'racket_straps' | 'trailer_rental' | 'storage' | 'cross_dock_charge' | 'drop_loaded_equipment' | 'drop_and_hook' | 'drop_equipment' | 'reweigh_reclass' | 'insurance' | 'chassis_rental', required: Addtional service options
  - `shipmentType` 'FTL': Shipment type. Only FTL is accepted; any other value is rejected with 400.
  - `vehicleType` object
    - `code` 'DRY_VAN_53' | 'STRAIGHT_TRUCK_26' | 'CARGO_VAN'
    - `options` string[]

## Response `200`

successful creation

- MultiStopsBookingResult
  - `message` string
  - `trackingNumber` string: The tracking number of the order (same as orderNumber)
  - `orderId` string: The ID of the created order
  - `orderNumber` string: The display number of the order
  - `shipments` object[]: List of created shipments
    - `trackingNumber` string
    - `shipmentId` string
    - `shipmentNumber` string
    - `refNum` string

## Other responses

- `400`: validation error
- `401`: Unauthorized - the apikey header is missing or does not match any active API key.
- `403`: Forbidden - the customer account is suspended. The body carries `message` only, without `code`.
- `429`: Too Many Requests - the quoting rate limit of the API key was exceeded (only POST /freights/quote, /freights/freight-quote and /freights/quote/multi-stops are rate limited; limits apply per UTC hour and per UTC day). The `Retry-After` header holds the number of seconds until the window resets.
- `500`: Internal Server Error - an unknown error has occurred.

---

[API](https://skmtc.dev/wearewarp/apis/warp-api-documentation.md) · [All operations](https://skmtc.dev/wearewarp/apis/warp-api-documentation/llms.txt) · [OpenAPI document](https://skmtc.dev/wearewarp/apis/warp-api-documentation/revisions/01526741bb48?raw)
