{
  "openapi": "3.1.0",
  "info": {
    "title": "FreightUtils API",
    "description": "The neutral freight reference layer for AI agents: reference and calculation APIs for dangerous goods, customs, locations and freight math that agents can call and cite. No freight to sell, no carrier to push. Anon 25/day per IP, free key 100/day, Pro 50k/month — freightutils.com/pricing.",
    "version": "1.0.0",
    "contact": {
      "name": "FreightUtils",
      "url": "https://www.freightutils.com",
      "email": "contact@freightutils.com"
    },
    "license": {
      "name": "Free to use",
      "url": "https://www.freightutils.com/api-docs"
    }
  },
  "servers": [
    {
      "url": "https://www.freightutils.com",
      "description": "Production"
    }
  ],
  "paths": {
    "/api/ldm": {
      "get": {
        "operationId": "calculateLdm",
        "summary": "Loading Metres Calculator",
        "description": "Calculate loading metres (LDM) for pallets on a vehicle. Supports preset pallet sizes or custom dimensions. Returns utilisation percentage, pallet spaces, and fit warnings.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "pallet",
            "in": "query",
            "description": "Preset pallet type. If omitted, length and width are required.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "euro",
                "uk",
                "half",
                "quarter"
              ]
            },
            "example": "euro"
          },
          {
            "name": "length",
            "in": "query",
            "description": "Pallet length in millimetres. Required if no pallet preset is specified.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 1200
          },
          {
            "name": "width",
            "in": "query",
            "description": "Pallet width in millimetres. Required if no pallet preset is specified.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 800
          },
          {
            "name": "qty",
            "in": "query",
            "description": "Number of pallets — a whole number from 1 to 9007199254740991 (default 1). Anything else, such as 2.5 or 1e+21, is refused with 400, never rounded.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": 2
          },
          {
            "name": "stackable",
            "in": "query",
            "description": "Whether the pallets are stackable.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "example": false
          },
          {
            "name": "stack",
            "in": "query",
            "description": "Stack factor: 2 or 3 pallets per floor position. Only read when stackable is true.",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                2,
                3
              ],
              "default": 2
            },
            "example": 2
          },
          {
            "name": "weight",
            "in": "query",
            "description": "Weight per pallet in kilograms.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 500
          },
          {
            "name": "vehicle",
            "in": "query",
            "description": "Vehicle type for utilisation calculation. DEPRECATED: rigid10 — removal in 3.0.0. It still answers with its own figures and returns a DEPRECATED advisory in warnings[]; its 10 m length is published by no manufacturer. Use custom with vehicle_length, or artic. Any other value is refused with 400.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "artic",
                "rigid10",
                "rigid75",
                "luton",
                "us53",
                "us48",
                "custom"
              ],
              "default": "artic"
            },
            "example": "artic"
          },
          {
            "name": "vehicle_length",
            "in": "query",
            "description": "The custom vehicle's load length in metres, greater than 0 — required when vehicle is 'custom' (fits and utilisation are measured against it); ignored otherwise.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 13.6
          }
        ],
        "responses": {
          "200": {
            "description": "Successful LDM calculation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LdmResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters — an unknown vehicle, a custom vehicle without a vehicle_length above 0, or a qty that is not a whole number. The details name each one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/cbm": {
      "get": {
        "operationId": "calculateCbm",
        "summary": "CBM Calculator",
        "description": "Calculate cubic metres (CBM), cubic feet, litres, and cubic inches from box dimensions.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "l",
            "in": "query",
            "description": "Length in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 120
          },
          {
            "name": "w",
            "in": "query",
            "description": "Width in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 80
          },
          {
            "name": "h",
            "in": "query",
            "description": "Height in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 100
          },
          {
            "name": "pcs",
            "in": "query",
            "description": "Number of pieces — a whole number from 1 to 9007199254740991 (default 1). Anything else, such as 2.5 or 1e+21, is refused with 400, never rounded.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": 2
          }
        ],
        "responses": {
          "200": {
            "description": "Successful CBM calculation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CbmResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/chargeable-weight": {
      "get": {
        "operationId": "calculateChargeableWeight",
        "summary": "Chargeable Weight Calculator",
        "description": "Calculate the chargeable weight for air freight shipments by comparing actual gross weight against volumetric weight.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "l",
            "in": "query",
            "description": "Length in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 120
          },
          {
            "name": "w",
            "in": "query",
            "description": "Width in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 80
          },
          {
            "name": "h",
            "in": "query",
            "description": "Height in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 100
          },
          {
            "name": "gw",
            "in": "query",
            "description": "Gross weight in kilograms of ALL pieces together (the total, not one piece); l/w/h are per piece.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 500
          },
          {
            "name": "pcs",
            "in": "query",
            "description": "Number of pieces — a whole number from 1 to 9007199254740991 (default 1). Anything else, such as 2.5 or 1e+21, is refused with 400, never rounded.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": 2
          },
          {
            "name": "factor",
            "in": "query",
            "description": "Volumetric divisor in cm³ per kg — a whole number from 1 to 9007199254740991. Standard air freight is 6000 (default); express carriers typically use 5000.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 6000
            },
            "example": 6000
          },
          {
            "name": "mode",
            "in": "query",
            "description": "Calculation mode: air (default) or sea (W/M at 1 CBM = 1 revenue tonne), in any case. Any other value is refused with 400 — it is never computed as air.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "air",
                "sea"
              ],
              "default": "air"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful chargeable weight calculation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChargeableWeightResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/pallet": {
      "get": {
        "operationId": "calculatePalletFitting",
        "summary": "Pallet Fitting Calculator",
        "description": "Calculate how many boxes fit on a pallet, including layers, orientation, volume utilisation, and weight limits.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "pl",
            "in": "query",
            "description": "Pallet length in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 120
          },
          {
            "name": "pw",
            "in": "query",
            "description": "Pallet width in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 80
          },
          {
            "name": "pmh",
            "in": "query",
            "description": "Pallet maximum height in centimetres (total including deck).",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 220
          },
          {
            "name": "bl",
            "in": "query",
            "description": "Box length in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 40
          },
          {
            "name": "bw",
            "in": "query",
            "description": "Box width in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 30
          },
          {
            "name": "bh",
            "in": "query",
            "description": "Box height in centimetres.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 25
          },
          {
            "name": "ph",
            "in": "query",
            "description": "Pallet deck height in centimetres.",
            "required": false,
            "schema": {
              "type": "number",
              "default": 15
            },
            "example": 15
          },
          {
            "name": "bwt",
            "in": "query",
            "description": "Weight per box in kilograms.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 5
          },
          {
            "name": "mpw",
            "in": "query",
            "description": "Maximum payload weight in kilograms.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 1000
          },
          {
            "name": "rotate",
            "in": "query",
            "description": "Allow box rotation to find best fit.",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": true
            },
            "example": true
          }
        ],
        "responses": {
          "200": {
            "description": "Successful pallet fitting calculation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PalletFittingResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/adr": {
      "get": {
        "operationId": "lookupAdr",
        "summary": "ADR / UN Number Lookup",
        "description": "Look up ADR dangerous goods data by UN number, name search, or hazard class filter. Provide exactly one search parameter.",
        "tags": [
          "Reference Data",
          "ADR"
        ],
        "parameters": [
          {
            "name": "un",
            "in": "query",
            "description": "UN number to look up (e.g. 1203, UN1203 or UN 1203).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "1203"
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to find substances by name.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "petrol"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Case-insensitive partial match on the proper shipping name (min 2 characters). A paged list: total, truncated, next_offset; no match is a 404 with suggestions — the closest proper shipping names in Table A.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "diesel"
          },
          {
            "name": "class",
            "in": "query",
            "description": "ADR hazard class (Table A column (3a)), e.g. 3, 6.1, 8. A paged list: total, truncated, next_offset.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "3"
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Name search / class filter only: rows to skip (default 0). The response gives total, truncated and next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Name search / class filter only: rows per page — 1 to 50 for a search (default 50), 1 to 100 for a class (default 100).",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching ADR substance records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdrLookupResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/adr-calculator": {
      "get": {
        "operationId": "calculateAdrExemptionGet",
        "summary": "ADR 1.1.3.6 Exemption Calculator (single item)",
        "description": "Check one line of dangerous goods carried in packages against the ADR 1.1.3.6 small-load exemption: quantity × transport-category multiplier within 1,000 points and within the category's 1.1.3.6.3 maximum; category 0 never qualifies. ID-prefixed numbers (ID8000) route AIR_ONLY_ID.",
        "tags": [
          "Reference Data",
          "ADR"
        ],
        "parameters": [
          {
            "name": "un",
            "in": "query",
            "description": "UN number of the substance — or an ID-prefixed air-only number (e.g. ID8000): no ADR Table A entry, so it is routed AIR_ONLY_ID and nothing is counted for it — the ADR answer for limited-quantity packages to the ICAO TI (3.4.9, 3.4.10, 1.1.3.6.5), as its warning states.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "1203"
          },
          {
            "name": "qty",
            "in": "query",
            "description": "Quantity on the ADR 1.1.3.6.3 basis: net kg for solids and liquefied, refrigerated or dissolved gases; litres for liquids; receptacle water capacity in litres for compressed or adsorbed gases and chemicals under pressure; articles as the mass of the articles without their packagings, in kg.",
            "required": true,
            "schema": {
              "type": "number",
              "exclusiveMinimum": 0,
              "maximum": 1000000000
            },
            "example": 200
          },
          {
            "name": "packing_group",
            "in": "query",
            "description": "Packing group (I, II or III) — only needed for a UN number with more than one ADR Table A row (e.g. UN 1789); ignored for single-row UNs. Without it a multi-variant UN returns candidates[] and no verdict. Enough alone when the rows it leaves agree on the verdict fields (UN 1790 PG I).",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "I",
                "II",
                "III"
              ]
            },
            "example": "III"
          },
          {
            "name": "variant_index",
            "in": "query",
            "description": "ADR Table A variant index (as returned by /api/adr) — pins one row when a UN number has several variants sharing a packing group (concentration bands). Ignored for single-row UN numbers. Digits only; anything else is a 400.",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "example": 2
          },
          {
            "name": "unit",
            "in": "query",
            "description": "OPTIONAL dimension of qty. Omit it and qty is taken as already on the 1.1.3.6.3 basis (unchanged). Supply it and it is checked against the dimension the row is counted in; a mismatch returns points, total_points and exempt all null with basis_mismatch true. Case-insensitive; else 400.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "L",
                "kg"
              ]
            },
            "example": "L"
          },
          {
            "name": "basis",
            "in": "query",
            "description": "OPTIONAL. ADR 1.1.3.6.3 counts the dangerous goods themselves, never the packaging, so a figure declared \"gross\" returns no points in ANY unit — send the net quantity instead.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "net",
                "gross"
              ]
            },
            "example": "net"
          }
        ],
        "responses": {
          "200": {
            "description": "ADR 1.1.3.6 result; items[].state names each line's route (COUNTED, AIR_ONLY_ID, NOT_SUBJECT_TO_ADR, BLOCKED). All lines ambiguous: human_review_required + blocking_errors[AMBIGUOUS_UN_VARIANT] + candidates[], no verdict; a mixed load withholds that line only. Agreeing rows resolve.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdrCalculatorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input — e.g. a quantity that is not a number > 0, an unknown unit or basis, an unknown UN number, or a parameter the route does not read (refused by name with the accepted ones listed, never ignored). The error names what arrived.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "calculateAdrExemption",
        "summary": "ADR 1.1.3.6 Exemption Calculator (multiple items)",
        "description": "Check a load carried in packages against the ADR 1.1.3.6 small-load exemption: the 1.1.3.6.4 points sum within 1,000, each 1.1.3.6.3 category maximum (a total when every line is one category) and no category 0. items[].state names each line's route.",
        "tags": [
          "Reference Data",
          "ADR"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdrCalculatorRequest"
              },
              "example": {
                "items": [
                  {
                    "un_number": "1203",
                    "quantity": 200
                  },
                  {
                    "un_number": "1950",
                    "quantity": 50
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "ADR 1.1.3.6 result; items[].state names each line's route (COUNTED, AIR_ONLY_ID, NOT_SUBJECT_TO_ADR, BLOCKED). All lines ambiguous: human_review_required + blocking_errors[AMBIGUOUS_UN_VARIANT] + candidates[], no verdict; a mixed load withholds that line only. Agreeing rows resolve.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdrCalculatorResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input — e.g. a quantity that is not a number > 0, an unknown unit or basis, an unknown UN number, a single-substance field sent beside items[], or any field the route does not read — refused by name, never dropped. The error names what arrived.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/airlines": {
      "get": {
        "operationId": "searchAirlines",
        "summary": "Airline Lookup",
        "description": "Search for cargo airlines by name, IATA code, ICAO code, AWB prefix, or country. Provide one search parameter.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "General search term (matches airline name, codes, and country).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "emirates"
          },
          {
            "name": "iata",
            "in": "query",
            "description": "2-character IATA airline code.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "EK"
          },
          {
            "name": "icao",
            "in": "query",
            "description": "3-character ICAO airline code.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "UAE"
          },
          {
            "name": "prefix",
            "in": "query",
            "description": "3-digit AWB prefix number.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "176"
          },
          {
            "name": "country",
            "in": "query",
            "description": "Country name to filter airlines by.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "United Arab Emirates"
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "view=summary returns summary rows (a subset of each record's fields) with detail_hint; the default is the full rows.",
            "schema": {
              "type": "string",
              "enum": [
                "summary"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "List paging: rows to skip (default 0). With offset or limit the answer states total, truncated and next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "List paging: rows per page, 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching airline records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AirlinesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/incoterms": {
      "get": {
        "operationId": "lookupIncoterms",
        "summary": "INCOTERMS 2020 Lookup",
        "description": "Look up INCOTERMS 2020 rules by code or filter by category. Returns detailed responsibility breakdowns for each term. When called with a specific code, returns a single detailed object. When called without a code, returns all terms.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "description": "Incoterms 2020 code, e.g. FOB. A code Incoterms 2020 replaced (DAT) answers 404 naming its successor (replaced_by: DPU, with the ICC source).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "FOB"
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by transport mode category.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "any_mode",
                "sea_only"
              ]
            },
            "example": "sea_only"
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "view=summary returns summary rows (a subset of each record's fields) with detail_hint; the default is the full rows.",
            "schema": {
              "type": "string",
              "enum": [
                "summary"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "List paging: rows to skip (default 0). With offset or limit the answer states total, truncated and next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "List paging: rows per page, 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "INCOTERMS data. Returns a single Incoterm object when queried by code, or a list when browsing.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/IncotermDetail"
                    },
                    {
                      "$ref": "#/components/schemas/IncotermsListResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/hs": {
      "get": {
        "operationId": "lookupHsCodes",
        "summary": "HS Code Lookup",
        "description": "Search and browse Harmonized System (HS 2022) commodity codes. Supports text search by product description, exact code lookup with ancestor chain, and section browsing. Covers 6,937 codes across 21 sections and 96 chapters.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Case-insensitive search on descriptions and HS codes. Min 2 characters. When no HS 2022 description contains the words, the UK Trade Tariff search references (HMRC) are asked, and the codes they name come back with `matched_via` (\"laptop\" → 847130).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "coffee"
          },
          {
            "name": "code",
            "in": "query",
            "description": "Exact HS code: 2–6 digits, written with or without dots or spaces (e.g. 847130, 8471.30, 0901).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "0901"
          },
          {
            "name": "section",
            "in": "query",
            "description": "Browse by section Roman numeral. Returns all chapters in that section.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "II"
          }
        ],
        "responses": {
          "200": {
            "description": "HS code data. Response shape varies by query mode.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/HsSearchResponse"
                    },
                    {
                      "$ref": "#/components/schemas/HsCodeDetail"
                    },
                    {
                      "$ref": "#/components/schemas/HsSectionResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Code or section not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/containers": {
      "get": {
        "operationId": "getContainers",
        "summary": "Container Capacity Reference",
        "description": "Shipping container specifications for all 10 standard ISO container types. Returns dimensions, weights, door openings, and pallet capacity. Optionally calculate how many items of given dimensions fit in a specific container.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "Container type slug. Omit to list all containers.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "20ft-standard",
                "40ft-standard",
                "20ft-high-cube",
                "40ft-high-cube",
                "20ft-open-top",
                "40ft-open-top",
                "20ft-flat-rack",
                "40ft-flat-rack",
                "20ft-reefer",
                "40ft-reefer"
              ]
            },
            "example": "40ft-high-cube"
          },
          {
            "name": "l",
            "in": "query",
            "description": "Item length in centimetres. Requires type, w, and h for loading calculation.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 60
          },
          {
            "name": "w",
            "in": "query",
            "description": "Item width in centimetres.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 40
          },
          {
            "name": "h",
            "in": "query",
            "description": "Item height in centimetres.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 40
          },
          {
            "name": "wt",
            "in": "query",
            "description": "Weight of one item in kilograms, 0 or more (default: no weight check). Anything else is refused with 400.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 15
          },
          {
            "name": "qty",
            "in": "query",
            "description": "Number of items — a whole number from 1 to 9007199254740991 (default 1). Anything else is refused with 400, never rounded.",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": 100
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "view=summary returns summary rows (a subset of each record's fields) with detail_hint; the default is the full rows.",
            "schema": {
              "type": "string",
              "enum": [
                "summary"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "List paging: rows to skip (default 0). With offset or limit the answer states total, truncated and next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "List paging: rows per page, 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Container specifications or loading calculation result.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ContainerListResponse"
                    },
                    {
                      "$ref": "#/components/schemas/ContainerSpec"
                    },
                    {
                      "$ref": "#/components/schemas/ContainerLoadingResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Container type not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/convert": {
      "get": {
        "operationId": "convertUnits",
        "summary": "Unit Converter",
        "description": "Convert between freight-relevant units — weights, volumes, lengths, and freight-specific conversions (CBM to chargeable weight using IATA 6000 divisor, CBM to freight tonnes using W/M rule).",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "value",
            "in": "query",
            "description": "The number to convert.",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 100
          },
          {
            "name": "from",
            "in": "query",
            "description": "Source unit code.",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "kg",
                "lbs",
                "oz",
                "tonnes",
                "short_tons",
                "long_tons",
                "cbm",
                "cuft",
                "cuin",
                "litres",
                "gal_us",
                "gal_uk",
                "cm",
                "inches",
                "m",
                "feet",
                "mm"
              ]
            },
            "example": "kg"
          },
          {
            "name": "to",
            "in": "query",
            "description": "Target unit code. Includes freight-specific targets: chargeable_kg (from cbm only) and freight_tonnes (from cbm only).",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "kg",
                "lbs",
                "oz",
                "tonnes",
                "short_tons",
                "long_tons",
                "cbm",
                "cuft",
                "cuin",
                "litres",
                "gal_us",
                "gal_uk",
                "cm",
                "inches",
                "m",
                "feet",
                "mm",
                "chargeable_kg",
                "freight_tonnes"
              ]
            },
            "example": "lbs"
          }
        ],
        "responses": {
          "200": {
            "description": "Conversion result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversionResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/consignment": {
      "post": {
        "summary": "Multi-item consignment calculator",
        "description": "Calculate total CBM, loading metres and mode-specific chargeable weight for a multi-item consignment, with per-line and grand totals plus flags (implausible density, mode/option mismatch, DG vs ADR 2025, ISO 6346 / IATA AWB check digits). Reference data only. Schema: /schema/consignment.v1.json.",
        "operationId": "calculateConsignment",
        "tags": [
          "Consignment"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Provide either `lines` (canonical) or `items` (legacy flat alias). `mode` defaults to road.",
                "anyOf": [
                  {
                    "required": [
                      "lines"
                    ]
                  },
                  {
                    "required": [
                      "items"
                    ]
                  }
                ],
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "road",
                      "air",
                      "sea"
                    ],
                    "default": "road"
                  },
                  "lines": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 50,
                    "items": {
                      "type": "object",
                      "required": [
                        "quantity",
                        "dims",
                        "weight"
                      ],
                      "properties": {
                        "description": {
                          "type": "string"
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1
                        },
                        "dims": {
                          "type": "object",
                          "required": [
                            "l",
                            "w",
                            "h",
                            "unit"
                          ],
                          "properties": {
                            "l": {
                              "type": "number"
                            },
                            "w": {
                              "type": "number"
                            },
                            "h": {
                              "type": "number"
                            },
                            "unit": {
                              "type": "string",
                              "enum": [
                                "mm",
                                "cm",
                                "m",
                                "in"
                              ]
                            }
                          }
                        },
                        "weight": {
                          "type": "object",
                          "required": [
                            "value",
                            "unit"
                          ],
                          "properties": {
                            "value": {
                              "type": "number"
                            },
                            "unit": {
                              "type": "string",
                              "enum": [
                                "kg",
                                "g",
                                "t",
                                "lb"
                              ]
                            }
                          }
                        },
                        "hs_code": {
                          "type": "string"
                        },
                        "un_number": {
                          "type": "string"
                        },
                        "stackable": {
                          "type": "boolean"
                        }
                      }
                    }
                  },
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 50,
                    "description": "Legacy flat alias — dimensions in cm, weight in kg.",
                    "items": {
                      "type": "object",
                      "required": [
                        "length",
                        "width",
                        "height"
                      ],
                      "properties": {
                        "description": {
                          "type": "string"
                        },
                        "length": {
                          "type": "number"
                        },
                        "width": {
                          "type": "number"
                        },
                        "height": {
                          "type": "number"
                        },
                        "quantity": {
                          "type": "integer",
                          "default": 1
                        },
                        "gross_weight": {
                          "type": "number"
                        },
                        "stackable": {
                          "type": "boolean"
                        },
                        "pallet_type": {
                          "type": "string",
                          "enum": [
                            "none",
                            "euro",
                            "uk",
                            "us",
                            "custom"
                          ]
                        }
                      }
                    }
                  },
                  "options": {
                    "type": "object",
                    "properties": {
                      "air_volumetric_divisor": {
                        "type": "number",
                        "default": 6000
                      },
                      "container_number": {
                        "type": "string"
                      },
                      "awb_number": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Consignment calculation result (schema: /schema/consignment.v1.json)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schema_version": {
                      "type": "string"
                    },
                    "mode": {
                      "type": "string"
                    },
                    "air_volumetric_divisor": {
                      "type": "number"
                    },
                    "per_line": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "totals": {
                      "type": "object"
                    },
                    "flags": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "disclaimer": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error"
          }
        }
      }
    },
    "/api/duty": {
      "post": {
        "summary": "UK import duty and VAT estimator",
        "description": "Estimate UK import duty and VAT using live GOV.UK Trade Tariff data.",
        "operationId": "estimateDuty",
        "tags": [
          "Customs"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "commodity_code",
                  "origin_country",
                  "customs_value"
                ],
                "properties": {
                  "commodity_code": {
                    "type": "string",
                    "pattern": "^(?:\\s*\\d){6,10}\\s*$",
                    "description": "UK commodity code. A declarable code is 10 digits; a 6- or 8-digit code is refused with HTTP 400 and declarable_codes — the 10-digit codes beneath it in the UK Trade Tariff — never padded with zeros.",
                    "example": "6204430000"
                  },
                  "origin_country": {
                    "type": "string",
                    "example": "CN"
                  },
                  "customs_value": {
                    "type": "number",
                    "example": 10000,
                    "description": "Goods value in GBP, greater than 0 — a number, or its digits as text. Anything else is refused with 400."
                  },
                  "freight_cost": {
                    "type": "number",
                    "example": 500,
                    "minimum": 0,
                    "description": "Freight cost in GBP, 0 or more (default 0). A negative or non-numeric cost is refused with 400 — it would change the CIF value duty is charged on."
                  },
                  "insurance_cost": {
                    "type": "number",
                    "example": 50,
                    "minimum": 0,
                    "description": "Insurance cost in GBP, 0 or more (default 0). A negative or non-numeric cost is refused with 400 — it would change the CIF value duty is charged on."
                  },
                  "incoterm": {
                    "type": "string",
                    "example": "FOB"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Duty and VAT estimate"
          },
          "400": {
            "description": "Invalid parameters: a commodity_code that is not 10 digits (a 6- or 8-digit code is refused with declarable_codes, the 10-digit codes beneath it in the UK Trade Tariff), an origin_country that is not ISO 3166-1, a customs_value not above 0, or a negative cost."
          }
        }
      }
    },
    "/api/unlocode": {
      "get": {
        "summary": "UN/LOCODE transport location lookup",
        "description": "Search 116,000+ UN/LOCODE entries by name, code, country, or function type.",
        "operationId": "searchUnlocode",
        "tags": [
          "Reference"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "description": "Name or code search; the spaced notation \"GB LHR\" reads as GBLHR.",
            "schema": {
              "type": "string"
            },
            "example": "rotterdam"
          },
          {
            "name": "code",
            "in": "query",
            "description": "Exact 5-character UN/LOCODE, e.g. GBLHR; \"GB LHR\" is accepted.",
            "schema": {
              "type": "string"
            },
            "example": "NLRTM"
          },
          {
            "name": "country",
            "in": "query",
            "description": "ISO 2-letter country",
            "schema": {
              "type": "string"
            },
            "example": "GB"
          },
          {
            "name": "function",
            "in": "query",
            "description": "Function type",
            "schema": {
              "type": "string",
              "enum": [
                "port",
                "airport",
                "rail",
                "road",
                "icd",
                "border"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Max results — a whole number (default 20); values outside 1–100 are clamped. Text that is not a whole number is refused with 400.",
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Search results. A name search with no match carries did_you_mean: up to 3 real places whose name is one or two letters from the query ({code, name, country}) — suggestions, never applied."
          },
          "404": {
            "description": "Code not found When the code is one character from real UN/LOCODEs in the same country, did_you_mean lists up to 3 of them ({code, name, country})."
          }
        }
      }
    },
    "/api/uld": {
      "get": {
        "operationId": "getULDs",
        "summary": "Air Freight ULD Types",
        "description": "Look up air freight ULD specifications. 16 types including AKE (LD3), PMC, the tall PMCQ7 variant and temperature-controlled containers. Returns dimensions, weights, volume and aircraft compatibility. An unrecognised query parameter returns 400, never a silent unfiltered result.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "IATA ULD type code (AKE), slug (ake-ld3) or the record name when one record carries it (LD3 → AKE). Unknown types answer 404 with suggestions.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "AKE"
          },
          {
            "name": "code",
            "in": "query",
            "description": "Alias for type — the IATA ULD code (e.g. AKE). Accepted because the response field is named code.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "AKE"
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by category: container, pallet, or special.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "container",
                "pallet",
                "special"
              ]
            }
          },
          {
            "name": "deck",
            "in": "query",
            "description": "Filter by deck position: lower or main.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "lower",
                "main"
              ]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "view=summary returns summary rows (a subset of each record's fields) with detail_hint; the default is the full rows.",
            "schema": {
              "type": "string",
              "enum": [
                "summary"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "List paging: rows to skip (default 0). With offset or limit the answer states total, truncated and next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "List paging: rows per page, 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ULD specification(s)."
          },
          "404": {
            "description": "ULD type not found."
          }
        }
      }
    },
    "/api/vehicles": {
      "get": {
        "operationId": "getVehicles",
        "summary": "Vehicle & Trailer Types",
        "description": "Look up road freight vehicle and trailer specifications. 17 types covering articulated trailers, rigid trucks, and vans. Returns dimensions, payload limits, pallet capacity.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "query",
            "description": "Vehicle slug, e.g. standard-curtainsider. Unknown slugs answer 404 with valid_slugs and suggestions (the closest slugs).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "standard-curtainsider"
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by category: articulated, rigid, or van.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "articulated",
                "rigid",
                "van"
              ]
            }
          },
          {
            "name": "region",
            "in": "query",
            "description": "Filter by region: EU or US.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "EU",
                "US"
              ]
            }
          },
          {
            "name": "view",
            "in": "query",
            "required": false,
            "description": "view=summary returns summary rows (a subset of each record's fields) with detail_hint; the default is the full rows.",
            "schema": {
              "type": "string",
              "enum": [
                "summary"
              ]
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "List paging: rows to skip (default 0). With offset or limit the answer states total, truncated and next_offset.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "List paging: rows per page, 1 to 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Vehicle specification(s)."
          },
          "404": {
            "description": "Vehicle type not found."
          }
        }
      }
    },
    "/api/adr/lq-check": {
      "post": {
        "operationId": "checkLqEq",
        "summary": "ADR Limited & Excepted Quantity Checker",
        "description": "Check whether dangerous goods items qualify for ADR Limited Quantity (Chapter 3.4) or Excepted Quantity (Chapter 3.5) concessions. Returns per-item pass/fail against ADR Table A limits.",
        "tags": [
          "Reference Data",
          "ADR"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "lq",
                      "eq"
                    ],
                    "default": "lq",
                    "description": "Check mode — 'lq' for Limited Quantity (Ch 3.4) or 'eq' for Excepted Quantity (Ch 3.5)"
                  },
                  "items": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "type": "object",
                      "required": [
                        "un_number",
                        "quantity"
                      ],
                      "properties": {
                        "un_number": {
                          "type": "string",
                          "description": "UN number (1-4 digits)",
                          "example": "1203"
                        },
                        "quantity": {
                          "type": "number",
                          "description": "Quantity per inner packaging",
                          "example": 0.5
                        },
                        "unit": {
                          "type": "string",
                          "enum": [
                            "ml",
                            "L",
                            "g",
                            "kg"
                          ],
                          "default": "L",
                          "description": "Unit of measure"
                        },
                        "inner_packaging_qty": {
                          "type": "number",
                          "description": "Inner packagings in one outer packaging (EQ mode only) — a whole number of 1 or more; omitted means 1. Anything else, such as 0, -20 or 16.5, is refused with 400."
                        },
                        "packing_group": {
                          "type": "string",
                          "enum": [
                            "I",
                            "II",
                            "III"
                          ],
                          "description": "Packing group — only needed for a UN number with more than one ADR Table A row (e.g. UN 1789); ignored for single-row UNs. Without it that line is withheld while its siblings are answered. Enough alone when the rows it leaves agree on the verdict fields (UN 1790 PG I)."
                        },
                        "variant_index": {
                          "type": "integer",
                          "minimum": 0,
                          "description": "ADR Table A variant index (as returned by /api/adr) — pins one row when a UN number has several variants sharing a packing group (concentration bands). Ignored for single-row UN numbers."
                        }
                      },
                      "additionalProperties": false
                    }
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "mode": "lq",
                "items": [
                  {
                    "un_number": "1203",
                    "quantity": 0.5,
                    "unit": "L"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "LQ/EQ per-item status. Multi-variant UN without packing_group: all items ambiguous = human_review_required + blocking_errors[AMBIGUOUS_UN_VARIANT] + candidates[], no verdict; a mixed batch withholds that item only and overall_status never reads qualifies. Agreeing rows resolve (equivalent_variants).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "blocking_errors": {
                      "type": "array",
                      "description": "Present only on the all-ambiguous 200 (no verdict, no items): [{ code: AMBIGUOUS_UN_VARIANT, message, recovery }], one per item, in the plain body too. recovery.params never pick a row (sent unchanged: asked again); pick from candidates[], send packing_group or variant_index on the item.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string",
                            "example": "AMBIGUOUS_UN_VARIANT"
                          },
                          "message": {
                            "type": "string"
                          },
                          "recovery": {
                            "type": "object"
                          }
                        }
                      }
                    },
                    "mode": {
                      "type": "string",
                      "enum": [
                        "lq",
                        "eq"
                      ]
                    },
                    "overall_status": {
                      "type": "string",
                      "enum": [
                        "qualifies",
                        "does_not_qualify",
                        "partial",
                        "not_applicable",
                        "inconclusive"
                      ],
                      "description": "not_applicable = every item is NOT SUBJECT TO ADR (Table A scope flag) — LQ/EQ provisions do not apply. inconclusive = every in-scope item could not be compared (see items[].status). A batch holding ANY inconclusive or withheld item never reads qualifies."
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "un_number": {
                            "type": "string"
                          },
                          "variant_index": {
                            "type": [
                              "integer",
                              "null"
                            ],
                            "description": "The resolved ADR Table A variant index for this row. Null on a withheld item."
                          },
                          "substance": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "class": {
                            "type": "string"
                          },
                          "packing_group": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "lq_limit": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "lq_limit_value": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "lq_limit_unit": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "eq_code": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "quantity_entered": {
                            "type": "number"
                          },
                          "unit_entered": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "within_limit",
                              "exceeds_limit",
                              "not_permitted",
                              "not_subject",
                              "inconclusive",
                              "withheld"
                            ],
                            "description": "not_subject = outside ADR scope. inconclusive = column (7a) limit and quantity in different unit families (mass vs volume); ADR states no density — resend in lq_limit_unit. withheld = the UN has several Table A rows and none was pinned; row fields null, its rows under candidates[]."
                          },
                          "reason": {
                            "type": "string"
                          },
                          "withheld": {
                            "type": "boolean",
                            "description": "Present and true on a withheld item."
                          },
                          "ambiguity_reason": {
                            "type": "string",
                            "enum": [
                              "multiple_variants",
                              "packing_group_collision",
                              "no_matching_variant"
                            ],
                            "description": "Why the withheld item could not be pinned. Present only with withheld."
                          },
                          "equivalent_variants": {
                            "type": "array",
                            "description": "Present when the supplied packing_group left several Table A rows that agree on class, column (7a), column (7b) and scope: the rows this verdict holds for. The row fields above are the first one's.",
                            "items": {
                              "type": "object",
                              "properties": {
                                "variant_index": {
                                  "type": "integer"
                                },
                                "proper_shipping_name": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "variant_note": {
                            "type": "string",
                            "description": "Plain-language statement of the equivalence. Present only with equivalent_variants."
                          },
                          "not_subject_to_adr": {
                            "type": "boolean",
                            "description": "Present and true for a Table A NOT SUBJECT TO ADR row."
                          },
                          "carriage_prohibited": {
                            "type": "boolean",
                            "description": "Present and true for a Table A CARRIAGE PROHIBITED row (status not_permitted)."
                          },
                          "conditions_ref": {
                            "type": "string",
                            "description": "ADR section whose carriage conditions still apply (e.g. 5.5.3)."
                          }
                        }
                      }
                    },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "total_items": {
                          "type": "integer"
                        },
                        "qualifying": {
                          "type": "integer"
                        },
                        "exceeding": {
                          "type": "integer"
                        },
                        "not_permitted": {
                          "type": "integer"
                        },
                        "not_subject": {
                          "type": "integer",
                          "description": "Count of out-of-scope items. Emitted only when non-zero."
                        },
                        "inconclusive": {
                          "type": "integer",
                          "description": "Count of items that could not be compared (unit family mismatch). Emitted only when non-zero."
                        },
                        "withheld": {
                          "type": "integer",
                          "description": "Count of items withheld for an unpinned multi-variant UN. Emitted only when non-zero."
                        }
                      }
                    },
                    "references": {
                      "type": "object",
                      "properties": {
                        "adr_chapter": {
                          "type": "string"
                        },
                        "table": {
                          "type": "string"
                        }
                      }
                    },
                    "human_review_required": {
                      "type": "boolean",
                      "description": "Present and true when at least one item is withheld. candidates[] then lists that item's rows."
                    },
                    "candidates": {
                      "type": "array",
                      "description": "The withheld items' candidate Table A rows, each tagged with the item_index and un_number they belong to. Present only with human_review_required.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "item_index": {
                            "type": "integer"
                          },
                          "un_number": {
                            "type": "string"
                          },
                          "variant_index": {
                            "type": "integer"
                          },
                          "packing_group": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "proper_shipping_name": {
                            "type": "string"
                          },
                          "limited_quantity": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "excepted_quantity": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters — e.g. a quantity that is not a positive number, an unknown unit, or a field the route does not read (refused by name with the accepted ones listed, never ignored). The error names what arrived.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "405": {
            "description": "Use POST with a JSON body."
          }
        }
      }
    },
    "/api/shipment/summary": {
      "post": {
        "summary": "Composite shipment summary",
        "description": "Chains CBM, chargeable weight, LDM, ADR compliance, and UK duty estimation into one response. The flagship composite endpoint.",
        "operationId": "shipmentSummary",
        "tags": [
          "Composite"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "mode",
                  "items"
                ],
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "road",
                      "air",
                      "sea",
                      "multimodal"
                    ]
                  },
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "length",
                        "width",
                        "height",
                        "weight"
                      ],
                      "properties": {
                        "description": {
                          "type": "string"
                        },
                        "length": {
                          "type": "number"
                        },
                        "width": {
                          "type": "number"
                        },
                        "height": {
                          "type": "number"
                        },
                        "weight": {
                          "type": "number",
                          "description": "Gross weight in kg PER ITEM (per piece) — multiplied by quantity."
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1,
                          "description": "Number of pieces: a whole number from 1 to 1,000,000, sent as a number. Omit it for 1; null, 0, fractions or text are a 400.",
                          "maximum": 1000000
                        },
                        "stackable": {
                          "type": "boolean"
                        },
                        "pallet_type": {
                          "type": "string",
                          "enum": [
                            "euro",
                            "uk",
                            "us",
                            "custom",
                            "none"
                          ],
                          "description": "Pallet standard the item sits on, if any (sets the pallet footprint for the road LDM)."
                        },
                        "hs_code": {
                          "type": "string"
                        },
                        "un_number": {
                          "type": "string"
                        },
                        "customs_value": {
                          "type": "number",
                          "description": "Customs value in GBP PER ITEM (per piece), 0 or more — multiplied by quantity for the line; the duty estimate uses the sum over all lines (echoed as customs.customsValueTotal). Left out, null or blank means none; a negative, NaN or infinite value is refused with 400 naming the item.",
                          "minimum": 0
                        },
                        "adr_quantity": {
                          "type": "number",
                          "description": "ADR 1.1.3.6.3 quantity for this dangerous-goods line — the TOTAL for the whole line, all pieces together, never per piece. Separate from weight (gross package mass). Supply it with adr_quantity_unit on every DG line and adrFlags.totalPoints is calculated.",
                          "exclusiveMinimum": 0,
                          "maximum": 1000000000
                        },
                        "adr_quantity_unit": {
                          "type": "string",
                          "enum": [
                            "L",
                            "kg"
                          ],
                          "description": "Dimension of adr_quantity. Checked against the dimension 1.1.3.6.3 counts for the row — a litres row given kilograms still withholds the total."
                        }
                      }
                    }
                  },
                  "origin": {
                    "type": "object",
                    "properties": {
                      "country": {
                        "type": "string"
                      },
                      "locode": {
                        "type": "string"
                      }
                    },
                    "additionalProperties": false
                  },
                  "destination": {
                    "type": "object",
                    "properties": {
                      "country": {
                        "type": "string"
                      },
                      "locode": {
                        "type": "string"
                      }
                    },
                    "additionalProperties": false
                  },
                  "incoterm": {
                    "type": "string"
                  },
                  "freight_cost": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Freight cost in GBP, 0 or more (added to the CIF value of the UK duty estimate). Left out, null or blank means 0. A negative, NaN or infinite value is refused with 400 naming the field."
                  },
                  "insurance_cost": {
                    "type": "number",
                    "minimum": 0,
                    "description": "Insurance cost in GBP, 0 or more (added to the CIF value of the UK duty estimate). Left out, null or blank means 0. A negative, NaN or infinite value is refused with 400 naming the field."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Complete shipment summary"
          },
          "400": {
            "description": "Invalid input — e.g. a piece count that is not a whole number ≥ 1, an adr_quantity / adr_quantity_unit that is not a number > 0 / \"L\" or \"kg\", a cost that is negative or not a finite number, or a field the route does not read (refused by name, never ignored). The error names what arrived."
          },
          "405": {
            "description": "Use POST"
          }
        }
      }
    },
    "/api/emissions": {
      "get": {
        "operationId": "calculateEmissions",
        "summary": "Freight Emissions Calculator",
        "description": "Estimate freight GHG emissions (kgCO2e) by the ISO 14083 / GLEC distance method (mass x distance x a published factor). Provide ACTUAL GROSS MASS (see mass_basis), not chargeable weight. Returns well-to-wheel + tank-to-wheel and a _source. Unknown mode/region -> available:false.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "mass",
            "in": "query",
            "description": "Shipment mass (in mass_unit).",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 10
          },
          {
            "name": "mass_unit",
            "in": "query",
            "description": "Unit for mass.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "kg",
                "tonnes"
              ],
              "default": "kg"
            }
          },
          {
            "name": "distance_km",
            "in": "query",
            "description": "Transport distance in kilometres (caller-provided; not routed).",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 500
          },
          {
            "name": "mode",
            "in": "query",
            "description": "Transport mode.",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "road",
                "rail",
                "sea",
                "air",
                "inland_waterway"
              ]
            }
          },
          {
            "name": "sub_mode",
            "in": "query",
            "description": "Optional sub-mode / vehicle class (e.g. \"articulated\", \"container ship\"). Omit for the representative default.",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "region",
            "in": "query",
            "description": "Factor source/region: uk = DEFRA, us = EPA, fr = ADEME. Default is per-mode.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "uk",
                "us",
                "fr"
              ]
            }
          },
          {
            "name": "basis",
            "in": "query",
            "description": "wtw (default) or ttw. When the factor publishes only the other basis, the answer uses it and says so: emissions.basis_used, basis_requested, basis_note and a BASIS_SUBSTITUTED warning.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "wtw",
                "ttw"
              ],
              "default": "wtw"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Computed emissions (available:true) or a not-available response (available:false) listing covered options.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmissionsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error (missing/invalid parameter).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/validate": {
      "get": {
        "operationId": "validateIdentifier",
        "summary": "Freight Identifier Validator",
        "description": "Parse ANY text (e.g. a booking line or email) to find and validate every freight identifier in it — shipping container (ISO 6346), air waybill (IATA modulus-7) and IMO ship number. Or pass value + type (container|awb|imo) to validate a single one. Structural check-digit validation only.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "text",
            "in": "query",
            "description": "Free text to scan for container, AWB and IMO identifiers. An AWB is also found written \"176 1234 5675\" or \"17612345675\" when its check digit and airline prefix are valid; every spelling of one identifier is kept in raw_forms.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "Box CSQU3054383 on AWB 020-58717481 to vessel IMO9074729"
          },
          {
            "name": "value",
            "in": "query",
            "description": "A single identifier to validate (typed mode). Requires type.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "020-58717481"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Identifier type for value: container (ISO 6346), awb (IATA Air Waybill), imo (IMO ship number).",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "container",
                "awb",
                "imo"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Validation result: every identifier found, each with check-digit verdict + _source.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error (neither text nor value+type supplied, or invalid type).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/ics2-check": {
      "get": {
        "operationId": "checkIcs2StopWords",
        "summary": "ICS2 Stop-Words Checker",
        "description": "Check a goods description against the official EU ICS2 stop-words list (unacceptable ENS terms, DE 18 05 000 000). Returns flagged terms, a clean boolean and a _source. Reference only - not an ENS filing or legal advice; non-exhaustive, clean != acceptance. Descriptions are not stored.",
        "tags": [
          "Calculators"
        ],
        "parameters": [
          {
            "name": "description",
            "in": "query",
            "description": "The goods description to screen (required, not blank). An empty or blank description is refused with 400 — there is nothing to screen.",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "men's cotton T-shirts, 100% cotton"
          }
        ],
        "responses": {
          "200": {
            "description": "Stop-words check result (flagged terms + caveat + _source).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Ics2CheckResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error (description parameter missing).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/airports": {
      "get": {
        "operationId": "lookupAirport",
        "summary": "Airport Code Lookup",
        "description": "Look up an airport by IATA code (3 letters), ICAO code (4 chars), or free-text name / city. Provide one of iata, icao, or q; optional type filter. Returns full airport record(s); ambiguous names return ranked candidates. Data: OurAirports (public domain), cross-checked vs OpenFlights + Wikidata.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "iata",
            "in": "query",
            "description": "Exact 3-letter IATA code.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "LHR"
          },
          {
            "name": "icao",
            "in": "query",
            "description": "Exact 4-character ICAO code.",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "EGLL"
          },
          {
            "name": "q",
            "in": "query",
            "description": "Name / city / municipality search (min 2 chars).",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "heathrow"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Optional filter by airport type.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "large_airport",
                "medium_airport",
                "small_airport",
                "heliport",
                "closed",
                "seaplane_base"
              ]
            },
            "example": "large_airport"
          }
        ],
        "responses": {
          "200": {
            "description": "Matching airport record(s).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AirportsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "No airport found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/nearest-airport": {
      "get": {
        "operationId": "nearestAirport",
        "summary": "Nearest Airport",
        "description": "Find the airports nearest to a caller-provided latitude/longitude, sorted by great-circle (haversine) distance with distance_km on each result. Coordinates are input only — never stored or logged. Optional radius_km, max_results (1-50, default 10) and type filter.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "description": "Latitude in decimal degrees (-90 to 90).",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": 51.47
          },
          {
            "name": "lon",
            "in": "query",
            "description": "Longitude in decimal degrees (-180 to 180).",
            "required": true,
            "schema": {
              "type": "number"
            },
            "example": -0.46
          },
          {
            "name": "radius_km",
            "in": "query",
            "description": "Optional maximum distance in kilometres.",
            "required": false,
            "schema": {
              "type": "number"
            },
            "example": 100
          },
          {
            "name": "max_results",
            "in": "query",
            "description": "Maximum results to return (1-50, default 10).",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "example": 5
          },
          {
            "name": "type",
            "in": "query",
            "description": "Optional airport type filter. Without it, closed airfields are left out; type=closed lists them.",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "large_airport",
                "medium_airport",
                "small_airport",
                "heliport",
                "closed",
                "seaplane_base"
              ]
            },
            "example": "large_airport"
          }
        ],
        "responses": {
          "200": {
            "description": "Nearest airports, ascending by distance_km.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearestAirportResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid or missing parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/resolve": {
      "get": {
        "operationId": "resolveReference",
        "summary": "Resolve any freight identifier to typed, ranked, cited candidates",
        "description": "The agent front door: one identifier-ish string in, typed candidates out. 13 grammars all run (UN numbers, AWB prefixes, airline/airport IATA+ICAO, UN/LOCODE, ISO 6346 container numbers with check digit, HS codes, Incoterms, ADR tunnel codes, ULD serials, ISO container types). Envelope v1.1 native.",
        "tags": [
          "Reference Data"
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "One freight identifier (single token, max 32 chars). Collisions return multiple ranked candidates; zero candidates is a valid count:0 result, never an error.",
            "schema": {
              "type": "string",
              "maxLength": 32
            },
            "example": "UN1845"
          }
        ],
        "responses": {
          "200": {
            "description": "Envelope v1.1 (native — always enveloped; ?envelope=1 downgrades to the byte-stable v1 envelope). result carries query, normalized, count and candidates[]; count 0 + note means no grammar matched. A 5-character query one character from a real UN/LOCODE adds did_you_mean[] ({value, label, api_url}).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolveResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing or over-length q — enveloped blocking_errors (MISSING_INPUT / INVALID_INPUT). v1 takes ONE identifier; free-text extraction is out of scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResolveResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message.",
            "example": "Missing required parameter: length"
          }
        },
        "required": [
          "error"
        ]
      },
      "LdmVehicle": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable vehicle name.",
            "example": "13.6m Artic Trailer"
          },
          "length_m": {
            "type": "number",
            "description": "Vehicle loading length in metres.",
            "example": 13.6
          },
          "max_payload_kg": {
            "type": "number",
            "description": "Maximum payload capacity in kilograms.",
            "example": 24000
          }
        },
        "required": [
          "name",
          "length_m",
          "max_payload_kg"
        ]
      },
      "LdmPalletSpaces": {
        "type": "object",
        "properties": {
          "used": {
            "type": "integer",
            "description": "Floor positions the load needs (stacked pallets share a position). For a footprint other than Euro or UK, Euro-pallet equivalents.",
            "example": 10
          },
          "available": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Floor positions the vehicle offers for this pallet standard: the record's own count when its palletCapacityBasis is floor-positions, otherwise derived from its internal length x width (see floor_positions_basis). null for a custom vehicle.",
            "example": 15
          },
          "basis": {
            "type": "string",
            "enum": [
              "euro_floor_positions",
              "uk_floor_positions",
              "euro_pallet_equivalents"
            ],
            "description": "What used and available count.",
            "example": "euro_floor_positions"
          },
          "floor_positions_basis": {
            "type": "string",
            "enum": [
              "record_floor_count",
              "deck_geometry",
              "loading_metre_convention",
              "not_available"
            ],
            "description": "Where available came from: the record's floor count, the deck geometry, the loading-metre convention (no internal width on the record), or not available (custom vehicle).",
            "example": "deck_geometry"
          },
          "floor_positions_note": {
            "type": "string",
            "description": "One sentence on how available was arrived at.",
            "example": "15 Euro (1200 x 800) floor positions from the 6.1 x 2.4 m deck (the better orientation, cross-checked against the loading-metre convention). The record's stored 8 is weight-limited, not a floor count."
          },
          "record_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The vehicle record's stored pallet count for this standard, as stored (it may be weight-limited or unverified rather than a floor count).",
            "example": 8
          },
          "record_count_basis": {
            "type": [
              "string",
              "null"
            ],
            "description": "The record's palletCapacityBasis: floor-positions, weight-limited or unverified.",
            "example": "weight-limited"
          }
        },
        "required": [
          "used",
          "available",
          "basis",
          "floor_positions_basis"
        ]
      },
      "LdmMetaInputs": {
        "type": "object",
        "properties": {
          "length_mm": {
            "type": "number",
            "description": "Pallet length in mm as interpreted.",
            "example": 1200
          },
          "width_mm": {
            "type": "number",
            "description": "Pallet width in mm as interpreted.",
            "example": 800
          },
          "qty": {
            "type": "integer",
            "description": "Number of pallets.",
            "example": 2
          },
          "stackable": {
            "type": "boolean",
            "example": false
          },
          "stack_factor": {
            "type": "integer",
            "example": 2
          },
          "weight_per_pallet_kg": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "vehicle": {
            "type": "string",
            "example": "artic"
          }
        }
      },
      "LdmResponse": {
        "type": "object",
        "properties": {
          "ldm": {
            "type": "number",
            "description": "Calculated loading metres.",
            "example": 0.8
          },
          "vehicle": {
            "$ref": "#/components/schemas/LdmVehicle"
          },
          "utilisation_percent": {
            "type": "number",
            "description": "Percentage of vehicle length used.",
            "example": 5.88
          },
          "pallet_spaces": {
            "$ref": "#/components/schemas/LdmPalletSpaces"
          },
          "total_weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "description": "Total weight of all pallets in kg, or null if weight not provided.",
            "example": null
          },
          "payload_checked": {
            "type": "boolean",
            "description": "true when a weight was given and checked against the vehicle's max payload. false: fits reflects the floor and length only, and warnings[] carries an info note with the payload figure.",
            "example": true
          },
          "fits": {
            "type": "boolean",
            "description": "true only when the load fits the vehicle's length, its floor positions (pallet_spaces.available) and, when a weight is given, its max payload. Each failed constraint is named in warnings[] with its numbers.",
            "example": true
          },
          "warnings": {
            "type": "array",
            "description": "Warnings about the load and the request. Each is an object. A deprecated vehicle id yields warnings[0] with type=info and a message starting DEPRECATED: vehicle=\"<id>\".",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "danger",
                    "warn",
                    "info"
                  ],
                  "description": "danger = the load does not fit or is overweight; warn = close to a limit; info = advisory, including vehicle deprecation."
                },
                "message": {
                  "type": "string",
                  "description": "Human-readable warning text."
                }
              },
              "required": [
                "type",
                "message"
              ]
            },
            "example": []
          },
          "meta": {
            "type": "object",
            "properties": {
              "inputs": {
                "$ref": "#/components/schemas/LdmMetaInputs"
              }
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "ldm",
          "vehicle",
          "utilisation_percent",
          "pallet_spaces",
          "total_weight_kg",
          "fits",
          "warnings",
          "meta"
        ]
      },
      "CbmMetaInputs": {
        "type": "object",
        "properties": {
          "length_cm": {
            "type": "number",
            "example": 120
          },
          "width_cm": {
            "type": "number",
            "example": 80
          },
          "height_cm": {
            "type": "number",
            "example": 100
          },
          "pieces": {
            "type": "integer",
            "example": 2
          }
        }
      },
      "CbmResponse": {
        "type": "object",
        "properties": {
          "cbm_per_piece": {
            "type": "number",
            "description": "Cubic metres per single piece.",
            "example": 0.96
          },
          "total_cbm": {
            "type": "number",
            "description": "Total cubic metres for all pieces.",
            "example": 1.92
          },
          "total_volume_m3": {
            "type": "number",
            "description": "Total volume in cubic metres (same as total_cbm).",
            "example": 1.92
          },
          "cubic_feet": {
            "type": "number",
            "description": "Total volume in cubic feet.",
            "example": 67.8042
          },
          "litres": {
            "type": "number",
            "description": "Total volume in litres.",
            "example": 1920
          },
          "cubic_inches": {
            "type": "number",
            "description": "Total volume in cubic inches.",
            "example": 117165.5
          },
          "pieces": {
            "type": "integer",
            "description": "Number of pieces.",
            "example": 2
          },
          "meta": {
            "type": "object",
            "properties": {
              "inputs": {
                "$ref": "#/components/schemas/CbmMetaInputs"
              }
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "cbm_per_piece",
          "total_cbm",
          "total_volume_m3",
          "cubic_feet",
          "litres",
          "cubic_inches",
          "pieces",
          "meta"
        ]
      },
      "ChargeableWeightMetaInputs": {
        "type": "object",
        "properties": {
          "length_cm": {
            "type": "number",
            "example": 120
          },
          "width_cm": {
            "type": "number",
            "example": 80
          },
          "height_cm": {
            "type": "number",
            "example": 100
          },
          "gross_weight_kg": {
            "type": "number",
            "example": 500
          },
          "pieces": {
            "type": "integer",
            "example": 2
          },
          "factor": {
            "type": "integer",
            "example": 6000
          }
        }
      },
      "ChargeableWeightResponse": {
        "type": "object",
        "properties": {
          "chargeable_weight_kg": {
            "type": "number",
            "description": "The chargeable weight (higher of actual vs volumetric).",
            "example": 500
          },
          "basis": {
            "type": "string",
            "description": "Whether the chargeable weight is based on 'actual' gross weight or 'volumetric' weight.",
            "enum": [
              "actual",
              "volumetric"
            ],
            "example": "actual"
          },
          "gross_weight_kg": {
            "type": "number",
            "description": "Actual gross weight in kg.",
            "example": 500
          },
          "volumetric_weight_kg": {
            "type": "number",
            "description": "Total volumetric weight in kg.",
            "example": 320
          },
          "volumetric_weight_per_piece_kg": {
            "type": "number",
            "description": "Volumetric weight per piece in kg.",
            "example": 160
          },
          "cbm": {
            "type": "number",
            "description": "Total cubic metres.",
            "example": 1.92
          },
          "ratio": {
            "type": "number",
            "description": "Weight-to-volume ratio (kg per CBM).",
            "example": 3.84
          },
          "factor": {
            "type": "integer",
            "description": "Volumetric divisor factor used.",
            "example": 6000
          },
          "pieces": {
            "type": "integer",
            "description": "Number of pieces.",
            "example": 2
          },
          "meta": {
            "type": "object",
            "properties": {
              "inputs": {
                "$ref": "#/components/schemas/ChargeableWeightMetaInputs"
              }
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "chargeable_weight_kg",
          "basis",
          "gross_weight_kg",
          "volumetric_weight_kg",
          "volumetric_weight_per_piece_kg",
          "cbm",
          "ratio",
          "factor",
          "pieces",
          "meta"
        ]
      },
      "PalletFittingMetaInputs": {
        "type": "object",
        "properties": {
          "pallet_length_cm": {
            "type": "number",
            "example": 120
          },
          "pallet_width_cm": {
            "type": "number",
            "example": 80
          },
          "pallet_max_height_cm": {
            "type": "number",
            "example": 220
          },
          "pallet_height_cm": {
            "type": "number",
            "example": 15
          },
          "box_length_cm": {
            "type": "number",
            "example": 40
          },
          "box_width_cm": {
            "type": "number",
            "example": 30
          },
          "box_height_cm": {
            "type": "number",
            "example": 25
          },
          "box_weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "max_payload_weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "example": null
          },
          "allow_rotation": {
            "type": "boolean",
            "example": true
          }
        }
      },
      "PalletFittingResponse": {
        "type": "object",
        "properties": {
          "boxes_per_layer": {
            "type": "integer",
            "description": "Number of boxes fitting in a single layer.",
            "example": 8
          },
          "layers": {
            "type": "integer",
            "description": "Number of layers that fit within the height constraint.",
            "example": 8
          },
          "total_boxes": {
            "type": "integer",
            "description": "Total number of boxes fitting on the pallet.",
            "example": 64
          },
          "orientation": {
            "type": "string",
            "description": "Whether boxes were rotated for best fit.",
            "enum": [
              "standard",
              "rotated"
            ],
            "example": "rotated"
          },
          "boxes_per_row": {
            "type": "integer",
            "description": "Number of boxes per row along the pallet length.",
            "example": 4
          },
          "boxes_per_col": {
            "type": "integer",
            "description": "Number of boxes per column along the pallet width.",
            "example": 2
          },
          "usable_height_cm": {
            "type": "number",
            "description": "Usable stacking height after subtracting deck height.",
            "example": 205
          },
          "utilisation_percent": {
            "type": "number",
            "description": "Volume utilisation percentage.",
            "example": 100
          },
          "total_box_volume_cbm": {
            "type": "number",
            "description": "Total volume of all boxes in CBM.",
            "example": 1.92
          },
          "pallet_volume_cbm": {
            "type": "number",
            "description": "Usable pallet volume in CBM.",
            "example": 1.968
          },
          "wasted_space_cbm": {
            "type": "number",
            "description": "Wasted space in CBM.",
            "example": 0.048
          },
          "weight_limited": {
            "type": "boolean",
            "description": "Whether the result was limited by weight rather than space.",
            "example": false
          },
          "total_weight_kg": {
            "type": [
              "number",
              "null"
            ],
            "description": "Total weight of all boxes, or null if box weight not provided.",
            "example": null
          },
          "remaining_weight_capacity_kg": {
            "type": [
              "number",
              "null"
            ],
            "description": "Remaining weight capacity, or null if not applicable.",
            "example": null
          },
          "meta": {
            "type": "object",
            "properties": {
              "inputs": {
                "$ref": "#/components/schemas/PalletFittingMetaInputs"
              }
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "boxes_per_layer",
          "layers",
          "total_boxes",
          "orientation",
          "boxes_per_row",
          "boxes_per_col",
          "usable_height_cm",
          "utilisation_percent",
          "total_box_volume_cbm",
          "pallet_volume_cbm",
          "wasted_space_cbm",
          "weight_limited",
          "total_weight_kg",
          "remaining_weight_capacity_kg",
          "meta"
        ]
      },
      "AdrSubstance": {
        "type": "object",
        "properties": {
          "un_number": {
            "type": "string",
            "description": "UN number identifying the dangerous goods.",
            "example": "1203"
          },
          "proper_shipping_name": {
            "type": "string",
            "description": "Official ADR proper shipping name.",
            "example": "MOTOR SPIRIT or GASOLINE or PETROL"
          },
          "class": {
            "type": "string",
            "description": "ADR hazard class.",
            "example": "3"
          },
          "classification_code": {
            "type": "string",
            "description": "ADR classification code.",
            "example": "F1"
          },
          "packing_group": {
            "type": "string",
            "description": "Packing group (I, II, or III). Null when the entry has none — including Table A rows flagged not_subject_to_adr or carriage_prohibited.",
            "example": "II"
          },
          "not_subject_to_adr": {
            "type": "boolean",
            "description": "Present and true when ADR 2025 Table A lists the entry as NOT SUBJECT TO ADR — the entry is outside ADR scope (road) and the 1.1.3.6 exemption calculation does not apply. See conditions_ref for carriage conditions that still apply.",
            "example": true
          },
          "carriage_prohibited": {
            "type": "boolean",
            "description": "Present and true when ADR 2025 Table A lists the entry as CARRIAGE PROHIBITED — it may not be carried by road under ADR.",
            "example": true
          },
          "conditions_ref": {
            "type": "string",
            "description": "ADR section whose carriage conditions still apply to a not-subject entry (e.g. 5.5.3 for UN 1845 dry ice: ventilation, warning mark, documentation). Null when no conditions attach.",
            "example": "5.5.3"
          },
          "table_a_remark": {
            "type": "string",
            "description": "Verbatim ADR 2025 Table A column (4) remark for scope-flagged entries.",
            "example": "NOT SUBJECT TO ADR except for 5.5.3"
          },
          "decision_rationale": {
            "type": "string",
            "description": "Data-integrity rationale recorded for this row, where present."
          },
          "labels": {
            "type": "string",
            "description": "Required hazard labels.",
            "example": "3"
          },
          "special_provisions": {
            "type": "string",
            "description": "Applicable special provisions.",
            "example": "243 534 664"
          },
          "limited_quantity": {
            "type": "string",
            "description": "Limited quantity allowance.",
            "example": "1 L"
          },
          "excepted_quantity": {
            "type": "string",
            "description": "Excepted quantity code.",
            "example": "E2"
          },
          "transport_category": {
            "type": "string",
            "description": "Transport category for 1.1.3.6 exemption (0-4).",
            "example": "2"
          },
          "tunnel_restriction_code": {
            "type": "string",
            "description": "Tunnel restriction code.",
            "example": "(D/E)"
          },
          "hazard_identification_number": {
            "type": "string",
            "description": "Kemler/HIN code for orange plates.",
            "example": "33"
          },
          "variant_index": {
            "type": "integer",
            "description": "Index of this variant (0-based) when a UN number has multiple entries.",
            "example": 0
          },
          "variant_count": {
            "type": "integer",
            "description": "Total number of variants for this UN number.",
            "example": 1
          },
          "verified": {
            "description": "Per-row verification state, ALWAYS present. true (or \"partial\") only when this row carries a row-level audit in the dataset; false otherwise. Silence is never verification.",
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "string",
                "enum": [
                  "partial"
                ]
              }
            ],
            "example": false
          },
          "verification": {
            "type": "object",
            "description": "Why `verified` says what it says. status verified/partial = a row-level audit (basis row: audited_at + cited source count); status unverified = no row-level audit, the row is transcribed from the UNECE ADR 2025 Table A and held by the dataset-level checks only (basis dataset).",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "verified",
                  "partial",
                  "unverified"
                ],
                "example": "unverified"
              },
              "basis": {
                "type": "string",
                "enum": [
                  "row",
                  "dataset"
                ],
                "example": "dataset"
              },
              "reason": {
                "type": "string",
                "example": "No row-level audit. Transcribed from the UNECE ADR 2025 Table A and held by the dataset-level checks only (56 anchor rows carry a row-level audit)."
              },
              "audited_at": {
                "type": "string",
                "description": "ISO date of the row-level audit. Present only with status verified/partial.",
                "example": "2026-08-26"
              },
              "sources": {
                "type": "integer",
                "description": "Number of cited sources on the row-level audit. Present only with status verified/partial.",
                "example": 2
              }
            },
            "required": [
              "status",
              "basis",
              "reason"
            ]
          },
          "audited_at": {
            "type": "string",
            "description": "ISO date of the row-level audit. Present only on audited rows.",
            "example": "2026-08-26"
          },
          "sources": {
            "type": "array",
            "description": "The row-level audit's cited sources. Present only on audited rows.",
            "items": {
              "type": "object"
            }
          }
        },
        "required": [
          "un_number",
          "proper_shipping_name",
          "class",
          "classification_code",
          "packing_group",
          "labels",
          "special_provisions",
          "limited_quantity",
          "excepted_quantity",
          "transport_category",
          "tunnel_restriction_code",
          "hazard_identification_number",
          "variant_index",
          "variant_count",
          "verified",
          "verification"
        ]
      },
      "AdrLookupResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of matching results.",
            "example": 1
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdrSubstance"
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "count",
          "results"
        ]
      },
      "AdrCalculatorRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "description": "Array of dangerous goods items to calculate.",
            "items": {
              "type": "object",
              "properties": {
                "un_number": {
                  "type": "string",
                  "description": "UN number of the substance — or an ID-prefixed air-only number (e.g. ID8000), routed AIR_ONLY_ID with nothing counted — the ADR answer for limited-quantity packages to the ICAO TI (3.4.9, 3.4.10, 1.1.3.6.5), as the line's warning states.",
                  "example": "1203"
                },
                "quantity": {
                  "type": "number",
                  "exclusiveMinimum": 0,
                  "description": "Quantity of the dangerous goods in kg or litres, as a JSON number > 0 and ≤ 1e9. Text (\"300 kg\"), null, 0 or a negative value is refused with a 400 — never scored.",
                  "example": 200,
                  "maximum": 1000000000
                },
                "packing_group": {
                  "type": "string",
                  "enum": [
                    "I",
                    "II",
                    "III"
                  ],
                  "description": "Packing group — only needed for a UN number with more than one ADR Table A row (e.g. UN 1789); ignored for single-row UNs. Without it that line is withheld while its siblings are answered. Enough alone when the rows it leaves agree on the verdict fields (UN 1790 PG I)."
                },
                "variant_index": {
                  "type": "integer",
                  "minimum": 0,
                  "description": "ADR Table A variant index (as returned by /api/adr) — pins one row when a UN number has several variants sharing a packing group (concentration bands). Ignored for single-row UN numbers. A JSON integer; anything else is a 400."
                },
                "unit": {
                  "type": "string",
                  "enum": [
                    "L",
                    "kg"
                  ],
                  "description": "OPTIONAL dimension of quantity, checked against the 1.1.3.6.3 basis for the row. Case-insensitive; any other value is a 400."
                },
                "basis": {
                  "type": "string",
                  "enum": [
                    "net",
                    "gross"
                  ],
                  "description": "OPTIONAL. A figure declared gross returns no points in any unit — send the net quantity. Any other value is a 400."
                }
              },
              "required": [
                "un_number",
                "quantity"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "items"
        ],
        "description": "items[] carries every line. Any single-substance field — un_number, quantity, packing_group, variant_index, unit, basis (or un / qty) — sent at the top level beside items[] is refused with HTTP 400 naming it: never dropped, never applied to a line by guess.",
        "additionalProperties": false
      },
      "AdrCalculatorItem": {
        "type": "object",
        "properties": {
          "un_number": {
            "type": "string",
            "description": "UN number of the substance — or, on an air-only line, the canonical ID number (e.g. ID8000).",
            "example": "1203"
          },
          "state": {
            "type": "string",
            "enum": [
              "COUNTED",
              "AIR_ONLY_ID",
              "NOT_SUBJECT_TO_ADR",
              "BLOCKED"
            ],
            "description": "The line's route, in the document check's words: COUNTED (evaluated on one Table A row), AIR_ONLY_ID (ID-prefixed, no Table A entry, nothing counted — its warning states the limited-quantity condition), NOT_SUBJECT_TO_ADR, BLOCKED (no points from the line as sent).",
            "example": "COUNTED"
          },
          "proper_shipping_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Official ADR proper shipping name. Null on a withheld line (no row was pinned — never the first row's name).",
            "example": "MOTOR SPIRIT or GASOLINE or PETROL"
          },
          "class": {
            "type": [
              "string",
              "null"
            ],
            "description": "ADR hazard class. Null on a withheld line whose candidate rows differ in class.",
            "example": "3"
          },
          "transport_category": {
            "type": [
              "string",
              "null"
            ],
            "description": "Transport category (0-4). Null on a withheld line.",
            "example": "2"
          },
          "packing_group": {
            "type": [
              "string",
              "null"
            ],
            "description": "The resolved ADR Table A packing group for this row (echoed so a multi-variant resolution is traceable). On a withheld line: the packing group the caller supplied, or null.",
            "example": "II"
          },
          "variant_index": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The resolved ADR Table A variant index for this row. Null on a withheld line.",
            "example": 0
          },
          "quantity": {
            "type": "number",
            "description": "Quantity being transported.",
            "example": 200
          },
          "multiplier": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Points multiplier for this transport category. Null for out-of-scope rows (not_subject_to_adr / carriage_prohibited) and withheld lines — they never enter the points math.",
            "example": 3
          },
          "points": {
            "type": [
              "number",
              "null"
            ],
            "description": "Calculated points (quantity x multiplier). Null for out-of-scope rows, basis mismatches and withheld lines.",
            "example": 600
          },
          "quantity_unit": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "L",
              "kg",
              null
            ],
            "description": "Echo of the unit the caller declared (null when none was declared)."
          },
          "quantity_basis": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "net",
              "gross",
              null
            ],
            "description": "Echo of the basis the caller declared (null when none was declared)."
          },
          "expected_unit": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "L",
              "kg",
              null
            ],
            "description": "The dimension ADR 1.1.3.6.3 counts this row in — L for liquids and compressed gases, kg for solids, liquefied/refrigerated/dissolved gases and articles; null when the row does not pin one."
          },
          "basis_mismatch": {
            "type": "boolean",
            "description": "Present and true when the declared unit or basis cannot be a 1.1.3.6.3 quantity for this row. The line never enters the points math; total_points and exempt are null (unless the load is already settled by other lines).",
            "example": true
          },
          "category_unresolved": {
            "type": "boolean",
            "description": "Present and true when the row carries no transport category in Table A column (15) — a dash (e.g. UN 3166) or 'See SP 671' (UN 3316 kits): no 1.1.3.6 multiplier, so points, total_points and exempt are null and a warning names the column value.",
            "example": true
          },
          "withheld": {
            "type": "boolean",
            "description": "Present and true when this line's UN resolves to more than one ADR Table A row and nothing pinned one. Row fields are null; the candidate rows sit under the response's candidates[] tagged with this line's item_index. total_points and exempt are null while any line is withheld.",
            "example": true
          },
          "ambiguity_reason": {
            "type": "string",
            "enum": [
              "multiple_variants",
              "packing_group_collision",
              "no_matching_variant"
            ],
            "description": "Why the withheld line could not be pinned. Present only with withheld."
          },
          "equivalent_variants": {
            "type": "array",
            "description": "Present when the supplied packing_group left several Table A rows that agree on class, transport category, scope and the 1.1.3.6.3 counted dimension: the rows this verdict holds for. The row fields above are the first one's.",
            "items": {
              "type": "object",
              "properties": {
                "variant_index": {
                  "type": "integer",
                  "example": 1
                },
                "proper_shipping_name": {
                  "type": "string"
                }
              }
            }
          },
          "variant_note": {
            "type": "string",
            "description": "Plain-language statement of the equivalence: which rows, which fields they share, whose fields are shown. Present only with equivalent_variants."
          },
          "not_subject_to_adr": {
            "type": "boolean",
            "description": "Present and true when this row is NOT SUBJECT TO ADR (Table A) — excluded from the 1.1.3.6 calculation.",
            "example": true
          },
          "carriage_prohibited": {
            "type": "boolean",
            "description": "Present and true when this row is CARRIAGE PROHIBITED (Table A) — the load cannot be carried by road under ADR.",
            "example": true
          },
          "conditions_ref": {
            "type": "string",
            "description": "ADR section whose carriage conditions still apply to a not-subject row (e.g. 5.5.3).",
            "example": "5.5.3"
          },
          "air_only_id": {
            "type": "boolean",
            "description": "Present and true on an ID-prefixed air-only line: no ADR Table A entry, row fields null, never in the points — the ADR answer for limited-quantity packages to the ICAO TI (3.4.9, 3.4.10, 1.1.3.6.5), stated in the warning. Never not_subject_to_adr.",
            "example": true
          }
        },
        "required": [
          "un_number",
          "state",
          "proper_shipping_name",
          "class",
          "transport_category",
          "quantity",
          "multiplier",
          "points"
        ]
      },
      "AdrCalculatorResponse": {
        "type": "object",
        "properties": {
          "blocking_errors": {
            "type": "array",
            "description": "Present only on the all-ambiguous 200 (no verdict): [{ code: AMBIGUOUS_UN_VARIANT, message, recovery }], in the plain body too. recovery.params never pick a row (sent unchanged: asked again); pick from candidates[] by packing group, concentration or description; send packing_group or variant_index.",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "example": "AMBIGUOUS_UN_VARIANT"
                },
                "message": {
                  "type": "string"
                },
                "recovery": {
                  "type": "object"
                }
              }
            }
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdrCalculatorItem"
            }
          },
          "total_points": {
            "type": [
              "number",
              "null"
            ],
            "description": "Sum of all item points. Null when no load verdict was reached — a line is withheld (items[].withheld), declared on a basis 1.1.3.6.3 does not count (items[].basis_mismatch), or carries no transport category in Table A column (15) (items[].category_unresolved).",
            "example": 600
          },
          "threshold": {
            "type": "integer",
            "description": "1.1.3.6 threshold (always 1000).",
            "example": 1000
          },
          "exempt": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Whether the shipment qualifies for 1.1.3.6 exemption. Null when no load verdict was reached, never false as a stand-in. false with total_points null = already NOT exempt on the resolved lines (carriage prohibited, category 0, a maximum exceeded, or a partial sum over 1,000) while a line is withheld.",
            "example": true
          },
          "has_category_zero": {
            "type": "boolean",
            "description": "Whether any item is transport category 0 (never exempt).",
            "example": false
          },
          "has_quantity_exceedance": {
            "type": "boolean",
            "description": "Whether any single item exceeds its maximum quantity per transport unit.",
            "example": false
          },
          "warnings": {
            "type": "array",
            "description": "Any warnings about the calculation.",
            "items": {
              "type": "string"
            },
            "example": []
          },
          "message": {
            "type": "string",
            "description": "Human-readable verdict. For loads whose entries are outside ADR scope this is a dedicated scope verdict (e.g. 'Not subject to ADR (road). Section 5.5.3 applies: ...' or 'Carriage prohibited by ADR (road). ...'), never a 1.1.3.6 claim.",
            "example": "1.1.3.6 exemption applies"
          },
          "not_subject_to_adr": {
            "type": "boolean",
            "description": "Present and true when EVERY item in the load is NOT SUBJECT TO ADR (Table A) — the 1.1.3.6 calculation was not applied.",
            "example": true
          },
          "conditions_ref": {
            "type": "string",
            "description": "ADR section whose carriage conditions still apply to a not-subject load (e.g. 5.5.3 for dry ice).",
            "example": "5.5.3"
          },
          "conditions": {
            "type": "array",
            "description": "Verbatim ADR 2025 carriage conditions for conditions_ref (e.g. section 5.5.3: ventilation, package marking, vehicle warning mark, documentation, unpackaged dry ice, training).",
            "items": {
              "type": "object",
              "properties": {
                "ref": {
                  "type": "string",
                  "description": "ADR 2025 subsection.",
                  "example": "5.5.3.3.3"
                },
                "heading": {
                  "type": "string",
                  "description": "Short practitioner-facing heading.",
                  "example": "Ventilation"
                },
                "requirement": {
                  "type": "string",
                  "description": "Verbatim requirement text from ADR 2025."
                },
                "note": {
                  "type": "string",
                  "description": "Verbatim accompanying note/example from ADR 2025, where one exists."
                }
              },
              "required": [
                "ref",
                "heading",
                "requirement"
              ]
            }
          },
          "carriage_prohibited": {
            "type": "boolean",
            "description": "Present and true when the load contains a CARRIAGE PROHIBITED Table A entry — exempt is false and the load may not be carried by road under ADR, whether or not another line is withheld.",
            "example": true
          },
          "human_review_required": {
            "type": "boolean",
            "description": "Present and true when at least one line is withheld for an unpinned multi-variant UN. candidates[] then lists that line's rows.",
            "example": true
          },
          "candidates": {
            "type": "array",
            "description": "The withheld lines' candidate Table A rows, each tagged with the item_index and un_number of the line it belongs to. Present only with human_review_required.",
            "items": {
              "type": "object",
              "properties": {
                "item_index": {
                  "type": "integer",
                  "example": 1
                },
                "un_number": {
                  "type": "string",
                  "example": "1789"
                },
                "variant_index": {
                  "type": "integer",
                  "example": 0
                },
                "packing_group": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "II"
                },
                "proper_shipping_name": {
                  "type": "string"
                },
                "transport_category": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "example": "2"
                },
                "multiplier": {
                  "type": [
                    "integer",
                    "null"
                  ],
                  "example": 3
                },
                "expected_unit": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "enum": [
                    "L",
                    "kg",
                    null
                  ],
                  "description": "The 1.1.3.6.3 counted dimension of the candidate row — the only difference between two candidates when a packing group collides on state alone (UN 3375 PG II: liquid in L, solid in kg)."
                }
              }
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "items",
          "total_points",
          "threshold",
          "exempt",
          "has_category_zero",
          "has_quantity_exceedance",
          "warnings",
          "message"
        ]
      },
      "Airline": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "description": "URL-friendly airline identifier.",
            "example": "emirates"
          },
          "airline_name": {
            "type": "string",
            "description": "Full airline name.",
            "example": "Emirates"
          },
          "iata_code": {
            "type": "string",
            "description": "2-character IATA airline designator.",
            "example": "EK"
          },
          "icao_code": {
            "type": "string",
            "description": "3-character ICAO airline designator.",
            "example": "UAE"
          },
          "awb_prefix": {
            "type": "array",
            "description": "3-digit Air Waybill prefix number(s).",
            "items": {
              "type": "string"
            },
            "example": [
              "176"
            ]
          },
          "callsign": {
            "type": "string",
            "description": "Radio telephony callsign.",
            "example": "EMIRATES"
          },
          "country": {
            "type": "string",
            "description": "Country of registration.",
            "example": "United Arab Emirates"
          },
          "has_cargo": {
            "type": "boolean",
            "description": "Whether the airline operates cargo services.",
            "example": true
          },
          "aliases": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Alternative names (e.g. cargo division name).",
            "example": [
              "Emirates SkyCargo"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active_verified",
              "historical",
              "unverified"
            ],
            "description": "Per-record verification status. active_verified: every served identifier confirmed against carrier-published pages (ICAO/callsign via FAA JO 7340.2), cited in field_provenance. historical: ceased operating, codes kept as fact. unverified: audited, not cleared. Absent = never audited.",
            "example": "active_verified"
          },
          "status_checked_at": {
            "type": "string",
            "format": "date",
            "description": "ISO date the verification status was last established. Absent when `status` is absent.",
            "example": "2026-08-11"
          },
          "data_note": {
            "type": "string",
            "description": "Plain-language caveat about this record's evidence, when one applies (e.g. why it is held at unverified)."
          },
          "field_provenance": {
            "type": "object",
            "description": "Per-FIELD source citations — the evidence active_verified rests on. Keys are field names (iata_code, icao_code, awb_prefix, callsign, operating_status); values are the sources confirming that field. Aggregators score zero and never appear.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "publisher": {
                    "type": "string"
                  },
                  "accessed_at": {
                    "type": "string",
                    "format": "date"
                  }
                },
                "required": [
                  "url",
                  "accessed_at"
                ]
              }
            }
          },
          "sources": {
            "type": "array",
            "description": "Record-level union of the per-field citations.",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "accessed_at": {
                  "type": "string",
                  "format": "date"
                }
              },
              "required": [
                "url",
                "accessed_at"
              ]
            }
          },
          "verified": {
            "type": "boolean",
            "deprecated": true,
            "description": "DEPRECATED — computed mirror of status==='active_verified', kept for one release. ABSENT (not false) on never-audited records, because false would assert a check that never happened. Read status instead.",
            "example": true
          }
        },
        "required": [
          "slug",
          "airline_name",
          "iata_code",
          "icao_code",
          "awb_prefix",
          "callsign",
          "country",
          "has_cargo"
        ]
      },
      "AirlinesResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of matching results.",
            "example": 1
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Airline"
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "count",
          "results"
        ]
      },
      "IncotermDetail": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "INCOTERM code.",
            "example": "FOB"
          },
          "name": {
            "type": "string",
            "description": "Full INCOTERM name.",
            "example": "Free on Board"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier.",
            "example": "fob-free-on-board"
          },
          "category": {
            "type": "string",
            "description": "Transport mode category.",
            "enum": [
              "any_mode",
              "sea_only"
            ],
            "example": "sea_only"
          },
          "summary": {
            "type": "string",
            "description": "Brief summary of the term."
          },
          "seller_responsibility": {
            "type": "string",
            "description": "What the seller is responsible for."
          },
          "buyer_responsibility": {
            "type": "string",
            "description": "What the buyer is responsible for."
          },
          "risk_transfer": {
            "type": "string",
            "description": "Point at which risk transfers from seller to buyer."
          },
          "cost_transfer": {
            "type": "string",
            "description": "Point at which cost responsibility transfers."
          },
          "insurance": {
            "type": "string",
            "description": "Insurance obligations."
          },
          "export_clearance": {
            "type": "string",
            "description": "Who handles export customs clearance."
          },
          "import_clearance": {
            "type": "string",
            "description": "Who handles import customs clearance."
          },
          "best_for": {
            "type": "string",
            "description": "Scenarios this term is best suited for."
          },
          "watch_out": {
            "type": "string",
            "description": "Common pitfalls or things to be aware of."
          }
        },
        "required": [
          "code",
          "name",
          "slug",
          "category",
          "summary",
          "seller_responsibility",
          "buyer_responsibility",
          "risk_transfer",
          "cost_transfer",
          "insurance",
          "export_clearance",
          "import_clearance",
          "best_for",
          "watch_out"
        ]
      },
      "IncotermsListResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of INCOTERMS returned.",
            "example": 11
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IncotermDetail"
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "count",
          "results"
        ]
      },
      "ContainerSpec": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Container type name.",
            "example": "40ft High Cube"
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly identifier.",
            "example": "40ft-high-cube"
          },
          "internal_length_cm": {
            "type": "number",
            "description": "Internal length in cm.",
            "example": 1203
          },
          "internal_width_cm": {
            "type": "number",
            "description": "Internal width in cm.",
            "example": 235
          },
          "internal_height_cm": {
            "type": [
              "number",
              "null"
            ],
            "description": "Internal height in cm. NULL on open decks (flat racks) — no roof, so no bounding height. Read height_basis to learn what a null means. Never 0: a zero here would make a length x width x height calculation return zero volume.",
            "example": 269
          },
          "external_length_cm": {
            "type": "number",
            "description": "External length in cm.",
            "example": 1219
          },
          "external_width_cm": {
            "type": "number",
            "description": "External width in cm.",
            "example": 244
          },
          "external_height_cm": {
            "type": "number",
            "description": "External height in cm.",
            "example": 290
          },
          "door_width_cm": {
            "type": [
              "number",
              "null"
            ],
            "description": "Door opening width in cm.",
            "example": 234
          },
          "door_height_cm": {
            "type": [
              "number",
              "null"
            ],
            "description": "Door opening height in cm.",
            "example": 263
          },
          "capacity_cbm": {
            "type": [
              "number",
              "null"
            ],
            "description": "Internal volume in CBM. NULL on open decks (flat racks), which have no roof and no side walls and therefore no cubic capacity — read capacity_basis, and use deck_area_sqm instead. Never 0.",
            "example": 76.2
          },
          "tare_weightKg": {
            "type": "number",
            "description": "Empty container weight in kg.",
            "example": 3900
          },
          "max_gross_kg": {
            "type": "number",
            "description": "Maximum gross weight in kg.",
            "example": 30480
          },
          "max_payload_kg": {
            "type": "number",
            "description": "Maximum cargo weight in kg.",
            "example": 26580
          },
          "euro_pallets": {
            "type": "string",
            "deprecated": true,
            "description": "DEPRECATED — use euro_pallets_min / euro_pallets_max. A string, and sometimes an EN-DASH range such as \"23–24\", so Number() returns NaN and parseInt() silently discards the upper bound. Kept unchanged for back-compat and now derived from the numeric pair. Will be removed in a future major version.",
            "example": "23–24"
          },
          "gma_pallets": {
            "type": "string",
            "deprecated": true,
            "description": "DEPRECATED — use gma_pallets_min / gma_pallets_max. A numeric value stored as a string. Kept unchanged for back-compat and now derived from the numeric pair. Will be removed in a future major version.",
            "example": "20"
          },
          "euro_pallets_min": {
            "type": "integer",
            "description": "EUR pallets (1200x800mm) that fit — the conservative figure. Always numeric. Replaces euro_pallets.",
            "example": 23
          },
          "euro_pallets_max": {
            "type": "integer",
            "nullable": true,
            "description": "Upper bound when the achievable EUR-pallet count is genuinely a range (depends on overhang tolerance and whether the last row is turned). Null when the figure is exact.",
            "example": 24
          },
          "gma_pallets_min": {
            "type": "integer",
            "description": "GMA pallets (48x40in) that fit — the conservative figure. Always numeric. Replaces gma_pallets.",
            "example": 20
          },
          "gma_pallets_max": {
            "type": "integer",
            "nullable": true,
            "description": "Upper bound when the GMA-pallet count is a range; null when exact.",
            "example": null
          },
          "deck_area_sqm": {
            "type": "number",
            "nullable": true,
            "description": "Deck area in m² — the meaningful capacity figure for an open deck (flat racks), where a cubic capacity does not exist. Null on enclosed containers.",
            "example": 13.64
          },
          "pallet_capacity_basis": {
            "type": "string",
            "enum": [
              "floor-positions",
              "weight-limited",
              "industry-convention",
              "unverified"
            ],
            "description": "Which constraint the pallet counts express. Container counts are 'industry-convention' because published figures assume a pinwheel load and exceed an aligned-row tiling of the same floor.",
            "example": "industry-convention"
          },
          "height_basis": {
            "type": "string",
            "enum": [
              "unbounded-open-top",
              "constrained-removable-roof",
              "varies-by-configuration",
              "unverified"
            ],
            "description": "What internal_height_cm means, INCLUDING what a null means. 'unbounded-open-top' = no roof, so no height constraint exists (flat racks; height is null). 'constrained-removable-roof' = a real roof-fitted height on a unit whose roof comes off (open tops). Never infer this from open_top.",
            "example": "unbounded-open-top"
          },
          "open_top": {
            "type": "boolean",
            "description": "Affirmative physical fact: the unit has no fixed roof. NOT the discriminator for what a null height means — read height_basis for that.",
            "example": true
          },
          "capacity_basis": {
            "type": "string",
            "enum": [
              "carrier-published",
              "computed-from-internal-dimensions",
              "not-applicable-open-deck",
              "unverified"
            ],
            "description": "What capacity_cbm is. Carrier-published capacities do NOT equal length x width x height, so an agent computing volume from dimensions and an agent reading capacity_cbm will differ; this says which figure is held. 'not-applicable-open-deck' means capacity_cbm is null because the unit is unbounded.",
            "example": "carrier-published"
          },
          "max_gross_basis": {
            "type": "string",
            "enum": [
              "carrier-published",
              "iso-668-series-1",
              "unverified"
            ],
            "description": "Which authority max_gross_kg comes from. 'iso-668-series-1' is a regulatory ceiling and is frequently LOWER than what carriers actually operate — where it applies, max_payload_kg (derived as max gross minus tare) understates usable payload.",
            "example": "iso-668-series-1"
          },
          "description": {
            "type": "string",
            "description": "Container description."
          },
          "notes": {
            "type": "string",
            "description": "Usage notes."
          }
        },
        "required": [
          "name",
          "slug",
          "internal_length_cm",
          "internal_width_cm",
          "internal_height_cm",
          "capacity_cbm",
          "tare_weightKg",
          "max_gross_kg",
          "max_payload_kg",
          "euro_pallets",
          "gma_pallets",
          "euro_pallets_min",
          "gma_pallets_min",
          "pallet_capacity_basis",
          "height_basis",
          "open_top",
          "capacity_basis",
          "max_gross_basis"
        ]
      },
      "ContainerListResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of containers.",
            "example": 10
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContainerSpec"
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "count",
          "results"
        ]
      },
      "ContainerLoadingResponse": {
        "type": "object",
        "properties": {
          "container": {
            "$ref": "#/components/schemas/ContainerSpec"
          },
          "loading": {
            "type": "object",
            "properties": {
              "fits_lengthwise": {
                "type": "integer",
                "description": "Items fitting along the length."
              },
              "fits_widthwise": {
                "type": "integer",
                "description": "Items fitting along the width."
              },
              "fits_height": {
                "type": "integer",
                "description": "Items fitting in height."
              },
              "max_items": {
                "type": "integer",
                "description": "Maximum items that physically fit."
              },
              "requested_qty": {
                "type": "integer",
                "description": "Quantity requested."
              },
              "fits": {
                "type": "boolean",
                "description": "Whether all requested items fit."
              },
              "total_weight_kg": {
                "type": "number",
                "description": "Total weight of loaded items."
              },
              "within_payload": {
                "type": "boolean",
                "description": "Whether total weight is within payload limit."
              },
              "utilisation_percent": {
                "type": "number",
                "description": "Volume utilisation percentage."
              }
            }
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "container",
          "loading"
        ]
      },
      "ConversionResult": {
        "type": "object",
        "properties": {
          "input": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Input value.",
                "example": 100
              },
              "unit": {
                "type": "string",
                "description": "Input unit code.",
                "example": "kg"
              },
              "name": {
                "type": "string",
                "description": "Input unit name.",
                "example": "Kilograms"
              }
            },
            "required": [
              "value",
              "unit",
              "name"
            ]
          },
          "result": {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "description": "Converted value.",
                "example": 220.462
              },
              "unit": {
                "type": "string",
                "description": "Output unit code.",
                "example": "lbs"
              },
              "name": {
                "type": "string",
                "description": "Output unit name.",
                "example": "Pounds"
              }
            },
            "required": [
              "value",
              "unit",
              "name"
            ]
          },
          "formula": {
            "type": "string",
            "description": "Human-readable conversion formula.",
            "example": "Kilograms × 2.20462 = Pounds"
          },
          "note": {
            "type": "string",
            "description": "Additional context for freight-specific conversions."
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "input",
          "result",
          "formula"
        ]
      },
      "HsCode": {
        "type": "object",
        "properties": {
          "hscode": {
            "type": "string",
            "description": "HS code (2, 4, or 6 digits).",
            "example": "0901"
          },
          "description": {
            "type": "string",
            "description": "Product description.",
            "example": "Coffee, whether or not roasted or decaffeinated"
          },
          "level": {
            "type": "integer",
            "description": "Hierarchy level: 2=chapter, 4=heading, 6=subheading.",
            "example": 4
          },
          "parent": {
            "type": "string",
            "description": "Parent code or TOTAL for chapters.",
            "example": "09"
          },
          "section": {
            "type": "string",
            "description": "Section Roman numeral.",
            "example": "II"
          }
        },
        "required": [
          "hscode",
          "description",
          "level",
          "parent",
          "section"
        ]
      },
      "HsCodeDetail": {
        "type": "object",
        "properties": {
          "hscode": {
            "type": "string",
            "example": "090111"
          },
          "description": {
            "type": "string",
            "example": "Coffee; not roasted, not decaffeinated"
          },
          "level": {
            "type": "integer",
            "example": 6
          },
          "parent": {
            "type": "string",
            "example": "0901"
          },
          "section": {
            "type": "string",
            "example": "II"
          },
          "ancestors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HsCode"
            }
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HsCode"
            }
          },
          "sectionName": {
            "type": "string",
            "example": "Vegetable products"
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "hscode",
          "description",
          "level",
          "parent",
          "section",
          "ancestors",
          "children",
          "sectionName"
        ]
      },
      "HsSearchResponse": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "example": "coffee"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HsCode"
            }
          },
          "count": {
            "type": "integer",
            "example": 12
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          },
          "matched_via": {
            "type": "object",
            "description": "Present only when the HS 2022 descriptions found nothing and HMRC's UK Trade Tariff search references named the code(s).",
            "properties": {
              "source": {
                "type": "string",
                "example": "UK Trade Tariff search references (HMRC)"
              },
              "url": {
                "type": "string",
                "example": "https://www.trade-tariff.service.gov.uk/search?q=laptop"
              },
              "matches": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "tariff_code": {
                      "type": "string",
                      "example": "8471300000",
                      "description": "The tariff line HMRC names."
                    },
                    "reference": {
                      "type": "string",
                      "description": "HMRC's reference title, when the search returns one."
                    },
                    "hscode": {
                      "type": "string",
                      "example": "847130",
                      "description": "The code in this dataset the line falls under."
                    }
                  },
                  "required": [
                    "tariff_code",
                    "hscode"
                  ]
                }
              }
            },
            "required": [
              "source",
              "url",
              "matches"
            ]
          }
        },
        "required": [
          "query",
          "results",
          "count"
        ]
      },
      "HsSectionResponse": {
        "type": "object",
        "properties": {
          "section": {
            "type": "object",
            "properties": {
              "numeral": {
                "type": "string",
                "example": "ii"
              },
              "name": {
                "type": "string",
                "example": "Vegetable products"
              }
            }
          },
          "chapters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HsCode"
            }
          },
          "count": {
            "type": "integer",
            "example": 14
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "section",
          "chapters",
          "count"
        ]
      },
      "SourceEnvelope": {
        "type": "object",
        "description": "Additive provenance citation for the dataset or method behind this response, from FreightUtils' single provenance source of truth. Shapes: reference, methodology (calculators), or reference with provenance_status:'pending-verification'. Fields appear only when a real value exists.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "reference",
              "methodology"
            ]
          },
          "authority": {
            "type": "string"
          },
          "dataset": {
            "type": "string"
          },
          "source_url": {
            "type": "string"
          },
          "data_vintage": {
            "type": "string"
          },
          "licence": {
            "type": "string"
          },
          "retrieved_via": {
            "type": "string"
          },
          "standard": {
            "type": "string"
          },
          "reference": {
            "type": "string"
          },
          "computed_by": {
            "type": "string"
          },
          "provenance_status": {
            "type": "string",
            "enum": [
              "pending-verification"
            ]
          },
          "dataset_edition": {
            "type": "string",
            "description": "Edition this response is served from (editioned reference datasets only), e.g. 'UN/LOCODE 2025-1'."
          },
          "authority_current_edition": {
            "type": "string",
            "description": "The authority's current in-force edition at the last check. Differs from dataset_edition only when the served data lags the authority."
          },
          "checked_at": {
            "type": "string",
            "description": "YYYY-MM-DD of the last served-vs-authority edition comparison (on-demand checker, staleness-guarded)."
          }
        },
        "required": [
          "type"
        ]
      },
      "EmissionsResponse": {
        "type": "object",
        "description": "Freight emissions result. available:true carries inputs/tonne_km/factor/emissions/_source; available:false carries message/available_for. methodology + disclaimer are always present.",
        "properties": {
          "available": {
            "type": "boolean"
          },
          "methodology": {
            "type": "string"
          },
          "disclaimer": {
            "type": "string"
          },
          "inputs": {
            "type": "object",
            "properties": {
              "mass": {
                "type": "number"
              },
              "mass_unit": {
                "type": "string"
              },
              "mass_tonnes": {
                "type": "number"
              },
              "distance_km": {
                "type": "number"
              },
              "mode": {
                "type": "string"
              },
              "sub_mode": {
                "type": "string"
              },
              "region": {
                "type": "string"
              },
              "basis": {
                "type": "string"
              }
            }
          },
          "tonne_km": {
            "type": "number"
          },
          "factor": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "mode": {
                "type": "string"
              },
              "sub_mode": {
                "type": "string"
              },
              "authority": {
                "type": "string"
              },
              "edition": {
                "type": "string"
              },
              "region": {
                "type": "string"
              },
              "unit": {
                "type": "string"
              },
              "wtw": {
                "type": "number",
                "nullable": true
              },
              "ttw": {
                "type": "number",
                "nullable": true
              }
            }
          },
          "emissions": {
            "type": "object",
            "properties": {
              "wtw_kgco2e": {
                "type": "number",
                "nullable": true
              },
              "ttw_kgco2e": {
                "type": "number",
                "nullable": true
              },
              "primary_kgco2e": {
                "type": "number"
              },
              "basis_used": {
                "type": "string"
              }
            }
          },
          "summary": {
            "type": "string",
            "description": "Primary human-readable one-line result — carries the empty-running + actual-gross-mass notes and, for sea/air, a high-variance warning."
          },
          "mass_basis": {
            "type": "string",
            "description": "Mass basis the factor expects: always \"actual_gross_mass\" — not chargeable/volumetric weight."
          },
          "empty_running": {
            "type": "string",
            "description": "\"sector_average_included\" (fleet-average empty running already in the factor — do not add your own empty-return leg) or \"see_source\"."
          },
          "representativeness": {
            "type": "string",
            "description": "\"low\" for sea/air (high real-world variance by vessel/aircraft type, load, routing); \"medium\" for road/rail/inland."
          },
          "confidence": {
            "type": "string",
            "description": "Human-readable confidence label for representativeness."
          },
          "_source": {
            "type": "object",
            "description": "Citability envelope: ISO method + the exact open factor used.",
            "properties": {
              "type": {
                "type": "string"
              },
              "standard": {
                "type": "string"
              },
              "reference": {
                "type": "string"
              },
              "source_url": {
                "type": "string"
              },
              "computed_by": {
                "type": "string"
              },
              "factor": {
                "type": "object",
                "properties": {
                  "authority": {
                    "type": "string"
                  },
                  "edition": {
                    "type": "string"
                  },
                  "value": {
                    "type": "number"
                  },
                  "unit": {
                    "type": "string"
                  },
                  "basis": {
                    "type": "string"
                  },
                  "last_verified": {
                    "type": "string",
                    "description": "Date the factor was last verified against its cited source (YYYY-MM-DD)."
                  },
                  "source_url": {
                    "type": "string"
                  },
                  "licence": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "message": {
            "type": "string"
          },
          "available_for": {
            "type": "object",
            "properties": {
              "modes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "regions_for_mode": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "sub_modes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "region": {
                      "type": "string"
                    },
                    "id": {
                      "type": "string"
                    },
                    "sub_mode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "required": [
          "available",
          "methodology",
          "disclaimer"
        ]
      },
      "ValidateResponse": {
        "type": "object",
        "description": "Structural validation result. `found` lists every identifier detected (ordered by position); `note` is present when nothing was found.",
        "properties": {
          "found": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "container",
                    "awb",
                    "imo"
                  ]
                },
                "raw": {
                  "type": "string",
                  "description": "The candidate as found in the input"
                },
                "normalised": {
                  "type": "string",
                  "description": "Canonical form (uppercased / dashed)"
                },
                "valid": {
                  "type": "boolean",
                  "description": "Check-digit pass/fail (structural only)"
                },
                "check_digit": {
                  "type": "object",
                  "properties": {
                    "expected": {
                      "type": "integer",
                      "nullable": true
                    },
                    "actual": {
                      "type": "integer",
                      "nullable": true
                    }
                  }
                },
                "details": {
                  "type": "object",
                  "description": "Type-specific: container → owner_prefix, equipment_category, equipment_category_label, serial; awb → airline_prefix, serial, airline{name,iata,icao}|null (a prefix held by several records: airline null + airline_candidates[{name,iata,icao,status?}] + airline_note); imo → number; malformed → error.",
                  "additionalProperties": true
                },
                "_source": {
                  "type": "object",
                  "description": "Methodology citation for the identifier scheme.",
                  "properties": {
                    "type": {
                      "type": "string"
                    },
                    "standard": {
                      "type": "string"
                    },
                    "reference": {
                      "type": "string"
                    },
                    "authority": {
                      "type": "string"
                    },
                    "source_url": {
                      "type": "string"
                    },
                    "computed_by": {
                      "type": "string"
                    }
                  }
                }
              },
              "required": [
                "type",
                "raw",
                "normalised",
                "valid",
                "check_digit",
                "details",
                "_source"
              ]
            }
          },
          "disclaimer": {
            "type": "string"
          },
          "note": {
            "type": "string",
            "description": "Present when no identifier was found"
          }
        },
        "required": [
          "found",
          "disclaimer"
        ]
      },
      "Ics2CheckResponse": {
        "type": "object",
        "description": "EU ICS2 stop-words check result. No accepted/rejected verdict — a flagged term will likely cause an ENS rejection; a clean result does not guarantee acceptance (the list is non-exhaustive).",
        "properties": {
          "description": {
            "type": "string",
            "description": "Echo of the submitted description"
          },
          "flagged": {
            "type": "array",
            "description": "Listed stop-words found (empty if none)",
            "items": {
              "type": "object",
              "properties": {
                "term": {
                  "type": "string",
                  "description": "The listed stop-word found"
                },
                "note": {
                  "type": "string",
                  "description": "Standalone (automatic ENS rejection) vs embedded (make the description more specific)"
                }
              },
              "required": [
                "term",
                "note"
              ]
            }
          },
          "clean": {
            "type": "boolean",
            "description": "True if no listed stop-word found — NOT a guarantee of acceptance"
          },
          "caveat": {
            "type": "string",
            "description": "Non-exhaustive-list caveat: clean does not mean accepted"
          },
          "_source": {
            "type": "object",
            "description": "Citability envelope: EU ICS2 list authority, legal basis, version + provenance.",
            "properties": {
              "type": {
                "type": "string"
              },
              "authority": {
                "type": "string"
              },
              "dataset": {
                "type": "string"
              },
              "legal_basis": {
                "type": "string"
              },
              "list_in_force": {
                "type": "string"
              },
              "source_url": {
                "type": "string"
              },
              "licence": {
                "type": "string"
              },
              "non_exhaustive": {
                "type": "boolean"
              },
              "retrieved": {
                "type": "string"
              },
              "retrieved_via": {
                "type": "string"
              }
            }
          },
          "disclaimer": {
            "type": "string",
            "description": "Reference-only disclaimer"
          }
        },
        "required": [
          "description",
          "flagged",
          "clean",
          "caveat",
          "disclaimer"
        ]
      },
      "Airport": {
        "type": "object",
        "properties": {
          "ident": {
            "type": "string",
            "description": "ICAO / OurAirports ident",
            "example": "EGLL"
          },
          "iata_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "IATA 3-letter code (null if none)",
            "example": "LHR"
          },
          "name": {
            "type": "string",
            "example": "London Heathrow Airport"
          },
          "type": {
            "type": "string",
            "enum": [
              "large_airport",
              "medium_airport",
              "small_airport",
              "heliport",
              "closed",
              "seaplane_base"
            ],
            "example": "large_airport"
          },
          "municipality": {
            "type": [
              "string",
              "null"
            ],
            "example": "London"
          },
          "region": {
            "type": [
              "string",
              "null"
            ],
            "description": "Region / subdivision (readable)",
            "example": "England"
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code",
            "example": "GB"
          },
          "country_name": {
            "type": [
              "string",
              "null"
            ],
            "example": "United Kingdom"
          },
          "latitude": {
            "type": "number",
            "example": 51.470748
          },
          "longitude": {
            "type": "number",
            "example": -0.459909
          },
          "elevation_ft": {
            "type": [
              "integer",
              "null"
            ],
            "example": 83
          }
        },
        "required": [
          "ident",
          "iata_code",
          "name",
          "type",
          "country",
          "latitude",
          "longitude"
        ]
      },
      "AirportWithDistance": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Airport"
          },
          {
            "type": "object",
            "properties": {
              "distance_km": {
                "type": "number",
                "description": "Great-circle distance from the query point, km",
                "example": 0.1
              }
            },
            "required": [
              "distance_km"
            ]
          }
        ]
      },
      "AirportsResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "example": 1
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Airport"
            }
          },
          "disclaimer": {
            "type": "string"
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "count",
          "results"
        ]
      },
      "NearestAirportResponse": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "example": 5
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AirportWithDistance"
            }
          },
          "disclaimer": {
            "type": "string"
          },
          "meta": {
            "type": "object",
            "description": "Echo of the query (latitude, longitude, radius_km, max_results, type) + source."
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "count",
          "results"
        ]
      },
      "ResolveCandidate": {
        "type": "object",
        "description": "One resolution candidate. Ambiguity is the product: colliding grammars each contribute candidates, ranked deterministically with an inspectable rank_basis.",
        "properties": {
          "entity_type": {
            "type": "string",
            "description": "What the candidate is: dangerous_good, airline, airport, location, hs_classification, incoterm, container_type, container_equipment, uld_type, tunnel_restriction.",
            "example": "airport"
          },
          "identifier_type": {
            "type": "string",
            "description": "Which grammar matched: un_number, awb_prefix, airline_iata, airline_icao, airport_iata, airport_icao, unlocode, container_number, hs_code, incoterm, tunnel_code, uld_type, iso_container_type.",
            "example": "airport_iata"
          },
          "value_normalized": {
            "type": "string",
            "example": "LHR"
          },
          "summary": {
            "type": "string",
            "description": "One-line human summary of the candidate.",
            "example": "London Heathrow Airport — London, United Kingdom"
          },
          "record": {
            "type": [
              "object",
              "null"
            ],
            "description": "Core fields from the matching dataset. Null for a pattern-only match (the value fits a grammar but is not in the served dataset)."
          },
          "verification_status": {
            "type": "string",
            "description": "Normalized across datasets: active_verified, verified, computed, partial, pending_verification, unchecked, unverified, historical, pattern_only.",
            "example": "verified"
          },
          "verification_basis": {
            "type": "string",
            "enum": [
              "record",
              "dataset"
            ],
            "description": "record = from this record's own provenance fields; dataset = the dataset-level claim (no record-level signal exists)."
          },
          "rank_basis": {
            "type": "string",
            "description": "Why the candidate sits where it does: record hit > verification status > static dataset prior > stable tiebreak."
          },
          "canonical_url": {
            "type": "string",
            "description": "The record's page on freightutils.com, where one exists. Omitted otherwise.",
            "example": "/adr/un/1845"
          },
          "api_url": {
            "type": "string",
            "description": "The dataset's REST query for this record, where one exists.",
            "example": "/api/airports?iata=LHR"
          },
          "citation": {
            "type": "object",
            "description": "The matching dataset's own citation for this record (text + optional qualifier).",
            "properties": {
              "text": {
                "type": "string"
              },
              "qualifier": {
                "type": "string"
              }
            },
            "required": [
              "text"
            ]
          }
        },
        "required": [
          "entity_type",
          "identifier_type",
          "value_normalized",
          "summary",
          "record",
          "verification_status",
          "verification_basis",
          "rank_basis",
          "citation"
        ]
      },
      "ResolveResponse": {
        "type": "object",
        "description": "Envelope v1.1 (native). result holds the resolution; each candidate carries its own dataset citation. Zero candidates is ok:true with count 0 and a note, never an error.",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "envelope_version": {
            "type": "string",
            "enum": [
              "1",
              "1.1"
            ]
          },
          "result": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string"
              },
              "normalized": {
                "type": "string",
                "description": "After trim, uppercase, space/dash collapse and UN-prefix strip."
              },
              "candidates": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ResolveCandidate"
                }
              },
              "count": {
                "type": "integer"
              },
              "note": {
                "type": "string",
                "description": "Present only when count is 0: 'no known freight identifier grammar matched'."
              }
            },
            "required": [
              "query",
              "normalized",
              "candidates",
              "count"
            ]
          },
          "confidence": {
            "type": "object",
            "description": "high/deterministic when candidates exist; low/deterministic with a NO_MATCH warning when none do."
          },
          "warnings": {
            "type": "array",
            "description": "Advisory only. NO_MATCH is emitted on every count:0 response.",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "normalized_input": {
            "type": "object",
            "description": "Present when normalization changed the query (lowercase, spacing, dashes, UN prefix): q_input + normalized."
          },
          "blocking_errors": {
            "type": "array",
            "description": "Present on the 400 branches only: MISSING_INPUT (no q) or INVALID_INPUT (over the 32-char single-token limit).",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                },
                "recovery": {
                  "type": "object"
                }
              }
            }
          },
          "citation": {
            "type": "object",
            "description": "Top-level one-line citation for the resolution itself; per-candidate dataset citations live on each candidate."
          },
          "_source": {
            "$ref": "#/components/schemas/SourceEnvelope"
          }
        },
        "required": [
          "ok",
          "envelope_version",
          "result",
          "confidence",
          "citation"
        ]
      }
    }
  }
}
