# OpenAPI 3.1 document. Validated with openapi-spec-validator (3.1) and rendered with Scalar.
# Note: VS Code's bundled OpenAPI validator targets 3.0 and may show false warnings for valid
# 3.1 features (type arrays like [string, null], schema `examples`, `if/then/else`, `info.summary`).
openapi: 3.1.0
info:
  title: CHI-Cargo Business Partner API
  version: "1.0.0"
  summary: Message-oriented air cargo integration API for the CHI Cargo warehouse (Chicago WMS).
  description: |
    The **CHI-Cargo Business Partner API v1** (internally referred to as the *Generic API*) is a
    message-oriented integration interface in front of the CHI Cargo warehouse system
    (Chicago WMS). It is purpose-built for enterprise integration teams that work with large,
    message-based payloads coming from TMS, forwarding, customs or EDI systems
    (for example via Lobster Data or classic EDI converters).

    Unlike a classical resource-oriented REST API, this interface exposes a **single endpoint**
    (`POST /v1`) that accepts one business message describing many objects and relationships at once.
    A single message can, for example, pre-advise one export MAWB together with hundreds of HAWBs and
    attach them all in one call.

    ### Design principles
    - **One endpoint, one message** — `POST /v1` accepts a `data` area (business objects) and an
      `actions` area (relationships / processing requests).
    - **Create-or-update (idempotent effects)** — objects are matched by their natural keys
      (`mawb_number`, `hawb_number`, `manifest_number`). Re-sending a corrected message updates the
      existing object; only transmitted fields change.
    - **Broad, optional model** — almost every field is optional at the schema level because different
      business processes require different meaningful subsets. The use-case documentation describes
      which fields matter for each process.

    > Most fields are optional **globally**, but specific business use cases require meaningful subsets.
    > Always model the documentation use case, not the raw schema.

    For the full narrative documentation, use cases, sequence diagrams and status-message reference,
    see the accompanying documentation site.
  contact:
    name: CHI Cargo — Enterprise Integration
    email: enterprise-integration@chi-cargo.com
  x-logo:
    url: assets/chi-logo.png
    altText: CHI Cargo

servers:
  - url: https://api.production.chi-deutschland.cloud 
    description: Production
  - url: https://api.staging.chi-deutschland.cloud 
    description: Staging (used for onboarding and testing)

security:
  - ApiKeyAuth: []

tags:
  - name: Messages
    description: The single message endpoint used for all business processes.

paths:
  /v1:
    post:
      tags:
        - Messages
      operationId: postMessage
      summary: Submit a business message
      description: |
        Submits one business message. The message body contains a `data` area (business objects to
        create or update) and/or an `actions` area (relationships and processing requests).

        The call is processed asynchronously: a syntactically valid, schema-conformant message is
        accepted with **202 Accepted** and a `id` (process id) that can be used to correlate the
        request with later status messages.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/GenericApiMessage"
            examples:
              export_shipment_pre_advice:
                summary: Export shipment pre-advice (outbound shipments)
                value:
                  data:
                    outbound_shipments:
                      - hawb_number: "FRA10099001"
                        origin: "FRA"
                        destination: "JFK"
                        pieces: 4
                        weight: 612.0
                        consigner: "ACME INSTRUMENTS GMBH"
                        consignee: "ACME US INC"
                        content: "Measuring instruments"
                        prior_party_secured: false
                        additional_data:
                          cargowise_shipment_id: "S00012345"
              export_mawb_with_attach:
                summary: Export MAWB creation + attach HAWBs
                value:
                  data:
                    outbound_masters:
                      - mawb_number: "02012345675"
                        consolidation_type: "consol"
                        origin: "FRA"
                        destination: "JFK"
                        pieces: 11
                        weight: 1180.5
                    outbound_shipments:
                      - hawb_number: "FRA10099001"
                        pieces: 4
                        weight: 612.0
                      - hawb_number: "FRA10099002"
                        pieces: 7
                        weight: 568.5
                  actions:
                    attach_shipment:
                      - process_type: "outbound"
                        hawb_number: "FRA10099001"
                        mawb_number: "02012345675"
                      - process_type: "outbound"
                        hawb_number: "FRA10099002"
                        mawb_number: "02012345675"
              local_export_label_link:
                summary: Local export without HAWB + later labeling/linking
                value:
                  data:
                    outbound_shipments:
                      - alt_refs: "WH-REF-77001"
                        origin: "FRA"
                        destination: "ORD"
                        pieces: 2
                        weight: 95.0
                  actions:
                    add_work_item:
                      - process_type: "outbound"
                        hawb_number: "FRA10099050"
                        workable: "label_hawb"
                        instructions: "Label and link warehouse pre-records to this HAWB."
                        attach_shipments:
                          - alt_refs: "WH-REF-77001"
              import_mawb_pre_advice:
                summary: Import MAWB / shipment pre-advice + attach
                value:
                  data:
                    inbound_masters:
                      - mawb_number: "02012345675"
                        consolidation_type: "consol"
                        origin: "JFK"
                        destination: "FRA"
                        pieces: 11
                        weight: 1180.5
                        total_amount_of_parts: 2
                        eta: "2026-06-14T06:30:00+02:00"
                    inbound_shipments:
                      - hawb_number: "FRA10088001"
                        pieces: 4
                        weight: 612.0
                        consignee: "ACME EUROPE GMBH"
                  actions:
                    attach_shipment:
                      - process_type: "inbound"
                        hawb_number: "FRA10088001"
                        mawb_number: "02012345675"
              import_pickup:
                summary: Import pickup for onward transport + attach
                value:
                  data:
                    inbound_pickups:
                      - manifest_number: "FRAT900123"
                        announced_for: "2026-06-14T14:00:00+02:00"
                        station: "MUC"
                        license_plate: "F-CC 4210"
                        trucker: "J. Becker"
                        hauler: "Placeholder Trucking GmbH"
                  actions:
                    attach_shipment:
                      - process_type: "inbound"
                        hawb_number: "FRA10088001"
                        manifest_number: "FRAT900123"
      responses:
        "202":
          description: Accepted. The message was syntactically valid and will be processed further.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AcceptedResponse"
              example:
                message: "Accepted"
                id: "9519adbe-cd08-411b-a1b5-754c92aa1cbd"
        "400":
          description: |
            Bad Request. The body is not valid JSON, or the `x-chi-api-token` header is missing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              examples:
                invalid_json:
                  summary: Invalid JSON body
                  value:
                    message: "Bad Request"
                    error: "Invalid JSON:\n[ERROR DETAILS]"
                    id: "9519adbe-cd08-411b-a1b5-754c92aa1cbd"
                missing_token_header:
                  summary: Missing api token header
                  value:
                    message: "Header 'x-chi-api-token' missing."
        "401":
          description: Unauthorized. The api token is invalid or unknown.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UnauthorizedResponse"
              example:
                message: "Unauthorized"
        "422":
          description: |
            Unprocessable Entity. The body is valid JSON but does not match the message schema.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
              example:
                message: "Unprocessable Entity"
                error: "JSON validation failed:\n'mawb_number' is a required property"
                id: "9519adbe-cd08-411b-a1b5-754c92aa1cbd"

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-chi-api-token
      description: |
        Per-customer API token issued by CHI Cargo during onboarding. A staging token is provided
        first; a production token follows once testing on staging is complete.

  schemas:
    # ---- Reusable primitives (from the JSON Schema definitions) ----
    mawb_number:
      type: string
      title: mawb_number
      description: Master Air Waybill number — 11 digits, no dashes or spaces.
      pattern: "^([\\d]{11})$"
      examples:
        - "02012345675"
    hawb_number:
      type: string
      title: hawb_number
      description: House Air Waybill number. Free format, restricted to A-Z and 0-9.
      minLength: 1
      pattern: "^[A-Z0-9]+$"
      examples:
        - "FRA10099001"
    manifest_number:
      type: string
      title: manifest_number
      description: Manifest / tour reference for an arrival or pickup.
      minLength: 1
      pattern: "^([A-Z0-9]+)$"
      examples:
        - "FRAT900123"
    additional_data:
      type: object
      title: additional_data
      description: |
        Arbitrary JSON defined by the customer. It is not interpreted by the Chicago WMS and is
        echoed back unchanged in related status messages (as `additional_api_data`). Use it to carry
        your own business keys alongside CHI's MAWB/HAWB so you can match status messages to your own
        records — for example a CargoWise One Consol ID on a master and Shipment ID on a shipment.
      additionalProperties: true
    timestamp:
      type:
        - string
        - "null"
      format: date-time
      description: RFC 3339 date-time.
      examples:
        - "2026-06-14T06:30:00+02:00"
    origin_destination:
      type:
        - string
        - "null"
      pattern: "^[A-Z0-9]{3}$"
      description: Three-letter IATA airport/station code.
      examples:
        - "FRA"
        - "JFK"
    consolidation_type:
      type:
        - string
        - "null"
      enum:
        - consol
        - b2b
        - iata_direct
      default: consol
    pieces:
      type:
        - integer
        - "null"
      minimum: 1
    weight:
      type:
        - number
        - "null"
      minimum: 0.1
      description: Weight in kilograms (rounded to one decimal).
    dimension:
      type: integer
      description: Dimension in centimeters.
      minimum: 1
    hazard_class:
      type:
        - string
        - "null"
      default: nonhazardous
      enum:
        - nonhazardous
        - explosive
        - gas
        - flammable_liquid
        - flammable_solid
        - oxidizing_substance
        - toxic_and_infectious_substance
        - radioactive_material
        - corrosive
        - miscellaneous_dangerous_good
        - lithium_batteries
        - unknown
    ssccs:
      type:
        - array
        - "null"
      title: sscc
      description: Serial Shipping Container Codes (each exactly 18 characters).
      items:
        type: string
        minLength: 18
        maxLength: 18
    package_references:
      type:
        - array
        - "null"
      title: pack_refs
      description: Alternative package references for customer use.
      items:
        type: string
    process_type:
      type:
        - string
        - "null"
      enum:
        - inbound
        - outbound
    alt_refs:
      type:
        - string
        - "null"
      description: Free customer reference used to identify an object (and to link HAWB-less records).
    consigner:
      type:
        - string
        - "null"
    consignee:
      type:
        - string
        - "null"
    content:
      type:
        - string
        - "null"
    measurements:
      title: measurements
      description: Measurements in cm for each piece on the shipment.
      type:
        - array
        - "null"
      items:
        type: object
        additionalProperties: false
        required:
          - length
          - width
          - height
        properties:
          length:
            $ref: "#/components/schemas/dimension"
          width:
            $ref: "#/components/schemas/dimension"
          height:
            $ref: "#/components/schemas/dimension"
          weight:
            $ref: "#/components/schemas/weight"

    # ---- Data objects ----
    inbound_master:
      type: object
      additionalProperties: false
      required:
        - mawb_number
      properties:
        mawb_number:
          $ref: "#/components/schemas/mawb_number"
        consolidation_type:
          $ref: "#/components/schemas/consolidation_type"
        origin:
          $ref: "#/components/schemas/origin_destination"
        destination:
          $ref: "#/components/schemas/origin_destination"
        pieces:
          $ref: "#/components/schemas/pieces"
        weight:
          $ref: "#/components/schemas/weight"
        total_amount_of_parts:
          type:
            - integer
            - "null"
          minimum: 1
          description: Number of ULDs / parts the master consists of.
        eta:
          $ref: "#/components/schemas/timestamp"
        alt_refs:
          $ref: "#/components/schemas/alt_refs"
        additional_data:
          $ref: "#/components/schemas/additional_data"
    outbound_master:
      type: object
      additionalProperties: false
      required:
        - mawb_number
      properties:
        mawb_number:
          $ref: "#/components/schemas/mawb_number"
        consolidation_type:
          $ref: "#/components/schemas/consolidation_type"
        origin:
          $ref: "#/components/schemas/origin_destination"
        destination:
          $ref: "#/components/schemas/origin_destination"
        lat:
          allOf:
            - $ref: "#/components/schemas/timestamp"
          description: Latest Arrival Time (LAT).
        contour:
          type:
            - string
            - "null"
          description: ULD contour of the master.
        pieces:
          $ref: "#/components/schemas/pieces"
        weight:
          $ref: "#/components/schemas/weight"
        alt_refs:
          $ref: "#/components/schemas/alt_refs"
        additional_data:
          $ref: "#/components/schemas/additional_data"
    inbound_shipment:
      type: object
      additionalProperties: false
      required:
        - hawb_number
      properties:
        hawb_number:
          $ref: "#/components/schemas/hawb_number"
        pieces:
          $ref: "#/components/schemas/pieces"
        weight:
          $ref: "#/components/schemas/weight"
        origin:
          $ref: "#/components/schemas/origin_destination"
        destination:
          $ref: "#/components/schemas/origin_destination"
        alt_refs:
          $ref: "#/components/schemas/alt_refs"
        consigner:
          $ref: "#/components/schemas/consigner"
        consignee:
          $ref: "#/components/schemas/consignee"
        content:
          $ref: "#/components/schemas/content"
        hazard_class:
          $ref: "#/components/schemas/hazard_class"
        measurements:
          $ref: "#/components/schemas/measurements"
        ssccs:
          $ref: "#/components/schemas/ssccs"
        package_references:
          $ref: "#/components/schemas/package_references"
        additional_data:
          $ref: "#/components/schemas/additional_data"
    outbound_shipment:
      type: object
      additionalProperties: false
      description: |
        An outbound shipment. Either `hawb_number` or `alt_refs` must be present — this allows
        creating local export records before a HAWB number exists.
      anyOf:
        - required: [hawb_number]
        - required: [alt_refs]
      properties:
        hawb_number:
          $ref: "#/components/schemas/hawb_number"
        prior_party_secured:
          type: boolean
          description: Whether the shipment has already been secured by a prior party.
        origin:
          $ref: "#/components/schemas/origin_destination"
        destination:
          $ref: "#/components/schemas/origin_destination"
        pieces:
          $ref: "#/components/schemas/pieces"
        weight:
          $ref: "#/components/schemas/weight"
        alt_refs:
          $ref: "#/components/schemas/alt_refs"
        consigner:
          $ref: "#/components/schemas/consigner"
        consignee:
          $ref: "#/components/schemas/consignee"
        content:
          $ref: "#/components/schemas/content"
        hazard_class:
          $ref: "#/components/schemas/hazard_class"
        subawb_number:
          type:
            - string
            - "null"
        measurements:
          $ref: "#/components/schemas/measurements"
        ssccs:
          $ref: "#/components/schemas/ssccs"
        package_references:
          $ref: "#/components/schemas/package_references"
        piece_references:
          $ref: "#/components/schemas/package_references"
        additional_data:
          $ref: "#/components/schemas/additional_data"
    manifest_object:
      type: object
      additionalProperties: false
      description: |
        Shared shape for `inbound_pickups`, `outbound_arrivals` and `inbound_arrivals`. Represents a
        truck manifest — an arrival to the warehouse (export) or a pickup from the warehouse (import).
      required:
        - manifest_number
      properties:
        manifest_number:
          $ref: "#/components/schemas/manifest_number"
        announced_for:
          $ref: "#/components/schemas/timestamp"
        station:
          type:
            - string
            - "null"
        license_plate:
          type:
            - string
            - "null"
        phone:
          type:
            - string
            - "null"
        trucker:
          type:
            - string
            - "null"
        hauler:
          type:
            - string
            - "null"

    # ---- Action objects ----
    attach_detach_shipment:
      type: object
      additionalProperties: false
      required:
        - hawb_number
        - process_type
      oneOf:
        - required: [mawb_number]
        - required: [manifest_number]
      properties:
        hawb_number:
          $ref: "#/components/schemas/hawb_number"
        process_type:
          $ref: "#/components/schemas/process_type"
        mawb_number:
          $ref: "#/components/schemas/mawb_number"
        manifest_number:
          $ref: "#/components/schemas/manifest_number"
    attach_shipment_to_arrival_item:
      type: object
      additionalProperties: false
      required:
        - hawb_number
        - process_type
        - manifest_number
      properties:
        hawb_number:
          $ref: "#/components/schemas/hawb_number"
        process_type:
          $ref: "#/components/schemas/process_type"
        manifest_number:
          $ref: "#/components/schemas/manifest_number"
    cancel_item:
      type: object
      additionalProperties: false
      required:
        - process_type
      oneOf:
        - required: [mawb_number]
        - required: [manifest_number]
        - required: [hawb_number]
      properties:
        hawb_number:
          $ref: "#/components/schemas/hawb_number"
        mawb_number:
          $ref: "#/components/schemas/mawb_number"
        manifest_number:
          $ref: "#/components/schemas/manifest_number"
        process_type:
          $ref: "#/components/schemas/process_type"
    work_item:
      type: object
      additionalProperties: false
      description: |
        Requests a unit of work on a shipment or master. `attach_shipments` (linking HAWB-less
        records via `alt_refs`) is only valid when `workable` is `label_hawb`.
      required:
        - workable
        - process_type
      allOf:
        - oneOf:
            - required: [mawb_number]
            - required: [hawb_number]
        - if:
            properties:
              workable:
                const: label_hawb
          else:
            not:
              required: [attach_shipments]
        - if:
            properties:
              process_type:
                const: outbound
            required: [hawb_number]
          then:
            properties:
              workable:
                enum:
                  [secure, palletize, measure, neutralize, label_hawb, shrink, weigh, photograph, other]
          else:
            properties:
              workable:
                enum:
                  [palletize, measure, neutralize, shrink, weigh, photograph, other]
      properties:
        hawb_number:
          $ref: "#/components/schemas/hawb_number"
        process_type:
          $ref: "#/components/schemas/process_type"
        mawb_number:
          $ref: "#/components/schemas/mawb_number"
        workable:
          type: string
          description: The work to be performed. Allowed values depend on `process_type` and target.
        instructions:
          type: string
          description: Free-text instructions for warehouse workers.
        client_reference:
          type: string
          description: Customer reference echoed back in the `work_item_done` status message.
        attach_shipments:
          type: array
          description: Only valid for `workable = label_hawb`. Links HAWB-less records by `alt_refs`.
          items:
            type: object
            additionalProperties: false
            required:
              - alt_refs
            properties:
              alt_refs:
                type: string

    # ---- Root message ----
    GenericApiMessage:
      type: object
      additionalProperties: false
      title: Generic API Message
      description: Root message — a `data` area and/or an `actions` area.
      properties:
        data:
          type: object
          additionalProperties: false
          properties:
            inbound_masters:
              type: array
              items:
                $ref: "#/components/schemas/inbound_master"
            outbound_masters:
              type: array
              items:
                $ref: "#/components/schemas/outbound_master"
            inbound_shipments:
              type: array
              items:
                $ref: "#/components/schemas/inbound_shipment"
            outbound_shipments:
              type: array
              items:
                $ref: "#/components/schemas/outbound_shipment"
            inbound_pickups:
              type: array
              items:
                $ref: "#/components/schemas/manifest_object"
            outbound_arrivals:
              type: array
              items:
                $ref: "#/components/schemas/manifest_object"
            inbound_arrivals:
              type: array
              items:
                $ref: "#/components/schemas/manifest_object"
        actions:
          type: object
          additionalProperties: false
          properties:
            attach_shipment:
              type: array
              items:
                $ref: "#/components/schemas/attach_detach_shipment"
            detach_shipment:
              type: array
              description: "Detach a HAWB from its master (MAWB). Provide process_type, hawb_number and mawb_number."
              items:
                $ref: "#/components/schemas/attach_detach_shipment"
            attach_shipment_to_arrival:
              type: array
              items:
                $ref: "#/components/schemas/attach_shipment_to_arrival_item"
            cancel:
              type: array
              description: "Note: not yet implemented at the time of writing."
              items:
                $ref: "#/components/schemas/cancel_item"
            add_work_item:
              type: array
              items:
                $ref: "#/components/schemas/work_item"

    # ---- Responses ----
    AcceptedResponse:
      type: object
      properties:
        message:
          type: string
          examples: ["Accepted"]
        id:
          type: string
          description: Process id used to correlate the request with later status messages.
          examples: ["9519adbe-cd08-411b-a1b5-754c92aa1cbd"]
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
        error:
          type: string
        id:
          type: string
    UnauthorizedResponse:
      type: object
      properties:
        message:
          type: string
          examples: ["Unauthorized"]
