openapi: 3.0.3
x-zally-ignore:
  - 224 # hostname has to follow the functional naming schema, not relevant here
  - 240 # RIO API Design guidelines require lower-kebab-case Enum values
  - 105 # We decided to use the scopes of our upstream API and therefore cannot follow the Zalando naming convention
  - 235 # The value field itself is not suffixed with _at because the EstimatedArrivalAt object has the suffix
info:
  title: Order Exchange Inbound REST API
  version: 0.0.7
  x-api-id: 5473eadc-66bd-400f-9d07-3c36fbca4e33
  x-audience: component-internal
  description: >
    This API allows management of transport orders and shipments.

    [Public Docs](https://docs.transport-order-exchange.rio.cloud)

    ## Taxonomy

    ### Transport order and shipments

    * A `Shipment` (DE: Sendung) is an aggregation of goods to be transported from one origin to one destination at a
      desired time.
    * A `TransportOrder` (DE: Transportauftrag) groups commissioned `Shipment`s together.
      Shipments contained in a transport order do not necessarily need to share a common origin and destination
      (e.g. milk-runs, delivery-runs).
    * `Goods` (DE: Ladungen) are all items that are included in a `Shipment`. Goods can be
      of freight types `CargoMaterial` and `CargoEmpties`. Goods may be further divided into `HandlingUnit`s.
    * A `HandlingUnit` (DE: Ladeeinheit) is a packaging container. Such a container may either contain the actual
      items, further (sub-)packaging, or a combination of both. Some examples are: small load carrier 
      (DE: Kleinladungsträger (KLT)), cardboard box, pallet cage (DE: Gitterbox), EUR-pallet, ...
    * A `HandlingUnit` has some physical properties: for example dimension (width, height, depth), 
      weight, or stacking factor.

    ### Confirmations
    
    * A `Confirmation` (DE: Auftragsbestätigung) is a formal acknowledgement confirmation from the `Contractor` that the
      `TransportOrder` will be executed. It can include details such as the planned means of transport, as well as
      loading and unloading time windows.
    
    ### Parties involved

    * The `OrderingParty` (DE: Auftraggeber) is the person or company who commissions the transport service and is 
      not necessarily equal to the `Shipper` or `Recipient`.
    * The `Shipper` (DE: Verlader) is the party who actually hands over the `Goods` to the `Carrier`.
      In automotive EDIFACT messages this partner is identified as Ship-from.
    * The `Recipient` (DE: Empfänger) is the party who actually receives the `Goods` from the `Carrier`.
      In automotive EDIFACT messages this partner is identified as Ship-to.
    * The `Contractor` (DE: Auftragnehmer) is commissioned by the `OrderingParty` to execute a transport or 
      if necessary, to have it executed by a `Carrier`. The operational coordination of the arrangements is then 
      carried out with the respective sender and `Recipient` of the corresponding transport.
    * The `Carrier` (DE: Frachtführer) undertakes the physical movement of the `Goods`.

    ## Typical use cases

    * A `Contractor` can retrieve a list of `TransportOrder`s to store and work with in e.g. a third party TMS.
      This can be done by retrieving all `TransportOrder`s with the modification date filter
      (`aggregated_modified_after` parameter) set to the time when the last retrieval took place.
      Thereby it is ensured that all updates will be included.
    * A `Contractor` can confirm a `TransportOrder` by sending a `Confirmation`. This confirms all `Shipment`s in this 
      `TransportOrder`. 
    * A `Contractor` can submit additional `ShipmentConfirmation` data such as licence plate number of the vehicle
      and/or expected loading and unloading times.
    
    * A typical `Contractor` workflow would thus be 
        - Fetch all potentially relevant transport orders filtering by modification date (`aggregated_modified_after`) 
          to only get those orders that were recently modified and setting the `embed=(shipments)` query parameter
        - Select all relevant transport orders
        - Confirm selected transport orders via API call to `/confirmed-transport-orders/{transport-order-id}`
        - Update shipment confirmations by posting to `/transport-orders/{transport-order-id}/shipments/{shipment-id}/confirmations`

  contact:
    name: RIO Team Transport One
    url: https://rio.cloud/
    email: rio_team_transport_one@rio.cloud

servers:
  - url: https://api.transport-order-exchange.rio.cloud

tags:
  - name: transport-orders
    description: Endpoints for receiving, creating and manipulating transport orders
  - name: confirmations
    description: Endpoints to confirm a transport order or shipments individually
  - name: transport-status
    description: Endpoints to update the transport status of a shipment

paths:
  /transport-orders:
    get:
      summary: Read transport orders
      tags:
        - transport-orders
      security:
        - oauth2:
            - transport-order.read
            - logistics.freight-forwarder
      parameters:
        - name: direction
          description: >
            Filter transport orders to get only incoming transport orders for which you are the contractor
            or outgoing transport orders for which you are the ordering party.
          in: query
          schema:
            type: string
            x-extensible-enum:
              - incoming
              - outgoing
            example: incoming
          required: false
        - name: loading_start_after
          description: >
            Setting this parameter to a date and time will filter transport orders before they are returned.
            Only those with a loading time window starting at or after the given date and time will be returned.
          in: query
          schema:
            type: string
            format: date-time
            example: 2022-02-02T11:22:33.444Z
          required: false
        - name: aggregated_modified_after
          in: query
          description: >
            Setting this parameter to a date and time will filter transport orders before they are returned.
            Only those transport orders with an `aggregated_modified_at` after the given date and time,
            where "transport order" in this case encompasses both the parent transport order and all its
            constituting shipments, will be returned.
          schema:
            type: string
            format: date-time
            example: 2022-02-02T11:22:33.444Z
          required: false
        - name: embed
          in: query
          schema:
            type: string
            example: embed=(shipments)
            description: >
              When "shipments" embed parameter is set, return list of shipments that are part of this transport order.
          required: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    oneOf:
                      - $ref: "#/components/schemas/TransportOrders"
                      - $ref: "#/components/schemas/TransportOrdersWithEmbedding"
                required:
                  - items
        default:
          description: All other cases (error)
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"

  /transport-orders/{transport-order-id}:
    get:
      summary: Returns the transport order for the given transport-order-id
      tags:
        - transport-orders
      security:
        - oauth2:
            - transport-order-exchange.read
            - transport-order.read
            - logistics.freight-forwarder
      parameters:
        - $ref: "#/components/parameters/transport-order-id"
        - name: embed
          in: query
          schema:
            type: string
            example: embed=(shipments)
            description: >
              When `shipments` embed parameter is set, return list of shipments that are part of this transport order.
          required: false
      responses:
        200:
          description: OK
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/TransportOrder"
                  - $ref: "#/components/schemas/TransportOrderWithEmbedding"
        default:
          description: All other cases (error)
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"

  /transport-orders/{transport-order-id}/shipments/{shipment-id}/confirmations:
    post:
      tags:
        - confirmations
      summary: Creates a confirmation for a shipment.
      description: >
        This endpoint is used to confirm a shipment as described in VDA 4933 T3. Everytime a confirmation is send, the
        previously sent confirmation is overwritten. Make sure that you include all necessary information in every request.
      security:
        - oauth2:
            - transport-order.confirm
      parameters:
        - name: transport-order-id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: shipment-id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ShipmentConfirmation"
      responses:
        200:
          description: OK
        default:
          description: All other cases (error)
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"

  /transport-orders/{transport-order-id}/shipments/{shipment-id}/transport-status:
    post:
      summary: Creates a transport status for a shipment.
      tags:
        - transport-status
      security:
        - oauth2:
            - transport-status.write
            - logistics.freight-forwarder
      parameters:
        - name: transport-order-id
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: shipment-id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TransportStatus'
      responses:
        202:
          description: Request accepted
        default:
          description: All other cases (error)
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"

  /confirmed-transport-orders/{transport-order-id}:
    put:
      summary: Confirm a transport order. This endpoint is deprecated and will be removed on 01.08.2025
      deprecated: true
      tags:
        - confirmations
      security:
        - oauth2:
            - transport-order.confirm
            - logistics.freight-forwarder
      parameters:
        - $ref: "#/components/parameters/ifMatchHeader"
        - name: transport-order-id
          description: The id of the confirmed transport order. This is the same as the id of the transport order.
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ConfirmedTransportOrder"
      responses:
        200:
          description: Contractor confirmation created or updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ConfirmedTransportOrder"
        default:
          description: All other cases (error)
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/ProblemWithFailedConfirmations"

components:
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://auth.iam.rio.cloud/oauth/token
          scopes:
            transport-order.read: Read transport orders (Deprecated, currently still required for connection to WebTMS)
            transport-order.confirm: Confirm transport orders (Deprecated, currently still required for connection to WebTMS)
            logistics.freight-forwarder: Scope for contractor clients (Deprecated, currently still required for connection to WebTMS)
            transport-order-exchange.read: Read transport orders
  schemas:
    TransportStatus:
      type: object
      properties:
        message_type:
          type: object
          description: The type and stage of the transport status.
          oneOf:
            - $ref: '#/components/schemas/TypeLeftLoadingLocation'
            - $ref: '#/components/schemas/TypeLocation'
            - $ref: '#/components/schemas/TypeArrivedAtCrossDock'
            - $ref: '#/components/schemas/TypeLeftCrossDock'
            - $ref: '#/components/schemas/TypeArrivedAtUnloadingLocation'
            - $ref: '#/components/schemas/TypeLeftUnloadingLocation'
          discriminator:
            propertyName: type
            mapping:
              left-loading-location: "#/components/schemas/TypeLeftLoadingLocation"
              location: "#/components/schemas/TypeLocation"
              arrived-at-cross-dock: "#/components/schemas/TypeArrivedAtCrossDock"
              left-cross-dock: "#/components/schemas/TypeLeftCrossDock"
              arrived-at-unloading-location: "#/components/schemas/TypeArrivedAtUnloadingLocation"
              left-unloading-location: "#/components/schemas/TypeLeftUnloadingLocation"
        estimated_arrival_at:
          type: string
          description: |
            Estimated time of arrival (ETA) of the shipment at its final destination, i.e. at the end of the last
            transport leg.
          format: date-time
        current_transport_leg:
          $ref: '#/components/schemas/CurrentTransportLeg'
        means_of_transport:
          type: object
          description: >
            The means of transport that is used to perform the transport order.
          properties:
            license_plate_number:
              type: string
            license_plate_country_code:
              type: string
            fuel_type:
              type: string
              description: Fuel type of the vehicle
              x-extensible-enum:
                - diesel
                - diesel-and-electric
                - petrol
                - petrol-and-electric
                - electric
                - liquid-gas-propane
          required:
            - license_plate_number
        location:
          $ref: '#/components/schemas/Coordinates'
        data_collected_at:
          type: string
          description: "The timestamp when the data was collected, formatted as ISO 8601."
          format: date-time
        bordero_number:
          type: string
          description: "The reference identifier for the trucks freight list."
        shipment_number:
          type: string
          description: Reference to the shipment ("Sendungsnummer")
        access_code_at_unloading:
          type: string
          description: Access code for unloading assigned by the goods recipient (ZeitfensterId, Time Window ID).
      required:
        - message_type
        - location
        - means_of_transport
        - data_collected_at
    CurrentTransportLeg:
      type: object
      description: |
        Information on the current transport leg. 
        Please specify geo_location_of_arrival or location_of_arrival or both.
      properties:
        departed_at:
          type: string
          description: Departure date & time of the current transport leg.
          format: date-time
        geo_location_of_arrival:
          $ref: '#/components/schemas/Coordinates'
        location_of_arrival:
          $ref: '#/components/schemas/LocationOfArrival'
        estimated_arrival_at:
          type: string
          description: Estimated arrival date & time at the end of the current transport leg
          format: date-time
      anyOf:
        - required:
            - geo_location_of_arrival
        - required:
            - location_of_arrival

    LocationOfArrival:
      type: object
      description: Location of arrival. Either duns or supplier_code or address must be provided.
      properties:
        duns:
          $ref: "#/components/schemas/Duns"
        supplier_code:
          type: string
          description: Supplier code of the site
        address:
          $ref: '#/components/schemas/TransportStatusAddress'
      anyOf:
        - required:
            - duns
        - required:
            - supplier_code
        - required:
            - address

    TypeLeftLoadingLocation:
      type: object
      description: The loading location was left indicating the start of the transport
      properties:
        type:
          type: string
          description: The type of the message
          enum:
            - left-loading-location
        stage:
          type: string
          description: The stage of the transport
          enum:
            - direct
            - preliminary-leg
      required:
        - type
        - stage

    TypeLocation:
      type: object
      description: A regular location report, no state transition between stages
      properties:
        type:
          type: string
          description: The type of the message
          enum:
            - location
        stage:
          type: string
          description: The stage of the transport
          enum:
            - direct
            - preliminary-leg
            - main-leg
            - unloading-location
            - at-arrival
      required:
        - type
        - stage

    TypeArrivedAtCrossDock:
      type: object
      description: Arrival at a cross dock
      properties:
        type:
          type: string
          description: The type of the message
          enum:
            - arrived-at-cross-dock
        stage:
          type: string
          description: The stage of the transport
          enum:
            - preliminary-leg
      required:
        - type
        - stage

    TypeLeftCrossDock:
      type: object
      description: The cross dock was left
      properties:
        type:
          type: string
          description: The type of the message
          enum:
            - left-cross-dock
        stage:
          type: string
          description: The stage of the transport
          enum:
            - main-leg
      required:
        - type
        - stage

    TypeArrivedAtUnloadingLocation:
      type: object
      description: Arrival at the unloading location
      properties:
        type:
          type: string
          description: The type of the message
          enum:
            - arrived-at-unloading-location
        stage:
          type: string
          description: The stage of the transport
          enum:
            - unloading-location
            - at-arrival
      required:
        - type
        - stage

    TypeLeftUnloadingLocation:
      type: object
      description: The unloading location was left indicating the end of the transport
      properties:
        type:
          type: string
          description: The type of the message
          enum:
            - left-unloading-location
        stage:
          type: string
          description: The stage of the transport
          enum:
            - at-arrival
            - completion
      required:
        - type
        - stage

    ConfirmedTransportOrder:
      description: >
        Confirmation of a transport order by the contractor.
      type: object
      properties:
        id:
          type: string
          description: >
            The id of the confirmed transport order. This is the same as the id of the transport order.
        status:
          type: string
          x-extensible-enum:
            - confirmed
          example: confirmed
      required:
        - id
        - status

    TransportOrder:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: >
            The RIO internal identifier of the transport order.
          example: 548d8587-047c-40a1-98d0-5d3fdcdbe9af
        contractor:
          description: >
            The contractor (DE: Auftragnehmer) of this transport order.
          allOf:
            - $ref: "#/components/schemas/Party"
        ordering_party:
          description: >
            The ordering party (DE: Auftraggeber) of this transport order.
          allOf:
            - $ref: "#/components/schemas/Party"
        ordering_party_transport_order_id:
          type: string
          description: >
            Transport order identifier in the external system of the ordering party.
          example: AGK2387200
        process_indicator:
          type: string
          description: |
            The process indicator (DE: Prozesskennzeichen) defines the contractually specified type of transport.
            It can be one of:
            - `ltl`: Less than truck load (DE: Teilladung)
            - `ftl`: Full truck load (DE: Komplett-LKW)
            - `kep`: Parcel service (DE: Paketdienste)
            Relevant for billing.
          x-extensible-enum:
            - ftl
            - ltl
            - kep
          example: ltl
        priority:
          type: string
          description: |
            Indicates the priority of the transport order.
            Options are:
            - `regular`: Regular route
            - `urgent`: Special route (DE: Sonderfahrt).
          default: regular
          x-extensible-enum:
            - regular
            - urgent
          example: regular
        proposed_vehicle_type:
          type: string
          description: >
            Proposed vehicle type for the forwarder to use. Relevant for billing.
          x-extensible-enum:
            - passenger-car
            - van
            - light-truck
            - medium-truck
          example: van
        confirmation_by_contractor:
          $ref: "#/components/schemas/Confirmation"
        etag:
          type: string
          description: Version of the order. Used for optimistic locking. See
            [Zalando guidelines](https://opensource.zalando.com/restful-api-guidelines/#etag-in-result-entities)
          readOnly: true
          example: 3
        created_at:
          type: string
          format: date-time
          readOnly: true
          example: 2022-03-08T07:58:10.123Z
        modified_at:
          type: string
          format: date-time
          description: >
            Datetime of the last modification of the transport order without considering its shipments.
          readOnly: true
          example: 2022-03-08T07:58:10.123Z
        aggregated_modified_at:
          type: string
          format: date-time
          description: >
            Datetime of the last modification of the transport order including its shipments.
          readOnly: true
          example: 2022-03-08T07:58:10.123Z
      required:
        - id
        - contractor
        - ordering_party
        - etag
        - created_at
        - modified_at
        - aggregated_modified_at

    TransportOrders:
      type: array
      items:
        $ref: "#/components/schemas/TransportOrder"

    TransportOrderWithEmbedding:
      allOf:
        - $ref: "#/components/schemas/TransportOrder"
        - properties:
            _embedded:
              type: object
              properties:
                shipments:
                  $ref: "#/components/schemas/Shipments"
          required:
            - _embedded

    TransportOrdersWithEmbedding:
      type: array
      items:
        $ref: "#/components/schemas/TransportOrderWithEmbedding"

    Shipment:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: The RIO internal identifier of the shipment.
          example: 548d8587-047c-40a1-98d0-5d3fdcdbe9af
        ordering_party_shipment_id:
          type: string
          description: Shipment identifier in the external system of the ordering party.
          example: FzaZNSeDCkMUfK65kbJa
        supplier:
          $ref: "#/components/schemas/Party"
        loading:
          $ref: "#/components/schemas/Loading"
        unloading:
          $ref: "#/components/schemas/Unloading"
        goods:
          description: >
            The goods that are contained in a shipment. Can be:
            - CargoMaterial (DE: Vollgut)
            - CargoEmpties (DE: Leergut)
          oneOf:
            - $ref: "#/components/schemas/CargoMaterial"
            - $ref: "#/components/schemas/CargoEmpties"
          discriminator:
            propertyName: type
            mapping:
              cargo-material: "#/components/schemas/CargoMaterial"
              cargo-empties: "#/components/schemas/CargoEmpties"
        cancellation:
          $ref: "#/components/schemas/Cancellation"
        confirmation:
          $ref: "#/components/schemas/ShipmentConfirmation"
      required:
        - id
        - loading
        - unloading
        - goods

    Shipments:
      type: array
      description: >
        The shipments ordered together in a transport order.
      items:
        $ref: "#/components/schemas/Shipment"

    Loading:
      type: object
      properties:
        time_window:
          $ref: "#/components/schemas/TimeWindow"
        access_code:
          $ref: "#/components/schemas/AccessCode"
        note:
          type: string
          example: Please call the contact before entering the plant.
        shipper:
          $ref: "#/components/schemas/Party"
        place_of_loading:
          type: string
          description: >
            The place if loading (DE: Beladestelle)
          example: Plant Munich, ramp 5
        location:
          $ref: "#/components/schemas/Location"
      required:
        - time_window
        - shipper
        - location

    Unloading:
      type: object
      properties:
        time_window:
          $ref: "#/components/schemas/TimeWindow"
        access_code:
          $ref: "#/components/schemas/AccessCode"
        note:
          type: string
          example: Please call the contact before entering the plant.
        recipient:
          $ref: "#/components/schemas/Party"
        place_of_discharge:
          type: string
          description: >
            The place of discharge (DE: Abladestelle)
          example: Plant Munich, ramp 5
        location:
          $ref: "#/components/schemas/Location"
      required:
        - recipient
        - location

    AccessCode:
      type: string
      description: >
        Access code (DE: Zugangscode) for the access to the unloading location (door opener).
        If the data is from WebTMS this is most likely the LKWControl time window id (DE: LKWControl Zeitfenster-ID).
      example: "ABCDEF"

    TimeWindow:
      type: object
      description: >
        The time window for loading and unloading the goods.
      properties:
        start_at:
          type: string
          format: date-time
          example: 2022-03-08T07:58:10.123Z
        finish_at:
          type: string
          format: date-time
          example: 2022-03-08T07:58:10.123Z
      required:
        - start_at
        - finish_at

    Party:
      type: object
      description: A party involved in the transport order.
      properties:
        name:
          type: string
          description: The name of the party.
          example: Carter LLC
        address:
          $ref: "#/components/schemas/Address"
        contact:
          $ref: "#/components/schemas/Contact"
        duns:
          $ref: "#/components/schemas/Duns"
        plant_code:
          type: string
          description: >
            The plant code (DE: Werksnummer) of the party.
          example: 12
        supplier_code:
          type: string
          description: >
            The supplier code (DE: Lieferantennummer, Lokale Lieferentennummer(LoLi)) of the party.
          example: 9999999
        account_id:
          type: string
          description: >
            The RIO account id of the contractor or freight forwarder.
          example: 67f99592-3ee8-4214-9110-df6672eeadee
      required:
        - name

    Contact:
      type: object
      properties:
        name:
          type: string
          example: Gordon Runolfsson
        email:
          type: string
          example: gordon.runolfsson@dickinson.com
        phone:
          type: string
          example: 1-918-238-1284

    Location:
      type: object
      properties:
        address:
          $ref: "#/components/schemas/Address"
        coordinates:
          $ref: "#/components/schemas/Coordinates"
        name:
          type: string
          example: Paketdepot Süd
          description: >
            Human readable name for the location.
      minProperties: 1

    Address:
      type: object
      properties:
        street:
          type: string
          example: Oskar-Schlemmer-Str. 18-21
        postal_code:
          type: string
          example: 80807
        city:
          type: string
          example: Munich
        country:
          type: string
          example: Germany
      required:
        - street
        - postal_code
        - city
        - country

    TransportStatusAddress:
      type: object
      description: A postal address
      properties:
        street:
          type: string
          description: Street name and number
        postal_code:
          type: string
          description: Postal code
        city:
          type: string
          description: City
        country:
          type: string
          description: The [ISO 3166-1 alpha-2](https://www.iso.org/iso-3166-country-codes.html) country code.
          maxLength: 2
          minLength: 2
          example: DE
      required:
        - street
        - postal_code
        - city
        - country

    Coordinates:
      type: object
      properties:
        latitude:
          type: number
          format: double
          description: >
            latitude (north-south position) in decimal degrees (-90 ... +90)
          example: 51.935317
        longitude:
          type: number
          format: double
          description: >
            longitude (east-west position) in decimal degrees (-180 ... +180)
          example: 10.145256
      required:
        - latitude
        - longitude

    Confirmation:
      description: >
        Confirmation of a transport order by the contractor.
      type: object
      properties:
        status:
          type: string
          x-extensible-enum:
            - confirmed
          example: confirmed
      required:
        - status

    Cancellation:
      description: >
        Cancellation of a shipment.
      type: object
      properties:
        status:
          type: string
          x-extensible-enum:
            - cancelled
          example: cancelled
      required:
        - status

    Goods:
      type: object
      properties:
        type:
          type: string
          description: |
            Currently there are two types of goods:
            - CargoMaterial (DE: Vollgut) with type `cargo-material`
            - CargoEmpties (DE: Leergut) with type `cargo-empties`
          x-extensible-enum:
            - cargo-material
            - cargo-empties
          example: cargo-material
      required:
        - type

    CargoMaterial:
      description: >
        CargoMaterial (DE: Vollgut)
      allOf:
        - $ref: "#/components/schemas/Goods"
        - type: object
          properties:
            handling_units:
              type: array
              minItems: 1
              items:
                $ref: "#/components/schemas/HandlingUnit"
          required:
            - handling_units

    CargoEmpties:
      description: >
        CargoEmpties (DE: Leergut)
      allOf:
        - $ref: "#/components/schemas/Goods"
        - type: object
          properties:
            handling_units:
              type: array
              minItems: 1
              items:
                $ref: "#/components/schemas/HandlingUnitEmpties"
          required:
            - handling_units

    HandlingUnit:
      type: object
      description: |
        A HandlingUnit is a unit of goods that combines the characteristics of load units and packages.
        On `CargoMaterial` level it represents a load unit where the `packaging_code` could be e.g. Euro Pallet.
        
        If the `HandlingUnit` is part of another `HandlingUnits` content it represents a package where the
        `packaging_code` could be one of packaging materials like a plastic container or a carton of a specific size.
      properties:
        type:
          type: string
          x-extensible-enum:
            - handling-unit
          example: handling-unit
        packaging_code:
          $ref: "#/components/schemas/PackagingCode"
        quantity:
          type: integer
          format: int32
          minimum: 1
          maximum: 999
          description: |
            The number of handling units that are exactly identical in their contents. For non-identical handling units
            with e.g. different quantities of articles, separate handling units need to be defined.
            
            *Note:* the restriction of 999 is valid for outer and intermediate handling units, when using 
            hierarchical packaging. For inner handling units or in the non hierarchical case up to 999999 
            handling units are allowed.
        stacking_factor:
          type: integer
          format: int32
          minimum: 1
          maximum: 99
          description: >
            The maximum stackability (DE: Maximaler Stapelfaktor) for transport purposes. Describes how many layers of
            the handling units can be stacked on top of each other.
            A value of 1 describes 1 layer, i.e., a non-stackable handling unit.
        dimension:
          $ref: "#/components/schemas/Dimension"
        weight:
          $ref: "#/components/schemas/Weight"
        auxiliary_packagings:
          type: array
          items:
            $ref: "#/components/schemas/AuxiliaryPackaging"
        contents:
          type: array
          description: >
            The contents of this handling unit. The handling unit can contain both handling units
            describing the inner packaging or articles.
          items:
            anyOf:
              - $ref: "#/components/schemas/HandlingUnit"
              - $ref: "#/components/schemas/Article"
          minItems: 1
      additionalProperties: true
      required:
        - type
        - packaging_code
        - quantity
        - contents

    HandlingUnitEmpties:
      type: object
      description: >
        (DE: Leergut) A `HandlingUnit` is a unit of goods that combines the characteristics of load units and packages.
        On `CargoEmpties` level it represents a load unit where the `packaging_code` could be e.g. euro pallet.
        
        If the `HandlingUnit` is part of another `HandlingUnit`s content it represents a package where
        the `packaging_code` could be one of packaging materials like a plastic container or a carton
        of a specific size. The `HandlingUnit` for empties differs from the `HandlingUnit` for materials by
        not having a `net_weight` and `auxiliary_packaging`.
      properties:
        packaging_code:
          $ref: "#/components/schemas/PackagingCode"
        quantity:
          type: integer
          format: int32
          minimum: 1
          maximum: 9999
          description: >
            Number (DE: Menge) of handling units that are exactly identical in their contents.
        stacking_factor:
          type: integer
          format: int32
          minimum: 1
          maximum: 999999999
          description: >
            The maximum stackability (DE: Maximaler Stapelfaktor) for transport purposes. Describes how many layers of
            the handling units can be stacked on top of each other.
            A value of 1 describes 1 layer, i.e., a non-stackable handling unit.
        dimension:
          $ref: "#/components/schemas/DimensionEmpties"
        gross_weight_kg:
          type: number
          format: double
          minimum: 0
          maximum: 999999999
          description: >
            Gross weight (DE: Bruttogewicht) in kg including packaging
        contents:
          type: array
          items:
            $ref: "#/components/schemas/ArticleEmpties"
          minItems: 1
      required:
        - packaging_code
        - quantity
        - contents

    AuxiliaryPackaging:
      type: object
      properties:
        quantity:
          type: integer
          format: int32
          minimum: 1
          maximum: 99999999
        packaging_code:
          $ref: "#/components/schemas/PackagingCode"
      required:
        - packaging_code
        - quantity

    Article:
      type: object
      properties:
        type:
          type: string
          x-extensible-enum:
            - article
          example: article
        id:
          type: string
          description: >
            The line item identifier (DE: Produktnummer, Materialnummer) of the article.
          minLength: 1
          maxLength: 35
          example: tV3jy4dWGIg0RWULveLr
        quantity:
          $ref: "#/components/schemas/ArticleQuantity"
        net_explosive_mass_kg:
          type: number
          format: double
          description: >
            Net explosive mass (DE: Nettoexplosivmasse) of the part in kg
          minimum: 0
        dangerous_goods_information:
          $ref: "#/components/schemas/DangerousGoodsInformation"
        internal_place_of_destination:
          $ref: "#/components/schemas/InternalPlaceOfDestination"
        order_reference:
          description: >
            Order document identifier (DE: Eindeutiger Identifier der Bestellung) for that article
          type: string
        delivery_instruction_reference:
          description: >
            Reference to the delivery call-off (DE: Lieferabruf)
          type: string
        country_of_origin:
          type: object
          description: >
            Country of origin (DE: Ursprungsland) and duty regime (DE: Zollregime)
          properties:
            country_code:
              type: string
              description: |
                County of origin (DE: Ursprungsland)
                Country code in the ISO 3361-1 ALPHA-2 format
              example: DE
            dutiable_goods:
              type: boolean
              description: >
                Dutiable goods indicator (DE: Zollgutindikator)
              example: true
          required:
            - dutiable_goods
      additionalProperties: true
      required:
        - type
        - id
        - quantity

    ArticleEmpties:
      type: object
      properties:
        id:
          type: string
          description: ID for packaging item
          minLength: 1
          maxLength: 7
          example: 006280
        quantity:
          type: integer
          format: int32
          minimum: 1
          maximum: 9999
        dangerous_goods_information:
          $ref: "#/components/schemas/DangerousGoodsInformation"
      additionalProperties: true
      required:
        - id
        - quantity

    ArticleQuantity:
      type: object
      description: >
        The quantity of the articles contained in the package
      oneOf:
        - $ref: "#/components/schemas/ArticleQuantityInteger"
        - $ref: "#/components/schemas/ArticleQuantityDecimal"

    ArticleQuantityInteger:
      type: object
      description: |
        Article quantities with an integer number value, e.g. 200 pieces.
        The possible types of integer numbers are:
        - piece
        - leaf
        - drum
        - pair
        - roll
        - set
      properties:
        type:
          type: string
          x-extensible-enum:
            - piece
            - leaf
            - drum
            - pair
            - roll
            - set
          example: piece
        value:
          type: integer
          format: int32
          minimum: 1
          maximum: 99999999
      required:
        - type
        - value

    ArticleQuantityDecimal:
      type: object
      description: |
        Article quantities with a decimal number value, e.g. 18.5 kg.
        The possible types of decimal numbers are:
        - meter
        - square-meter
        - cubic-meter
        - kilogram
      properties:
        type:
          type: string
          x-extensible-enum:
            - meter
            - square-meter
            - cubic-meter
            - kilogram
          example: kilogram
        value:
          type: number
          format: double
          minimum: 0.0
          maximum: 999999.9
      required:
        - type
        - value

    Dimension:
      type: object
      properties:
        length_m:
          type: number
          format: double
          minimum: 0
          maximum: 99999
          description: >
            Length dimension of the package (DE: Länge der Verpackung) in meters
        width_m:
          type: number
          format: double
          minimum: 0
          maximum: 99999
          description: >
            Width dimension of the package (DE: Breite der Verpackung) in meters
        height_m:
          type: number
          format: double
          minimum: 0
          maximum: 99999
          description: >
            Height dimension of the package (DE: Höhe der Verpackung) in meters

    DimensionEmpties:
      type: object
      properties:
        length_m:
          type: number
          format: double
          minimum: 0
          maximum: 10
          exclusiveMaximum: true
          description: Length in m
        width_m:
          type: number
          format: double
          minimum: 0
          maximum: 10
          exclusiveMaximum: true
          description: Width in m
        height_m:
          type: number
          format: double
          minimum: 0
          maximum: 10
          exclusiveMaximum: true
          description: Height in m
        volume_m3:
          type: number
          format: double
          minimum: 0
          maximum: 999999999
          description: Volume in cubic metre

    Weight:
      type: object
      properties:
        gross_weight_kg:
          type: number
          format: double
          minimum: 0
          maximum: 9999999
          description: >
            Gross weight (DE: Bruttogewicht) in kg including packaging
        net_weight_kg:
          type: number
          format: double
          minimum: 0
          maximum: 9999999
          description: >
            Net weight (DE: Nettogewicht) in kg excluding packaging

    DangerousGoodsInformation:
      type: object
      properties:
        undg:
          type: string
          minLength: 4
          maxLength: 4
          pattern: "^\\d{4}$"
          description: >
            The United Nations Dangerous Goods (DE: Gefahrgut-Identifikation der Vereinten Nationen, UNDG) identifier
          example: 3507
        description:
          type: string
          description: >
            Dangerous goods description (DE: Gefahrgutbeschreibung)
          minLength: 1
          maxLength: 256
          example: Uranium hexafluoride
        exception_regulation:
          type: string
          description: >
            Exception regulation (DE: Ausnahmeregelung)
          minLength: 1
          maxLength: 256
          example: It's safe, I promise
      required:
        - undg

    InternalPlaceOfDestination:
      type: object
      description: >
        Internal place of destination (DE: Interner Bestimmungsort)
      properties:
        id:
          type: string
          minLength: 1
          maxLength: 5
          description: >
            Identifier of the internal place of destination. Usually has a length 1 to 5 characters.
          example: G0004
        name:
          type: string
          description: >
            Name of the internal place of destination
          minLength: 1
          maxLength: 256
      required:
        - id

    PackagingCode:
      type: string
      minLength: 1
      maxLength: 7
      description: >
        The packaging type description code (DE: Art der Verpackung, Packmittelcode) for used packaging material
      example: 0000PAL

    Duns:
      type: string
      pattern: "^\\d{9}$"
      description: >
        DUNS number assigned by Dun & Bradstreet
      example: "123456789"

    OccurredAt:
      type: object
      properties:
        occurred_at:
          type: string
          format: date-time
          description: >
            ISO 8601 timestamp (UTC) when the event was measured on the device
          example: '2019-08-09T10:12:46.057Z'

    Problem:
      type: object
      properties:
        type:
          type: string
          format: uri
          description: |
            An absolute URI that identifies the problem type.  When dereferenced,
            it SHOULD provide human-readable documentation for the problem type
            (e.g., using HTML).
          default: 'about:blank'
          example: 'https://zalando.github.io/problem/constraint-violation'
        title:
          type: string
          description: |
            A short, summary of the problem type. Written in english and readable
            for engineers (usually not suited for non technical stakeholders and
            not localized); example: Service unavailable
        status:
          type: integer
          format: int32
          description: |
            The HTTP status code generated by the origin server for this occurrence
            of the problem.
          minimum: 100
          maximum: 600
          exclusiveMaximum: true
          example: 503
        detail:
          type: string
          description: |
            A human readable explanation specific to this occurrence of the
            problem.
          example: Connection to database timed out
        instance:
          type: string
          format: uri
          description: |
            An absolute URI that identifies the specific occurrence of the problem.
            It may or may not yield further information if dereferenced.

    ProblemWithFailedConfirmations:
      allOf:
        - $ref: "#/components/schemas/Problem"
        - type: object
          properties:
            failed_confirmations:
              type: array
              items:
                type: string
    ShipmentConfirmation:
      description: Confirmation of a shipment by the carrier.
      type: object
      properties:
        means_of_transport:
          type: object
          description: >
            The means of transport that is used to perform the shipment.
          properties:
            license_plate:
              type: string
              description: >
                License plate number (DE: Kennzeichen) of the asset.
              example: "M RI 0284"
            country_code:
              type: string
              description: The 2-letter ISO country in which the asset is registered.
              example: "DE"
        loading:
          type: object
          properties:
            access_code:
              type: string
              example: "ABCDEF"
            time_window:
              $ref: "#/components/schemas/ShipmentConfirmationTimeWindow"
        unloading:
          type: object
          properties:
            access_code:
              type: string
              example: "ABCDEF"
            time_window:
              $ref: "#/components/schemas/ShipmentConfirmationTimeWindow"

    ShipmentConfirmationTimeWindow:
      type: object
      properties:
        time_from:
          type: string
          format: date-time
          example: 2022-03-08T07:58:10.123Z
        time_to:
          type: string
          format: date-time
          example: 2022-03-08T07:58:10.123Z
      required:
        - time_from
        - time_to

  parameters:
    transport-order-id:
      in: path
      name: transport-order-id
      description: The id of the `TransportOrder` for which to retrieve or update data.
      required: true
      schema:
        type: string
        format: uuid
    shipment-id:
      in: path
      name: shipment-id
      description: The id of the `Shipment` for which to retrieve or update data.
      required: true
      schema:
        type: string
        format: uuid
    ifMatchHeader:
      name: If-Match
      in: header
      description: >
        The RFC7232 `If-Match` header field in a request requires the server to
        only operate on the resource that matches at least one of the provided
        entity-tags. This allows clients express a precondition that prevent
        the method from being applied if there have been any changes to the
        resource (see [RFC 7232 Section
        3.1](https://tools.ietf.org/html/rfc7232#section-3.1).
        
        Also see [the Zalando Guidelines](https://opensource.zalando.com/restful-api-guidelines/#182) 
        on how to use this header.
      schema:
        type: string
        example: "3"
      required: true
    ifNoneMatch:
      name: If-None-Match
      in: header
      description: >
        The RFC7232 `If-None-Match` header field in a request requires the server
        to only operate on the resource if it does not match any of the provided
        entity-tags. If the provided entity-tag is `*`, it is required that the
        resource does not exist at all (see [RFC 7232 Section
        3.2](https://tools.ietf.org/html/rfc7232#section-3.2).
      schema:
        type: string
        example: "7da7a728-f910-11e6-942a-68f728c1ba70"
      required: false
