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

# Update a Shipment

> Change an existing Shipment — and understand which fields replace, which append, and which can never change.

Update an existing Shipment with `POST /v5/shipment/update/`, identifying it by the `shipment_uuid` **or** `shipment_id` query parameter:

```bash theme={null}
curl --request POST \
  --url 'https://api.perform.ai/v5/shipment/update/?shipment_id=SHP-2026-000002' \
  --header 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{ "note": "Repacked before dispatch", "tags": ["repacked"] }'
```

The request body takes the same fields as [Create Shipment](/guides/create-shipment); none are required. Full field specs: [API reference](/api-reference/v5/shipments/update-shipment).

## Replace, append, or locked — know which is which

**Most fields replace the stored value entirely.** That includes three cases that surprise integrators:

* **`line_items` and `shipping_costs` replace the whole array.** Sending one line item removes all others. To keep existing items, resend the complete set.
* **Each address object replaces as a unit.** Sending `to_address` with only a new `postal_code` erases the rest of that address.
* **`notification_email` / `notification_phone` replace the whole array** — to add a recipient, send the full list.

**Four fields append instead:** `tags`, `events`, `linked_shipments`, and `documents`. Values you send are added; nothing is removed. (v5.0 has no way to remove tags — that's what the v5.2 endpoint below is for.)

**Locked fields:**

| Field                                  | Rule                                                                                                                                                                         |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `shipment_id`                          | Can be *added once* to a Shipment created without one; never changed after.                                                                                                  |
| `tracking_number`, `carrier_reference` | Changeable **only while the Shipment has no track events**. Afterwards the API rejects the change: `4030` — "tracking\_number cannot be changed for a shipment with events". |
| Return Shipments                       | Cannot be updated after a successful carrier booking.                                                                                                                        |

## Manage tags with v5.2

`POST /v5-2-0/shipment/update/` adds `tags_action`, which controls how the `tags` you send are applied:

```json theme={null}
{ "tags": ["priority"], "tags_action": "replace" }
```

| `tags_action`   | Effect                                                                                                                            |
| --------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `add` (default) | Appends — identical to v5.0 behavior.                                                                                             |
| `remove`        | Removes the listed tags from the Shipment.                                                                                        |
| `replace`       | Replaces the Shipment's tags with the listed ones. System-generated tags (SLA, routing, and similar) are preserved automatically. |

Sending `tags_action` without `tags` returns a `299` warning; removing a tag that doesn't exist, or a system-generated one, returns a validation error. Everything else about the v5.2 endpoint is identical to v5.0.

## Read the response

```json theme={null}
{
  "api_response": "200",
  "data": {
    "shipment_uuid": "5b8ed503-20d2-46cf-8675-ce77a059f691",
    "order_uuid": null,
    "documents": [],
    "created_date": "2026-09-19T03:26:29+00:00",
    "updated_date": "2026-09-19T03:26:31+00:00"
  }
}
```

`299` means the update applied with skipped parts (see `warnings`); `4030` means nothing changed — including `No shipments found with provided shipment_id.` when the identifier doesn't match. See [responses and errors](/essentials/responses-and-errors).

## Next steps

* [Retrieve the Shipment](/guides/retrieve-shipment) to verify the stored state after an update.
* Order fields (`order_reference`, `order_source_*`) require a valid existing `order_id` — see [Orders](/concepts/orders).
