---
title: "Records the shipment of an in-transit transfer (the app's Ship dialog): carrier and tracking, or \"ship without tracking\"."
method: POST
path: "/api/v1/sales-orders/{id}/ship"
tags: ["SalesOrders"]
---

# Records the shipment of an in-transit transfer (the app's Ship dialog): carrier and tracking, or "ship without tracking".

`POST /api/v1/sales-orders/{id}/ship`

## Request

- Base URL: `https://app.flexonthejob.com`
- URL: `https://app.flexonthejob.com/api/v1/sales-orders/{id}/ship`
- Auth: HTTP bearer

Requires `ManageSalesOrders` and an `Idempotency-Key` header. Body:
`{ "transferId": 904, "carrier": "UPS", "trackingNumber": "1Z999AA10123456784" }`, or
`{ "transferId": 904, "withoutTracking": true }`. `transferId` omitted = the
order's single in-transit transfer. The transfer must be in transit (`/complete-pick`
first). Same code path as the app: the transfer's shipment is added — or replaced when it
already has one (every field is overwritten; `shipDate` omitted = now) — the history
records "Shipment added — UPS tracking … (via API key '…')" and the order's `status`
is recalculated: `Shipped` once every live transfer has shipping info. Without
tracking only flags the transfer shipped ("Shipped without tracking").

## Path parameters

- `id` integer, required

## Request body

- ShipSalesOrderApiRequest: Body of `POST /api/v1/sales-orders/{id}/ship`. Example: `{ "transferId": 904, "carrier": "UPS", "trackingNumber": "1Z999AA10123456784", "shippingMethod": "Ground" }`; without tracking: `{ "transferId": 904, "withoutTracking": true }`.
  - `transferId` integer, nullable: The order's in-transit transfer being shipped. Omit when the order has exactly one transfer in transit. Example: `904`.
  - `withoutTracking` boolean: `true` = the app's "Ship without tracking": no shipment record, the transfer is only flagged shipped so it can be delivered. Then `carrier`, `trackingNumber` and the other shipment fields must be omitted. Default `false`.
  - `carrier` string, nullable: Carrier name, up to 100 characters. Example: `UPS`.
  - `trackingNumber` string, nullable: Carrier tracking number, up to 100 characters. Example: `1Z999AA10123456784`.
  - `shippingMethod` string, nullable: Shipping method / service level, up to 50 characters. Example: `Ground`.
  - `shipDate` string, date-time, nullable: Ship date as ISO-8601 (stored as sent); omit for now (UTC). Example: `2026-09-23T15:00:00Z`.
  - `estimatedDeliveryDate` string, date-time, nullable: Estimated delivery date as ISO-8601 (stored as sent). Example: `2026-09-26`.
  - `weight` number, double, nullable: Package weight, 0–1,000,000, in whatever unit the organization uses (the app does not fix one). Example: `12.5`.
  - `notes` string, nullable: Free-text shipment notes. Example: `2 boxes`.

## Response `200`

Shipment saved; the recalculated order status.

- SalesOrderStepResponse: Response of the sales-order fulfilment steps (`/pick`, `/complete-pick`, `/ship`, `/deliver`, `/complete`, `/cancel`).
  - `salesOrderId` integer: The sales order's id. Example: `318`.
  - `status` string: Order status after the step: `Pending`, `Picking`, `Packed`, `Shipped`, `Delivered`, `Complete` or `Cancelled`. Recalculated from the order's transfers, so always read it rather than assuming the next status. Example: `Packed`.
  - `fulfillmentStatus` string, nullable: Aggregate status of the order's transfers (`None`, `Pending`, `InTransit`, `AtWaypoint`, `Completed`, `Cancelled`…), as `fulfillmentStatus` on the order. Example: `InTransit`.
  - `transferId` integer, nullable: The transfer the step acted on (resolved when the request did not name one); null for `/complete` and `/cancel`. Example: `904`.
  - `message` string, nullable: Human-readable confirmation, as the app shows it. Example: `Transfer status updated to In Transit.`
  - `unitsPicked` integer: `/pick`: units marked picked by this call (0 for other steps). Example: `10`.
  - `itemsReturned` integer: `/cancel`: delivered units returned to inventory (0 for other steps). Example: `0`.
  - `transfersCancelled` integer: `/cancel`: transfers cancelled (0 for other steps). Example: `1`.

## Other responses

- `400`: Missing `Idempotency-Key`, a malformed body (a field over its length), or `withoutTracking` sent with shipment fields.
- `401`: Unauthorized
- `403`: Forbidden
- `404`: No such sales order in this organization, or `transferId` is not one of its transfers.
- `409`: The transfer is not in transit (detail: `Shipping information can only be added while the transfer is In Transit. Current status: Pending`), the order has no transfer in transit, or the key's creator is unknown.
- `422`: Several transfers in transit and no `transferId` (`errors.transferId` lists them).
- `429`: Too Many Requests

---

[API](https://skmtc.dev/flexonthejob/apis/flex-api.md) · [All operations](https://skmtc.dev/flexonthejob/apis/flex-api/llms.txt) · [OpenAPI document](https://skmtc.dev/flexonthejob/apis/flex-api/revisions/19c8f4d27acf?raw)
