> ## 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 Shipment

> Updates an existing Shipment, identified by the `shipment_uuid` **or**
`shipment_id` query parameter.

**Replace vs add:** most fields **replace** the stored value entirely —
including the whole `line_items` array, the whole `shipping_costs`
array, and each address object as a unit. Four fields are **add-only**:
`tags`, `events`, `linked_shipments`, and `documents` — values you send
are appended, never removed (use the v5.2 endpoint's `tags_action` to
remove or replace tags).

**Immutability:** `shipment_id` can be set once on a Shipment created
without one, and never changed after. `tracking_number` and
`carrier_reference` can be changed only while the Shipment has no track
events. A Return Shipment cannot be updated after a successful carrier
booking.



## OpenAPI

````yaml /specs/public-api-v5.yaml post /v5/shipment/update/
openapi: 3.1.0
info:
  title: Perform.AI Public API (v5)
  version: 5.0.0
  description: |-
    The Perform.AI Public API lets you create and manage shipments, returns,
    bookings, tracking events, and documents, and retrieve reference data such
    as PUDO locations and carrier configurations.

    All endpoints accept HTTPS connections only and are secured with OAuth 2.0.
    Generate a Bearer access token with your API credentials (Client ID and
    Client Secret, from **Integrations > API** in your account), then send it in
    the `Authorization` header of every request.

    This specification covers the following endpoints:
    - `POST /auth/oauth/token/`
    - `POST /v5/shipment/`
    - `POST /v5/shipment/update/`
    - `POST /v5-2-0/shipment/update/`
    - `GET /v5/shipment/list/`
    - `GET /v5/shipment/details/`
    - `GET /v5-2-0/shipment/details/`
    - `POST /v5/events/create/`
    - `POST /v5/return/`
    - `POST /v5/return/update/`
    - `GET /v5/shipments/documents/`
    - `GET /v5/shipments/documents/{document_uuid}/`
    - `GET /v5/shipments/documents/labels/`
    - `POST /v5/booking/`
    - `GET /v5/pudo-locations/`
    - `GET /v5/carrier-configs/`
servers:
  - url: https://api.perform.ai
security:
  - BearerAuth: []
tags:
  - name: Authentication
    description: Generate the Bearer access token used by every other endpoint.
  - name: Shipments
    description: Create, update, search, and retrieve Shipments.
  - name: Events
    description: Add manual tracking events to Shipments.
  - name: Returns
    description: Create and update Returns and their Return Shipments.
  - name: Documents
    description: Retrieve documents attached to Shipments.
  - name: Booking
    description: Book Open Shipments with carriers and provision shipping labels.
  - name: PUDO locations
    description: Search pick-up/drop-off locations across your configured carriers.
  - name: Carrier configurations
    description: Discover the carriers configured in your account.
  - name: Webhooks
    description: Shipment update payloads Perform.AI pushes to your endpoint.
paths:
  /v5/shipment/update/:
    post:
      tags:
        - Shipments
      summary: Update Shipment
      description: |-
        Updates an existing Shipment, identified by the `shipment_uuid` **or**
        `shipment_id` query parameter.

        **Replace vs add:** most fields **replace** the stored value entirely —
        including the whole `line_items` array, the whole `shipping_costs`
        array, and each address object as a unit. Four fields are **add-only**:
        `tags`, `events`, `linked_shipments`, and `documents` — values you send
        are appended, never removed (use the v5.2 endpoint's `tags_action` to
        remove or replace tags).

        **Immutability:** `shipment_id` can be set once on a Shipment created
        without one, and never changed after. `tracking_number` and
        `carrier_reference` can be changed only while the Shipment has no track
        events. A Return Shipment cannot be updated after a successful carrier
        booking.
      operationId: post-v5-shipment-update
      parameters:
        - $ref: '#/components/parameters/ShipmentUuidQuery'
        - $ref: '#/components/parameters/ShipmentIdQuery'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShipmentUpdateRequest'
            example:
              note: Fragile — repack before dispatch
              tags:
                - repacked
      responses:
        '200':
          description: Shipment updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ShipmentWriteResponse'
              example:
                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':
          description: >-
            Shipment updated with warnings — same warning catalogue as Create
            Shipment.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SuccessWithWarnings'
        '400':
          description: |-
            Field validation failed; nothing was changed. Update-specific
            causes: `No shipments found with provided shipment_uuid.` (or
            `shipment_id`), `tracking_number cannot be changed for a shipment
            with events.`, `carrier_reference cannot be changed for a shipment
            with events.` — plus the Create Shipment validation catalogue.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FieldValidationError'
              example:
                api_response: '4030'
                message: validation_error
                errors:
                  tracking_number:
                    - >-
                      tracking_number cannot be changed for a shipment with
                      events
        '403':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/Throttled'
        '500':
          $ref: '#/components/responses/SystemError'
components:
  parameters:
    ShipmentUuidQuery:
      name: shipment_uuid
      in: query
      schema:
        type: string
        format: uuid
      description: >-
        Perform.AI identifier of the Shipment. Provide either `shipment_uuid` or
        `shipment_id`.
    ShipmentIdQuery:
      name: shipment_id
      in: query
      schema:
        type: string
        maxLength: 50
      description: >-
        Your identifier of the Shipment. Provide either `shipment_uuid` or
        `shipment_id`.
  schemas:
    ShipmentUpdateRequest:
      allOf:
        - $ref: '#/components/schemas/ShipmentCreateRequest'
      required: []
      description: >-
        Same fields and constraints as Create Shipment; no field is required.
        Most fields replace the stored value entirely (whole arrays, whole
        address objects); `tags`, `events`, `linked_shipments`, and `documents`
        are add-only.
    ShipmentWriteResponse:
      type: object
      description: Response of Create Shipment and Update Shipment.
      properties:
        api_response:
          type: string
        data:
          type: object
          properties:
            shipment_uuid:
              type: string
              format: uuid
            order_uuid:
              type:
                - string
                - 'null'
              description: Present when the Shipment is attached to an order.
            documents:
              type: array
              items:
                type: object
              description: Identifiers of documents stored from the request.
            created_date:
              type: string
            updated_date:
              type: string
              description: Present on Update Shipment responses.
    SuccessWithWarnings:
      type: object
      description: >-
        HTTP 299 — the request succeeded, but parts of it could not be applied.
        The `warnings` object maps each affected field to its messages.
      required:
        - api_response
        - warnings
      properties:
        api_response:
          type: string
          description: Always `"299"`.
        data:
          type: object
          description: The endpoint's normal success payload, when it has one.
        warnings:
          type: object
          description: Affected field → array of warning messages.
          additionalProperties:
            type: array
            items:
              type: string
    FieldValidationError:
      type: object
      description: >-
        HTTP 400 — one or more fields failed validation; nothing was persisted.
        For fields inside arrays, errors are keyed by the item's position as a
        string ("0", "1", …), then the field name.
      required:
        - api_response
        - message
        - errors
      properties:
        api_response:
          type: string
          description: Always `"4030"`.
        message:
          type: string
          description: Always `validation_error`.
        errors:
          type: object
          description: >-
            Affected field → array of error messages (or a nested object for
            array items).
    ShipmentCreateRequest:
      type: object
      required:
        - shipment_id
      properties:
        shipment_id:
          type: string
          maxLength: 50
          description: >-
            Your unique identifier. Unique across the account; cannot be changed
            after creation. Accepts `A–Z a–z 0–9 _ - .`, no spaces.
        tracking_number:
          type: string
          minLength: 6
          maxLength: 50
          description: >-
            Carrier tracking number — optional, but needed (with
            `carrier_reference`) for tracking. `A–Z a–z 0–9 _ - . /`, no spaces,
            at least one digit. Stored uppercase.
        carrier_reference:
          type: string
          maxLength: 50
          description: >-
            A carrier reference configured under **Settings > Carriers**. An
            unconfigured value blocks creation.
        shipment_reference:
          type: string
          maxLength: 50
        additional_reference:
          type: string
          maxLength: 50
        order_uuid:
          type: string
          format: uuid
          description: >-
            Attach to an existing order by its Perform.AI identifier. Preferred
            over `order_id` if both are sent.
        order_id:
          type: string
          maxLength: 50
          description: Your order identifier. Creates the order if it doesn't exist.
        order_reference:
          type: string
          maxLength: 50
          description: Settable only together with a new `order_id`.
        order_source_type:
          type: string
          maxLength: 500
        order_source_name:
          type: string
          maxLength: 500
        tags:
          type: array
          items:
            type: string
            maxLength: 100
          description: Stored lowercase.
        notification_email:
          type: array
          items:
            type: string
            format: email
            maxLength: 100
          description: Recipients of tracking email notifications.
        notification_phone:
          type: array
          items:
            type: string
            maxLength: 30
          description: >-
            Recipients of tracking SMS notifications, as `+{country
            code}{number}`.
        tracking_page_reference:
          type: string
          maxLength: 50
          description: >-
            Assigns the Shipment to a tracking page for notification branding
            and tracking links. An unconfigured value returns a 299 warning.
        recipient_address:
          $ref: '#/components/schemas/AddressInput'
        sender_address:
          $ref: '#/components/schemas/AddressInput'
        to_address:
          $ref: '#/components/schemas/AddressInput'
        from_address:
          $ref: '#/components/schemas/AddressInput'
        return_address:
          $ref: '#/components/schemas/AddressInput'
        shipment_value:
          type: string
          description: Money string, e.g. `150 SGD`.
        total_shipping_cost:
          type: string
          description: Money string. Computed from `shipping_costs` if not provided.
        shipping_costs:
          type: array
          items:
            $ref: '#/components/schemas/ShippingCostInput'
        cod_value:
          type: string
          description: Money string.
        payment_type:
          type: string
          maxLength: 75
        length:
          type: string
          description: Measurement string, e.g. `15 cm`. Stored in cm.
        width:
          type: string
          description: Measurement string. Stored in cm.
        height:
          type: string
          description: Measurement string. Stored in cm.
        weight:
          type: string
          description: Measurement string, e.g. `1.5 kg`.
        item_count:
          type: integer
          minimum: 0
        packaging_type:
          type: string
          maxLength: 75
        note:
          type: string
          maxLength: 500
        description_of_goods:
          type: string
          maxLength: 500
        handling_instructions:
          type: string
          maxLength: 500
        sales_channel:
          type: string
          maxLength: 100
        shipping_service:
          type: string
          maxLength: 50
        expected_delivery_from:
          type: string
          description: ISO 8601. Start of the expected delivery window.
        expected_delivery_to:
          type: string
          description: ISO 8601. Requires `expected_delivery_from`.
        events:
          type: array
          items:
            $ref: '#/components/schemas/EventInput'
        linked_shipments:
          type: array
          items:
            $ref: '#/components/schemas/LinkedShipmentInput'
        documents:
          type: array
          items:
            $ref: '#/components/schemas/DocumentInput'
        line_items:
          type: array
          items:
            $ref: '#/components/schemas/LineItemInput'
        additional_info:
          type: object
          description: Custom fields. Keys max 50 chars, values max 150.
    GatewayError:
      type: object
      description: >-
        An error generated at the API gateway — authorization (`403`) or
        throttling (`429`). Note `api_response` is a number here, unlike
        application-level responses where it is a string.
      required:
        - api_response
        - message
      properties:
        api_response:
          type: integer
          description: '`403` or `429`.'
        message:
          type: string
          description: E.g. `Key not authorized`, `Quota exceeded`, `Throttled`.
    RequestError:
      type: object
      description: >-
        A request-level error such as `4000` (invalid request format), `4041`
        (no results found), or a `5XX` system error.
      required:
        - api_response
        - message
      properties:
        api_response:
          type: string
          description: Error code as a string, e.g. `"4000"`, `"4041"`, `"500"`.
        message:
          type: string
    AddressInput:
      type: object
      description: >-
        One of the Shipment's five address roles (recipient, sender, to, from,
        return). Provide either `country` or `country_code`. The `email` and
        `phone` here are contact data — they are never subscribed to tracking
        notifications.
      properties:
        address_name:
          type: string
          maxLength: 50
          description: Name or description of the address.
        location_type:
          type: string
          maxLength: 50
        entity_reference:
          type: string
          maxLength: 50
          description: Reference for the entity behind the address.
        salutation:
          type: string
          maxLength: 50
        first_name:
          type: string
          maxLength: 150
          description: First or full name.
        last_name:
          type: string
          maxLength: 150
        line1:
          type: string
          maxLength: 150
        line2:
          type: string
          maxLength: 150
        line3:
          type: string
          maxLength: 150
        street_name:
          type: string
          maxLength: 500
          description: Street name, when kept separate from the address lines.
        house_number:
          type: string
          maxLength: 50
        city:
          type: string
          maxLength: 75
        postal_code:
          type: string
          maxLength: 25
        state_or_province:
          type: string
          maxLength: 75
        region:
          type: string
          maxLength: 75
        country:
          type: string
          maxLength: 75
          description: >-
            Country name; resolved through a country identifier and stored as
            the identified name. Provide this or `country_code`.
        country_code:
          type: string
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2. Provide this or `country`.
        email:
          type: string
          format: email
          maxLength: 100
          description: Contact email. Not subscribed to notifications.
        phone:
          type: string
          maxLength: 30
          description: >-
            Contact phone, `+` then country calling code and number. Not
            subscribed to notifications.
        fax:
          type: string
          maxLength: 16
          description: '`+` followed by up to 15 digits.'
        company:
          type: string
          maxLength: 150
        tax_id:
          type: string
          maxLength: 100
    ShippingCostInput:
      type: object
      required:
        - name
      description: >-
        One shipping cost component. Provide `total_cost` directly, or
        `unit_cost` + `unit_quantity` to have it calculated. All entries in a
        request must use the same currency.
      properties:
        name:
          type: string
          description: Name of the cost component.
        reference:
          type: string
        unit_quantity:
          type: number
          exclusiveMinimum: 0
        unit_cost:
          type: string
          description: Money string, e.g. `2.50 SGD`.
        total_cost:
          type: string
          description: Money string, e.g. `150 SGD`.
    EventInput:
      type: object
      description: >-
        One manual event. Provide `description` **or** `standard_key`; if both,
        `standard_key` wins and `description` is ignored (299 warning). The
        Shipment must already have a tracking number and an assigned carrier.
      properties:
        description:
          type: string
          maxLength: 250
        standard_key:
          type: string
          maxLength: 5
          description: >-
            A Perform.AI standard event key. The key list is available from your
            account team.
        date_time:
          type: string
          description: ISO 8601. Defaults to the current time (UTC) when omitted.
        location:
          type: object
          properties:
            place:
              type: string
              maxLength: 250
              description: Required if `location` is provided.
        additional_info:
          type: object
          description: Custom fields. Keys max 50 chars, values max 150.
    LinkedShipmentInput:
      type: object
      required:
        - tracking_number
        - carrier_reference
      description: >-
        Another carrier's record of the same physical shipment. Its events are
        incorporated into the main Shipment.
      properties:
        tracking_number:
          type: string
          minLength: 6
          maxLength: 50
        carrier_reference:
          type: string
          maxLength: 50
          description: Must be configured in **Settings > Carriers**.
    DocumentInput:
      type: object
      required:
        - document_id
        - name
        - type
        - link
      description: >-
        A document attached by link. The link must be public, IP-allowlisted, or
        time-expiring; a document Perform.AI cannot download is not stored.
      properties:
        document_id:
          type: string
          maxLength: 50
          description: Your unique ID for the document within the Shipment.
        name:
          type: string
          maxLength: 50
        type:
          type: string
          maxLength: 25
          description: E.g. invoice, manifest, customs declaration.
        file_format:
          type: string
          maxLength: 25
        link:
          type: string
          format: uri
          description: Where Perform.AI downloads the document from.
        created_date:
          type: string
          description: ISO 8601. Defaults to the current time (UTC).
        additional_info:
          type: object
    LineItemInput:
      type: object
      description: One product line in the Shipment.
      properties:
        product_name:
          type: string
          maxLength: 500
        product_id:
          type: string
          maxLength: 50
        product_reference:
          type: string
          maxLength: 50
          description: Another reference for the line item, e.g. an SKU.
        product_category:
          type: string
          maxLength: 500
        product_description:
          type: string
          maxLength: 500
        product_origin_country_code:
          type: string
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 country of origin.
        hs_code:
          type: string
          maxLength: 20
          description: Harmonized System code, mainly for customs.
        customs_description:
          type: string
          maxLength: 500
        quantity:
          type: integer
          minimum: 1
          maximum: 1000000
          default: 1
        product_image_url:
          type: string
          format: uri
          maxLength: 1024
          description: JPG/PNG/GIF up to 5 MB; stored at up to 1 MB and 1024×1024.
        product_url:
          type: string
          format: uri
          maxLength: 1024
        product_weight:
          type: number
          minimum: 0
          description: Weight of a single unit.
        product_weight_unit:
          type: string
          maxLength: 5
        line_item_weight:
          type: number
          minimum: 0
        line_item_weight_unit:
          type: string
          maxLength: 5
        currency_code:
          type: string
          description: >-
            ISO 4217 currency for the cost fields. Must match across all line
            items in a Shipment.
        product_cost:
          type: number
          minimum: 0
        subtotal_cost:
          type: number
          minimum: 0
          description: Before discount and tax.
        discount_amount:
          type: number
          minimum: 0
        tax_amount:
          type: number
          minimum: 0
        misc_cost:
          type: number
          minimum: 0
        total_price:
          type: number
          minimum: 0
          description: After discount and tax.
        return_id:
          type: string
          maxLength: 50
          description: Return this line item belongs to, if any.
        return_reason:
          type: string
          maxLength: 512
        additional_info:
          type: object
          description: Custom fields. Keys max 50 chars, values max 150.
  responses:
    Unauthorized:
      description: >-
        The Bearer token is expired, invalid, or missing — or the account lacks
        access.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          example:
            api_response: 403
            message: Key not authorized
    Throttled:
      description: Rate limit exceeded (40 requests per second per account).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/GatewayError'
          example:
            api_response: 429
            message: Throttled
    SystemError:
      description: Internal system error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RequestError'
          example:
            api_response: '500'
            message: System error
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Used by every functional endpoint. Generate the token with `POST
        /auth/oauth/token/` and send it as `Authorization: Bearer {token}`.

````