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

# Update a shipment template

> Update an existing template with partial shipment input in shipment. This does not change or book any shipments previously created using the template. The response wraps the template resource in data.



## OpenAPI

````yaml /openapi-v2beta.json put /teams/{teamUuid}/shipment-templates/{shipmentTemplateUuid}
openapi: 3.1.0
info:
  title: Smart Send API
  description: >
    Shipment-centred API for discovering shipping services, booking immutable
    shipments, tracking parcels, downloading business documents, and printing.


    ## Contract status


    This v2 beta specification describes the target API contract agreed during
    the API design review. It is not a declaration that every operation and
    behaviour has already been deployed. The implementation must be brought into
    conformance before this contract is announced as available.


    ## Shipments and booking


    A shipment represents one logical carrier booking. Integrations own their
    webshop orders and store the returned shipment UUID, tracking numbers,
    documents and drop-off codes on those orders. There is no order
    synchronisation resource and no editing or rebooking of accepted shipment
    input.


    POST /teams/{teamUuid}/shipments validates before persistence and starts
    booking immediately. Upfront validation failure is 422 and creates no
    shipment. A successful booking returns 201. A definitive carrier rejection
    returns 424 with the persisted failed ShipmentResponse. Technical failures
    use appropriate 5xx responses. 424 is the application-specific use of Failed
    Dependency defined by RFC 4918, not a universal carrier convention.


    The server waits up to 10 seconds for the complete booking workflow. If
    processing continues, it returns 202 with ShipmentResponse, Location
    pointing to the ordinary shipment GET, and Retry-After: 5. Follow Location
    with GET. A successful GET always returns 200 with the current
    ShipmentResponse, including while booking is in progress or has failed. The
    response schema is the same; the representation is current, not a frozen
    copy of an earlier HTTP body. The worker's final booking deadline is
    separate from this HTTP wait. A rare late carrier success updates the same
    shipment.


    Booked means the carrier booking has succeeded and all required documents,
    QR codes and drop-off codes are ready. Printing is a separate process and
    does not delay booked. A completed carrier booking must never be repeated to
    recover a document-generation failure. Once the carrier has accepted a
    booking, deletion is forbidden even if document generation subsequently
    fails.


    ## Carrier roles


    Shipment delivery and shipment-specific delivery options expose carrier and
    last_mile_carrier as separate objects, each containing code, name, logo_url
    and icon_url. carrier identifies the provider whose service and account are
    used to book the shipment. service_code continues to identify that carrier's
    service; last_mile_carrier is response data and cannot be selected
    independently in booking input.


    last_mile_carrier is the expected final delivery partner configured for the
    selected shipping route. It is null when unknown. When the booking carrier
    also performs final delivery, return that carrier explicitly in both fields.
    This is planned delivery information, not a confirmation of a physical
    handoff or delivery. Snapshot the expected partner when accepting the
    shipment; later route-configuration changes do not rewrite that shipment's
    attribution. A last-mile partner does not require a separate carrier account
    for the team.


    Last mile follows the physical direction: delivery to the customer for
    outbound shipments, and delivery to the merchant for returns. It does not
    identify the customer's return drop-off network. Carrier branding does not
    change service-point identifiers or tracking numbers and URLs.


    The general GET /teams/{teamUuid}/routes response does not expose
    last_mile_carrier in this version. Its carrier object describes the provider
    whose services the team can book.


    ## Parties, delivery and defaults


    parties.merchant and parties.customer have stable commercial meanings,
    including on returns. When merchant is omitted, use the team's outbound
    sender address or return address as appropriate, falling back to the
    outbound address when no return address is configured. Pickup points,
    selected addons and delivery windows belong to delivery.


    Resolve and snapshot effective booking settings when accepting the shipment,
    including when adding it to an open batch. Later team-setting changes do not
    mutate accepted shipments. This contract has no per-booking overrides of
    team document or automatic-print preferences. Ordered team format
    preferences are negotiated up front; reject an incompatible selection with
    422 rather than silently choosing an unaccepted format. Carrier-specific
    constraints can still cause a subsequent booking failure.


    ## Currency and measurement units


    Each shipment must explicitly supply currency, weight_unit and
    dimension_unit, including each shipment submitted to a batch. The same
    requirement applies to shipment-specific delivery-options input. Missing,
    null or invalid values return 422; these fields never fall back to team
    defaults. Upfront shipment validation creates no shipment, and batch-add
    validation adds none of that request.


    A shipment uses one currency for its monetary amounts, one weight unit for
    all parcel and item weights, and one dimension unit for all parcel and item
    dimensions. Per-value overrides are not supported. Preserve the explicitly
    accepted values in responses. A batch or list may contain shipments with
    different units; each shipment carries its own context. Templates may be
    partial, but the integration must include all three fields in the final
    merged request.


    Service-point proximity results retain a distance object with value and unit
    on each result. Distance is returned only by the closest search, in metres,
    and is not moved into response metadata.


    ## Documents and codes


    Document means a completed business document intended for viewing or
    printing, such as a label, customs declaration, report or end-of-day
    manifest. Documents are team resources and may be associated with shipments,
    reports or manifests. QR images and machine-readable data exports are not
    Document resources.


    Shipment.documents embeds its booking documents, including metadata and
    expiring download URLs, never base64 file data. A document may cover
    multiple parcels or multiple document types. qr_codes and drop_off_codes are
    separate arrays directly on Shipment. A shared QR code is one array entry.
    Where a carrier returns one code per parcel, array index n corresponds to
    parcels[n]; no explicit parcel relation is exposed for these codes. Parcel
    and code order remains stable across responses.


    GET and idempotent replay can refresh file URLs without rebooking,
    generating documents again, or submitting print jobs. Access to an expired
    URL is recovered by retrieving the owning resource again.


    ## Documents, printers and print jobs


    Document represents one completed file. Its metadata is identical when
    embedded in a shipment or returned by document list/detail endpoints. width
    and height are distance objects in millimetres at document level; page_count
    is the number of pages or labels in the file. Every page or label must have
    the same dimensions in its finished orientation. For example, 101.6 × 152.4
    mm labels and an A4 invoice are separate documents with separate files. A
    document can contain multiple pages of the same size. Dimensions and
    page_count are null when unknown or not applicable, such as an XLSX report
    without fixed pagination. Null must not be used to disguise mixed page
    sizes. Store dimensions and page count when producing the file so metadata
    reads do not fetch or parse file contents.


    Document.print_status exposes the progress of the most recently created
    local print attempt directly in document and shipment responses. A null
    print_status means no local print request exists; the field is still
    present. Null does not mean an unknown outcome. pending means the request is
    recorded and Smart Send is preparing or waiting to submit it; queued means
    the print service has accepted it; printing means the provider reports
    processing; printed means the best available successful completion
    acknowledgement; failed means a known failure; unknown means the current
    outcome cannot be established. These attempt states have the same meanings
    as PrintJob.state. Printed currently means delivery to the operating-system
    print queue. Printing a downloaded file outside Smart Send is not observed.


    Select the most recently created print attempt by creation time and a stable
    creation-order tie-breaker, not by updated_at or callback arrival time. A
    new reprint immediately becomes the attempt represented by print_status,
    even after an earlier print succeeded. For example, printed can become
    pending and then failed. Delayed updates to older jobs update their own
    history without overriding the newer attempt's status.


    Retrieve all print attempts separately with GET
    /teams/{teamUuid}/print-jobs?document_uuid=... and follow the cursor until
    the end. Each PrintJob contains its state, fixed printer identity, copy
    count, error and timestamps. Earlier successful attempts remain in the
    history after a later failure. Document.updated_at advances when its
    published print_status or other document metadata changes; each job has its
    own updated_at. Print updates do not advance Shipment.updated_at or change
    its booking or tracking state. On a thin print_job.updated webhook, use
    document_uuid to retrieve the current document; the notification may concern
    an older attempt.


    Printer is current team configuration: identity, display name, availability,
    supported formats and paper_sizes. paper_sizes is null when unknown,
    otherwise an array of driver-advertised named sizes with width and height
    distance objects in millimetres. Individual dimensions are null when only
    the name is known. An empty array means the provider reported no named
    sizes, not that printing or custom sizes are unsupported. Multiple sizes may
    be advertised at once. This list does not map sizes to trays or confirm
    which paper is currently loaded. GET /printers/{printer} returns that
    current resource. Default selection rules are part of team settings and may
    choose different printers for different file formats and page layouts. Print
    jobs embed only the selected printer identity captured for the attempt, so
    later renames, availability changes or removal do not rewrite history. They
    also embed the document identity and display metadata captured when the job
    was created; current document metadata is retrieved through the document
    endpoint.


    One PrintJob represents one logical print attempt for an entire completed
    file and a copy count. All print attempts use the same public
    representation, regardless of how they were initiated. Record accepted print
    intent locally before file preparation or external submission; setup failure
    then produces a failed job rather than disappearing. When booking also
    requests printing, record the corresponding local jobs before returning
    document metadata so the response shows pending, or a later state if already
    reached. Printing itself remains asynchronous. printer may be null if an
    accepted attempt has not selected a target or failed before selection. Once
    selected, the target is fixed for the attempt. POST /print-jobs validates
    its target before accepting a job and returns 422 when invalid. Rejected
    requests create no print attempt and do not change the document's current
    print_status.


    POST /print-jobs returns 201 once the local job is durably accepted,
    normally pending. Printing continues asynchronously; retrieve Location or
    consume print_job.updated notifications. POST and GET return the same
    PrintJobResponse structure. queued means accepted by the print service;
    printed requires its best available completion acknowledgement, currently
    delivery to the operating-system print queue. Printing is independent of
    document readiness and shipment booking state. Duplicate or delayed provider
    updates must not erase a confirmed success; a subsequent successful
    acknowledgement clears a previous failure on the same job. Reprints create
    separate jobs, and unknown outcomes must be checked before requesting
    another print to avoid duplicate output.


    ## Idempotency


    Idempotency-Key is optional on operations that declare it. Without a key,
    each valid create request is independent, even for identical content. No key
    is generated from the payload. Use a fresh client-generated key for each
    intended action and reuse it for recovery after a lost response.


    Keys are scoped to the team, HTTP method and canonical target path. A key
    binds atomically to the accepted action and its resources, with a request
    fingerprint. Object-key ordering is ignored; array order is significant.
    Resolve defaults only once for the accepted action. A changed payload with
    the same key is 422 with a validation error for Idempotency-Key. A
    concurrent duplicate is 409 with Retry-After and, when known, Location. Once
    completed, reconstruct the result from the stored outcome and current
    resource representation and return Idempotency-Replayed: true. URLs and
    subsequent resource state can therefore differ from the first response. For
    shipment creation, the status reflects the booking outcome: 201 for success
    or 424 for carrier rejection, even if a later cancellation has changed the
    current shipment state.


    Retain keys for at least 24 hours from acceptance and never expire an
    actively processing action. After expiry, reusing a key may execute a new
    action. Authentication, authorisation and upfront validation failures do not
    reserve a key. The header does not replace the 202/Location polling flow.
    Idempotency-Replayed is this API's documented extension, not a standard HTTP
    header.


    ## HTTP errors


    Request errors use JSON: message for an ordinary error, with an additional
    errors object for 422 validation failures. There is no custom error code
    field. Use the HTTP status, documented response headers and resource state
    to decide what to do; message text may be localised and can change. Send
    Accept: application/json.


    | Status | Meaning | Client action |

    | --- | --- | --- |

    | 401 | Missing or invalid authentication. | Supply valid credentials. |

    | 403 | Missing permission or scope. | Check team access and permissions. |

    | 404 | Resource unavailable to this team. | Check the resource identifier
    and team. |

    | 409 with Retry-After | An action with this idempotency key is still
    processing. | Wait, then GET Location if supplied; otherwise retry the
    original request with the same key and payload. |

    | 409 without Retry-After | Conflict with resource state or an ambiguous
    tracking lookup. | Retrieve current state or supply the documented tracking
    filters. Do not automatically repeat an unchanged request. |

    | 410 | Tracking cursor expired. | Resynchronise and establish a new feed
    position. |

    | 422 | Invalid input, including reuse of a key with different input. |
    Correct the entries in errors. Upfront booking validation creates no
    shipment; batch-add validation adds none of that request. |

    | 424 | Carrier rejected an accepted booking. | Inspect the persisted failed
    ShipmentResponse. Corrected input requires a new shipment. |

    | 429 | Rate limit reached. | Wait for Retry-After. |

    | 500 | Unexpected server failure. | Recover using the known resource URL or
    original idempotency key; include Request-ID in support reports. |

    | 502 | Accepted booking workflow failed technically. | Inspect the failed
    ShipmentResponse; recover documents without rebooking after carrier
    acceptance. |

    | 503 | Temporary service unavailability. | Wait for Retry-After; preserve
    the original idempotency key when retrying an action. |

    | 504 | Final booking deadline expired. | Inspect the persisted failed
    ShipmentResponse; a rare late carrier success may still update it. |


    The distinction between the two 409 cases using Retry-After is this API's
    convention, not a universal HTTP rule. The usual 10-second booking wait
    returns 202, not 504. A later GET returns 200 when retrieval succeeds, even
    when the shipment's state is failed. Booking-specific 424/502/504 responses
    keep the ShipmentResponse shape rather than switching to a generic
    message-only body.


    ### Invalid shipment input


    ```http

    HTTP/1.1 422 Unprocessable Content

    Content-Type: application/json

    Request-ID: req-example-validation


    {
      "message": "The customer postal code is required.",
      "errors": {
        "parties.customer.address.postal_code": [
          "The customer postal code is required."
        ]
      }
    }

    ```


    ### Batch membership is locked


    ```http

    HTTP/1.1 409 Conflict

    Content-Type: application/json

    Request-ID: req-example-batch


    {
      "message": "Shipments can only be added to an open batch."
    }

    ```


    ### An idempotent request is still processing


    ```http

    HTTP/1.1 409 Conflict

    Content-Type: application/json

    Retry-After: 5

    Request-ID: req-example-processing


    {
      "message": "A request with this Idempotency-Key is still being processed."
    }

    ```


    Location may additionally identify the resource when known. Browser clients
    must be able to read Location, Retry-After, Request-ID and
    Idempotency-Replayed on cross-origin responses; the server exposes these
    through Access-Control-Expose-Headers.


    ## Pagination and synchronisation


    Paginated requests use cursor and per_page for cursor pagination, or page
    and per_page for page pagination. Omit cursor or page for the first page.
    Page numbers start at 1; cursors are opaque. Page-size defaults and limits
    are declared for each endpoint.


    All paginated responses contain data, links and meta. links always contains
    first, last, prev and next. Cursor pagination sets first and last to null;
    its meta contains path, per_page, next_cursor and prev_cursor. Page
    pagination provides first/last URLs and meta.current_page, from, last_page,
    links, path, per_page, to and total. Its meta.links is a navigation window;
    labels are display text, and ellipsis entries omit page. An empty page has
    an empty data array and null from/to. meta.path is the collection URL
    without query parameters.


    Follow the returned navigation URLs with GET. They preserve filters,
    sorting, per_page and the fixed sync boundary where applicable. Changing
    these values starts a new page sequence. Shipments add meta.sync_until and
    tracking adds meta.resume_cursor as endpoint-specific extensions. Cursor
    pagination does not provide a total count or last page number.


    Shipment lists represent current resources, not every intermediate change.
    Shipment.updated_at follows its booking lifecycle, including cancellation;
    tracking changes, print updates and refreshed file URLs do not advance it.
    For incremental sync use inclusive updated_since, sort=updated_at and the
    server-provided sync_until boundary. Follow all next links, then persist
    that boundary. On the next round, subtract an overlap (60 seconds is a
    suggested starting point) and upsert by shipment UUID. Mutable timestamps
    can cause duplicates or omit intermediate states; overlap does not turn this
    into a lossless history. Use include_deleted=true for minimal deletion
    markers and periodic reconciliation where necessary.


    The dedicated tracking/events endpoint is append-only and uses publication
    order, not carrier event time. Its resume_cursor remains usable at the end
    of a page sequence, including empty responses. ETA changes also produce feed
    entries. Tracking and print resources have their own timestamps.


    ## Webhooks and batch callbacks


    Team webhooks are configured through team settings. A batch may additionally
    register its own callback during creation. Both use the same signed thin
    event envelopes: event id, type, occurred_at, team_uuid and affected
    resource identifiers. Retrieve full resource data through the ordinary
    authenticated API when needed. A GET returns current state, which can differ
    from the state when the event occurred. Tracking notifications wake the
    consumer to resume the tracking event feed; deletion notifications identify
    what to remove without requiring a successful GET. Full payloads may be
    added later as an explicit opt-in. Delivery can be duplicated or arrive out
    of order; deduplicate by event id and retrieve the current resource when
    needed. A callback failure never repeats a booking or print action.
    Signatures follow the Standard Webhooks convention. See the callback and
    webhook definitions for delivery and acknowledgement rules.


    ## Localisation and request identification


    Accept-Language takes precedence over the team's default language, with
    English as fallback. Carrier, service and addon codes are stable; names and
    messages may be localised. Error messages are for people, not client control
    flow. A descriptive User-Agent identifies the integration. Request-ID is
    returned on every API response and should be included in support reports.
    Currency amounts use the ISO 4217 currency's minor unit; null means unknown,
    not zero. Dates use RFC 3339 with an explicit UTC offset.
  version: 2.0.0-beta
  contact:
    name: Smart Send
    url: https://www.smartsend.io
  x-contract-status: design
  x-design-defaults:
    http_wait_seconds: 10
    poll_after_seconds: 5
    idempotency_retention_hours: 24
    list_default_per_page: 100
    list_max_per_page: 1000
    batch_add_max_shipments: 100
    webhook_retry_window_hours: 24
    tracking_feed_retention_days: 90
  x-webhook-payload-mode: thin
servers:
  - url: https://api.smartsend.io/v2
    description: Production
security:
  - bearerAuth: []
  - oauth2: []
tags:
  - name: Me
    description: Information about the authenticated user
  - name: Teams
    description: Teams available to the authenticated user
  - name: Service Points
    description: Pickup points and delivery locations
  - name: Carrier Catalog
    description: >-
      Global reference data for carriers, services, and addons. Not
      team-specific.
  - name: Routing
    description: >-
      Team-specific listing of available carriers, services, and addons based on
      configured carrier accounts. Pre-shipment meaning no shipment details
      required.
  - name: Delivery Options
    description: >-
      Shipment-specific delivery options including available services, addons,
      estimated pricing, and delivery windows.
  - name: Tracking
    description: Shipment tracking information and event history
  - name: Shipments
    description: >-
      Immutable booking input, one logical booking per shipment, cancellation
      and synchronisation.
  - name: Booking batches
    description: >-
      Validate shipments before adding them to a batch; after start, book one
      shipment at a time in insertion order.
    externalDocs:
      description: Batch booking documentation
      url: https://docs.smartsend.io/features/booking#batch-booking
  - name: Shipment Templates
    description: >-
      Reusable shipment templates for quickly creating shipments with
      pre-configured delivery, consignment, and parcel settings.
  - name: WMS Experimental
    description: >-
      Warehouse management for a team's configured WMS driver. Covers
      fulfillment requests (listing open requests, inspecting picking lines,
      recording packed lines), inventory levels (listing, moving between bins,
      adjusting counts), and catalog items (SKU lookup).
  - name: Documents
    description: >-
      Completed business documents for viewing or printing, with metadata and
      download links.
  - name: Printing
    description: Discover printers and follow document print jobs.
  - name: Webhooks
    description: Signed resource updates and batch-specific callbacks.
paths:
  /teams/{teamUuid}/shipment-templates/{shipmentTemplateUuid}:
    put:
      tags:
        - Shipment Templates
      summary: Update a shipment template
      description: >-
        Update an existing template with partial shipment input in shipment.
        This does not change or book any shipments previously created using the
        template. The response wraps the template resource in data.
      operationId: updateShipmentTemplate
      parameters:
        - $ref: '#/components/parameters/teamUuid'
        - name: shipmentTemplateUuid
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: UUID of the shipment template
        - $ref: '#/components/parameters/Accept-Language'
        - $ref: '#/components/parameters/Request-ID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ShipmentTemplateInput'
            examples:
              CreateShipmentTemplateInput:
                $ref: '#/components/examples/CreateShipmentTemplateInput'
      responses:
        '200':
          description: Shipment template updated successfully
          headers:
            Request-ID:
              $ref: '#/components/headers/Request-ID'
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/ShipmentTemplate'
              examples:
                ShipmentTemplateResponse:
                  $ref: '#/components/examples/ShipmentTemplateResponse'
        '401':
          $ref: '#/components/responses/ApiUnauthorized'
        '403':
          $ref: '#/components/responses/ApiForbidden'
        '404':
          $ref: '#/components/responses/ApiNotFound'
        '422':
          $ref: '#/components/responses/ApiValidationError'
        '429':
          $ref: '#/components/responses/ApiTooManyRequests'
        '500':
          $ref: '#/components/responses/ApiInternalServerError'
        '503':
          $ref: '#/components/responses/ApiServiceUnavailable'
      security:
        - bearerAuth: []
        - oauth2:
            - shipment:write
components:
  parameters:
    teamUuid:
      name: teamUuid
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Team uuid. All resources are scoped to this team.
    Accept-Language:
      name: Accept-Language
      in: header
      required: false
      schema:
        type: string
        default: en
        examples:
          - da-DK, da;q=0.9, en;q=0.8
      description: >-
        Preferred language(s) for translatable content using BCP 47 language
        tags. Supports quality values (q-factors) for priority ordering. The API
        negotiates the best available language based on this header, the team's
        configured language, and available translations. If omitted, the team's
        default language is used.
    Request-ID:
      name: Request-ID
      in: header
      required: false
      schema:
        type: string
        minLength: 1
        maxLength: 64
        pattern: ^[A-Za-z0-9._-]{1,64}$
      description: >-
        Optional client-supplied request identifier. When provided and matching
        the validation pattern, the value is echoed back in the `Request-ID`
        response header. Otherwise the server generates one. Use this to
        correlate requests between client and server when reporting issues.
      examples:
        uuid:
          summary: UUID v7
          value: 019c486f-c237-76f5-85e1-ba7017a77024
        opaque:
          summary: Opaque client-generated key
          value: booking-12345-at-1768609378
  schemas:
    ShipmentTemplateInput:
      type: object
      required:
        - title
        - shipment
      properties:
        title:
          type: string
          maxLength: 255
          description: Human-readable name for the template.
        description:
          type:
            - 'null'
            - string
          description: Optional description of what the template is used for.
        shipment:
          $ref: '#/components/schemas/ShipmentTemplateData'
          description: >-
            Partial booking input to prefill a shipment. This is a reusable set
            of input fields, not a created shipment resource; it has no shipment
            UUID or booking state.
      description: >-
        Create or update a template using title, an optional description and
        partial shipment input. Request bodies have no outer data wrapper.
    ShipmentTemplate:
      type: object
      required:
        - uuid
        - title
        - shipment
        - created_at
        - updated_at
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the shipment template.
        title:
          type: string
          description: Human-readable name for the template.
          examples:
            - Standard domestic parcel
        description:
          type:
            - 'null'
            - string
          description: Optional description of what the template is used for.
        shipment:
          $ref: '#/components/schemas/ShipmentTemplateData'
          description: >-
            Partial booking input to prefill a shipment. This is a reusable set
            of input fields, not a created shipment resource; it has no shipment
            UUID or booking state.
        created_at:
          type: string
          format: date-time
          readOnly: true
          description: When the template was created (ISO 8601).
        updated_at:
          type: string
          format: date-time
          readOnly: true
          description: When the template was last updated (ISO 8601).
      description: >-
        A saved template with its own identity, display metadata and partial
        shipment input. Successful responses wrap this template in data; its
        reusable booking fields are in shipment.
    ShipmentTemplateData:
      type: object
      properties:
        currency:
          type: string
          minLength: 3
          maxLength: 3
          description: ISO 4217 currency code for all monetary values
          examples:
            - EUR
          pattern: ^[A-Z]{3}$
        weight_unit:
          $ref: '#/components/schemas/WeightUnit'
        dimension_unit:
          $ref: '#/components/schemas/DimensionUnit'
        invoice_number:
          type:
            - 'null'
            - string
          description: >-
            Customs invoice number when applicable. Use reference for the public
            order reference.
          examples:
            - INV-1001121
        reference:
          type:
            - 'null'
            - string
          description: >-
            Public reference, e.g. order number or SKU, which may be forwarded
            to the carrier or printed. Not necessarily unique.
          examples:
            - Order-5521
        identifier:
          type:
            - 'null'
            - string
          description: >-
            Private integration reference, e.g. a database ID. Not used for
            deduplication and not forwarded to carrier labels. Not necessarily
            unique.
        uri:
          type:
            - 'null'
            - string
          format: uri
          description: >-
            URI linking to the source of this shipment (webshop order URL, deep
            link, or any URI scheme)
        delivery:
          type: object
          properties:
            service_code:
              type: string
              description: Composite service code identifying both carrier and product.
              minLength: 1
              examples:
                - postnord_agent
            pickup_point:
              anyOf:
                - type: 'null'
                - $ref: '#/components/schemas/PickupPointInput'
              examples:
                - null
              description: >-
                Selected pickup point, or null when none is selected. An empty
                object is not a valid pickup point.
            addons:
              type: array
              items:
                $ref: '#/components/schemas/AddonInput'
              description: >-
                Selected addons. Omit to apply the route defaults; an empty
                array explicitly selects no optional addons.
            delivery_window:
              anyOf:
                - $ref: '#/components/schemas/DateTimeWindow'
                - type: 'null'
            incoterm:
              anyOf:
                - $ref: '#/components/schemas/Incoterm'
                - type: 'null'
          additionalProperties: false
        parties:
          $ref: '#/components/schemas/ShipmentPartiesInput'
        parcels:
          type: array
          items:
            $ref: '#/components/schemas/ShipmentParcelInput'
          description: Parcels in stable input order.
          minItems: 1
        total_net_amount:
          type:
            - 'null'
            - integer
          description: Total goods value in minor units (cents) excluding tax
          examples:
            - 15920
        tax_amount:
          type:
            - 'null'
            - integer
          description: Total goods tax in minor units (cents)
          examples:
            - 3980
        duty_amount:
          type:
            - 'null'
            - integer
          description: Total goods duty in minor units (cents)
          examples:
            - 5572
        shipping_net_amount:
          type:
            - 'null'
            - integer
          description: Shipping cost in minor units (cents) excluding tax
          examples:
            - 3920
        shipping_tax_amount:
          type:
            - 'null'
            - integer
          description: Shipping tax in minor units (cents)
          examples:
            - 980
        content_type:
          $ref: '#/components/schemas/ShipmentContentType'
      description: >-
        Partial ShipmentInput used as an integration template. Merge selected
        template input in the client before booking; the server validates and
        snapshots the submitted result. This does not override team document or
        automatic-print settings. Templates may omit currency and measurement
        units, but the final merged shipment or delivery-options request must
        explicitly supply currency, weight_unit and dimension_unit; the server
        does not fill them from team defaults.
      additionalProperties: false
    ApiErrorResponse:
      type: object
      properties:
        message:
          type: string
          description: >-
            Human-readable, possibly localised explanation. Do not parse this
            text for client control flow.
      required:
        - message
      description: >-
        An unsuccessful API request, using JSON with message and no custom error
        code. Persisted booking outcomes use ShipmentResponse where documented.
    ApiValidationErrorResponse:
      type: object
      properties:
        message:
          type: string
          description: >-
            Human-readable, possibly localised explanation. Do not parse this
            text for client control flow.
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: >-
            Field or header names mapped to validation messages. Nested input
            uses dot notation, e.g. data.0.parties.customer.address.country.
            Header validation uses the header name, e.g. Idempotency-Key.
      required:
        - message
        - errors
      description: >-
        422 validation response. Field errors use dot notation for nested input;
        Idempotency-Key identifies a header validation error.
    WeightUnit:
      type: string
      description: Unit of measurement for weight
      enum:
        - g
        - kg
        - lb
        - oz
      examples:
        - g
    DimensionUnit:
      type: string
      description: Unit of measurement for dimensions
      enum:
        - mm
        - cm
        - m
        - in
      examples:
        - cm
    PickupPointInput:
      description: >-
        Identify the selected pickup point by UUID or by carrier reference, but
        not both. The carrier is derived from delivery.service_code.
      oneOf:
        - type: object
          properties:
            uuid:
              type: string
              description: Service-point UUID returned by discovery.
              format: uuid
          required:
            - uuid
          additionalProperties: false
        - type: object
          properties:
            country:
              type: string
              description: ISO 3166-1 alpha-2 country code.
              pattern: ^[A-Z]{2}$
            code:
              type: string
              description: Carrier service-point code; preserve leading zeroes.
              minLength: 1
          required:
            - country
            - code
          additionalProperties: false
    AddonInput:
      type: object
      properties:
        code:
          type: string
          description: Supported addon code, as returned by discovery.
          examples:
            - SIGNATURE
      required:
        - code
      additionalProperties: false
    DateTimeWindow:
      type: object
      required:
        - earliest
        - latest
      properties:
        earliest:
          type: string
          format: date-time
          description: Inclusive beginning of the window (RFC 3339).
          examples:
            - '2025-01-02T00:00:00Z'
        latest:
          type: string
          format: date-time
          description: Inclusive end of the window (RFC 3339).
          examples:
            - '2025-01-04T23:59:59Z'
      description: >-
        A bounded time window with earliest <= latest. Its owning field
        identifies whether it is an estimate or a requested delivery choice.
    Incoterm:
      type: string
      description: International Commercial Terms for trade
      enum:
        - EXW
        - FCA
        - CPT
        - CIP
        - DAP
        - DPU
        - DDP
    ShipmentPartiesInput:
      type: object
      properties:
        merchant:
          $ref: '#/components/schemas/PartyInput'
        customer:
          $ref: '#/components/schemas/PartyInput'
      required:
        - customer
      description: >-
        Omit merchant to use the appropriate team address. Pickup points belong
        to delivery.
      additionalProperties: false
    ShipmentParcelInput:
      type: object
      properties:
        reference:
          type:
            - 'null'
            - string
          description: >-
            Public reference, e.g. order number or SKU, which may be forwarded
            to the carrier or printed. Not necessarily unique.
        identifier:
          type:
            - 'null'
            - string
          description: >-
            Private integration reference, e.g. a database ID. Not used for
            deduplication and not forwarded to carrier labels. Not necessarily
            unique.
        freetext:
          type:
            - 'null'
            - string
          description: Description or notes for the parcel
          examples:
            - Gift wrapped as per requested
        gross_weight:
          type:
            - 'null'
            - number
          minimum: 0
          description: >-
            Weight of the parcel including both packaging and content (in the
            shipment's weight_unit) Omitted values are resolved only where the
            team and service allow; otherwise upfront validation fails.
          examples:
            - 1500
        length:
          type:
            - 'null'
            - number
          minimum: 0
          description: >-
            Parcel length (in the shipment's dimension_unit) Omitted values are
            resolved only where the team and service allow; otherwise upfront
            validation fails.
          examples:
            - 30
        width:
          type:
            - 'null'
            - number
          minimum: 0
          description: >-
            Parcel width (in the shipment's dimension_unit) Omitted values are
            resolved only where the team and service allow; otherwise upfront
            validation fails.
          examples:
            - 20
        height:
          type:
            - 'null'
            - number
          minimum: 0
          description: >-
            Parcel height (in the shipment's dimension_unit) Omitted values are
            resolved only where the team and service allow; otherwise upfront
            validation fails.
          examples:
            - 15
        total_net_amount:
          type:
            - 'null'
            - integer
          description: Total value in minor units (cents) excluding tax
          examples:
            - 15920
        tax_amount:
          type:
            - 'null'
            - integer
          description: Tax amount in minor units (cents)
          examples:
            - 3980
        duty_amount:
          type:
            - 'null'
            - integer
          description: Duty amount in minor units (cents)
          examples:
            - 5572
        items:
          type: array
          items:
            $ref: '#/components/schemas/ShipmentParcelItemInput'
          description: Item lines; required for routes needing item-level customs data.
      description: >-
        Immutable parcel input. Weight and dimensions use the enclosing shipment
        units.
      additionalProperties: false
    ShipmentContentType:
      type: string
      description: Type of contents in the shipment
      enum:
        - commercial_goods
        - returned_goods
        - gift
        - commercial_sample
        - documents
        - other
    PartyInput:
      type: object
      properties:
        reference:
          type:
            - 'null'
            - string
          description: Human-readable reference visible externally
        identifier:
          type:
            - 'null'
            - string
          description: System identifier for internal integrations
        uri:
          type:
            - 'null'
            - string
          format: uri
          description: URI linking to this party (URL, deep link, or any URI scheme)
        address:
          $ref: '#/components/schemas/AddressInput'
        contact:
          $ref: '#/components/schemas/ContactInput'
        identifiers:
          anyOf:
            - $ref: '#/components/schemas/PartyIdentifiersInput'
            - type: 'null'
      required:
        - address
        - contact
      description: >-
        A merchant or customer. Roles stay the same for outbound and return
        services.
      additionalProperties: false
    ShipmentParcelItemInput:
      type: object
      properties:
        reference:
          type:
            - 'null'
            - string
          description: >-
            Public reference, e.g. order number or SKU, which may be forwarded
            to the carrier or printed. Not necessarily unique.
        identifier:
          type:
            - 'null'
            - string
          description: >-
            Private integration reference, e.g. a database ID. Not used for
            deduplication and not forwarded to carrier labels. Not necessarily
            unique.
        uri:
          type:
            - 'null'
            - string
          format: uri
          description: >-
            URI linking to this item (product page URL, deep link, or any URI
            scheme)
        image_url:
          type:
            - 'null'
            - string
          format: url
          description: URL for an product thumbnail image
          examples:
            - https://www.example.com/products/1234-image1.jpeg
        sku:
          type:
            - 'null'
            - string
          description: Stock keeping unit identifier
          examples:
            - PROD-001
        location:
          type:
            - 'null'
            - string
          description: Warehouse location
          examples:
            - AA-01-B45-C
        name:
          type:
            - 'null'
            - string
          description: Product name
          examples:
            - Widget
        description:
          type:
            - 'null'
            - string
          description: Product description for customs
        tariff_code:
          type:
            - 'null'
            - string
          description: HS/customs tariff code
          examples:
            - '8471300000'
        country_of_origin:
          type:
            - 'null'
            - string
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 country code of origin
          examples:
            - CN
        quantity:
          type: number
          exclusiveMinimum: 0
          description: Quantity represented by this item line.
        total_net_amount:
          type:
            - 'null'
            - integer
          description: Total value for all quantities in minor units (cents) excluding tax
          examples:
            - 15920
        tax_amount:
          type:
            - 'null'
            - integer
          description: Total tax for all quantities in minor units (cents)
          examples:
            - 3980
        duty_amount:
          type:
            - 'null'
            - integer
          description: Total duty for all quantities in minor units (cents)
          examples:
            - 5572
        net_weight:
          type:
            - 'null'
            - number
          minimum: 0
          description: >-
            Weight of all items excluding any packaging (in the shipment's
            weight_unit)
          examples:
            - 550
        cost_amount:
          type:
            - 'null'
            - integer
          description: Cost of all itemst in minor units (cents) - no vat or duty
          examples:
            - 5300
        dangerous_goods:
          type:
            - 'null'
            - array
          items:
            $ref: '#/components/schemas/DangerousGood'
          description: Dangerous goods contained in this item
      required:
        - quantity
      description: >-
        A parcel item. Customs fields are required when applicable to the
        selected route. Values and net_weight are totals for the line, not
        per-unit amounts.
      additionalProperties: false
    AddressInput:
      type: object
      required:
        - city
        - country
      properties:
        address_lines:
          type:
            - 'null'
            - array
          items:
            type: string
          maxItems: 3
          description: Street address lines (e.g., street name, building, floor)
          examples:
            - - 3200 Whitehaven St. NW
              - Building A, Floor 2
        postal_code:
          type:
            - 'null'
            - string
          description: >-
            Postal/ZIP code. Always a string, even when the value is purely
            numeric.
          examples:
            - 20008-4351
        city:
          type: string
          description: City
          examples:
            - Washington
        country:
          type: string
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 country code
          examples:
            - US
          pattern: ^[A-Z]{2}$
        administrative_area:
          type:
            - 'null'
            - string
          minLength: 2
          maxLength: 3
          description: >-
            The sub-national subdivision code (e.g., state, province, or
            department) representing the suffix part of the ISO 3166-2 standard.
            This field should contain only the characters following the hyphen.
            For example, for 'US-NY', provide 'NY'; for 'JP-13', provide '13'
          examples:
            - DC
      additionalProperties: false
      description: >-
        Postal address. Additional street, postal-code and administrative-area
        requirements depend on the selected service and country and are
        validated before acceptance.
    ContactInput:
      type: object
      required:
        - name_lines
      description: Contact information for a party
      properties:
        name_lines:
          type: array
          items:
            type: string
          minItems: 1
          maxItems: 2
          description: Name lines (e.g., person name, company name, department)
          examples:
            - - John Doe
              - Att. Finance department
        company:
          type:
            - 'null'
            - string
          description: Company or organization name
          examples:
            - Acme Corp
        email:
          type:
            - 'null'
            - string
          format: email
          description: Email address
          examples:
            - john@example.com
        phone:
          type:
            - 'null'
            - string
          description: Phone number with country code
          examples:
            - '+4512345678'
      additionalProperties: false
    PartyIdentifiersInput:
      type: object
      description: Tax and trade identifiers for customs clearance
      properties:
        vat:
          type:
            - 'null'
            - string
          description: VAT identification number
          examples:
            - DK12345678
        eori:
          type:
            - 'null'
            - string
          description: Economic Operators Registration and Identification number (EU)
          examples:
            - DK1234567890123
        gb_eori:
          type:
            - 'null'
            - string
          description: GB EORI number for UK customs
          examples:
            - GB123456789000
        tax_id:
          type:
            - 'null'
            - string
          description: Tax identification number
          examples:
            - DK1234567890
        voec:
          type:
            - 'null'
            - string
          description: VOEC (VAT on E-Commerce) number for Norway
          examples:
            - '2000123'
      additionalProperties: false
    DangerousGood:
      type: object
      required:
        - un_number
        - class
        - un_packing_group
        - tunnel_restriction_code
        - net_weight
        - quantity
        - environmentally_hazardous
      properties:
        un_number:
          type: string
          description: UN number (e.g., '1202', '1950')
        class:
          type: string
          description: Dangerous goods class (e.g., '1', '2.1', '3', '8')
        un_packing_group:
          type:
            - 'null'
            - string
          description: UN packing group (e.g., 'I', 'II', 'III')
        tunnel_restriction_code:
          type:
            - 'null'
            - string
          enum:
            - A
            - B
            - C
            - D
            - E
            - null
          description: ADR tunnel restriction code. A=no restrictions, E=most restrictive
        net_weight:
          type:
            - 'null'
            - number
          minimum: 0
          description: Net weight of this dangerous good (in the shipment's weight_unit)
        quantity:
          type:
            - 'null'
            - number
          minimum: 0
          description: Quantity of this dangerous good
        environmentally_hazardous:
          type:
            - 'null'
            - boolean
          description: Whether this is environmentally hazardous
  examples:
    CreateShipmentTemplateInput:
      summary: Save partial shipment input with its explicit measurement units.
      value:
        title: Standard domestic parcel
        description: Default service and packaging for a small parcel.
        shipment:
          currency: DKK
          weight_unit: g
          dimension_unit: cm
          delivery:
            service_code: postnord_agent
            pickup_point: null
          parcels:
            - gross_weight: 1000
              length: 30
              width: 20
              height: 15
    ShipmentTemplateResponse:
      summary: Template metadata in data and reusable booking input in data.shipment.
      value:
        data:
          uuid: aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa
          title: Standard domestic parcel
          description: Default service and packaging for a small parcel.
          shipment:
            currency: DKK
            weight_unit: g
            dimension_unit: cm
            delivery:
              service_code: postnord_agent
              pickup_point: null
            parcels:
              - gross_weight: 1000
                length: 30
                width: 20
                height: 15
          created_at: '2026-09-18T14:00:00Z'
          updated_at: '2026-09-18T14:00:00Z'
    Unauthenticated:
      summary: 401 — Missing or invalid credentials
      value:
        message: Unauthenticated.
      description: >-
        Supply a valid API token. Repeating the same credentials does not
        resolve this response.
    PermissionDenied:
      summary: 403 — Insufficient team permission
      value:
        message: This action is unauthorized.
      description: Use credentials with the required team permission or scope.
    ResourceNotFound:
      summary: 404 — Resource unavailable to this team
      value:
        message: The requested resource was not found.
      description: >-
        Check the resource UUID and team. A missing, deleted or other-team
        resource uses the same response.
    ValidationFailed:
      summary: 422 — Validation response shape
      value:
        message: The given data was invalid.
        errors:
          field_name:
            - This field is required.
      description: >-
        Illustrative field name; actual errors name the invalid request fields.
        See shipment and batch operations for concrete examples.
    TooManyRequests:
      summary: 429 — Rate limit reached
      value:
        message: Too Many Attempts.
      description: >-
        Wait for the number of seconds in Retry-After before sending another
        request.
    ServerError:
      summary: 500 — Unexpected server failure
      value:
        message: Server Error
      description: >-
        An action may already have been accepted. Recover through its known
        resource URL or retry with the original Idempotency-Key. Include
        Request-ID when contacting support.
    ServiceUnavailable:
      summary: 503 — Temporary unavailability
      value:
        message: Service Unavailable
      description: >-
        Wait for Retry-After before retrying. Preserve the original
        Idempotency-Key for an action that may already have been accepted.
  headers:
    Request-ID:
      description: >-
        Unique identifier for this HTTP request. Always present in responses.
        Echoes the client-supplied `Request-ID` request header when it matches
        the validation pattern; otherwise the server generates a UUIDv7. Include
        this value when reporting issues so support can locate the request in
        logs.
      schema:
        type: string
        minLength: 1
        maxLength: 64
        pattern: ^[A-Za-z0-9._-]{1,64}$
    Retry-After:
      description: >-
        Delay in seconds before the next polling or retry request. Booking
        polling normally uses 5.
      schema:
        type: integer
        minimum: 1
        examples:
          - 5
  responses:
    ApiUnauthorized:
      description: Authentication is missing or invalid.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            Unauthenticated:
              $ref: '#/components/examples/Unauthenticated'
    ApiForbidden:
      description: The authenticated principal lacks the required team permission or scope.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            PermissionDenied:
              $ref: '#/components/examples/PermissionDenied'
    ApiNotFound:
      description: The resource is absent, belongs to another team, or has been deleted.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            ResourceNotFound:
              $ref: '#/components/examples/ResourceNotFound'
    ApiValidationError:
      description: >-
        Invalid request input or reuse of an Idempotency-Key with different
        input. Upfront shipment validation creates no shipment; a failing
        batch-add request adds none of its members. Correct the fields listed in
        errors before retrying.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiValidationErrorResponse'
          examples:
            ValidationFailed:
              $ref: '#/components/examples/ValidationFailed'
    ApiTooManyRequests:
      description: Rate limit exceeded. Wait for Retry-After before retrying.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            TooManyRequests:
              $ref: '#/components/examples/TooManyRequests'
    ApiInternalServerError:
      description: >-
        Unexpected server failure. An accepted action may already exist; recover
        using the same idempotency key or known resource URL.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            ServerError:
              $ref: '#/components/examples/ServerError'
    ApiServiceUnavailable:
      description: The service is temporarily unavailable.
      headers:
        Request-ID:
          $ref: '#/components/headers/Request-ID'
        Retry-After:
          $ref: '#/components/headers/Retry-After'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          examples:
            ServiceUnavailable:
              $ref: '#/components/examples/ServiceUnavailable'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
    oauth2:
      type: oauth2
      description: OAuth 2.0 Authorization Code flow for API access
      flows:
        authorizationCode:
          authorizationUrl: https://app.smartsend.io/oauth/authorize
          tokenUrl: https://app.smartsend.io/oauth/token
          scopes:
            teams:read: Access team information
            members:read: Read team member information
            members:write: Manage team members
            service_points: Access service points and pickup locations
            routing: Access team-specific routing (pre-shipment discovery)
            delivery-options:read: Get shipping rates and pricing
            tracking:read: Access shipment tracking information
            shipment:read: Read shipment information
            shipment:write: Create and manage shipments
            inventory:read: Read team WMS inventory levels and items
            inventory:write: Mutate team WMS inventory (move stock, update counts)
            fulfillment:read: Read team WMS fulfillment requests
            fulfillment:write: Mutate team WMS fulfillment requests (pack)
            documents:read: Read team business documents, including reports and manifests
            printing:read: Read printers and document print jobs
            printing:write: Create document print and reprint jobs

````