{
  "openapi": "3.1.0",
  "info": {
    "title": "LoadingMCP API",
    "version": "1.0.0",
    "description": "3D container & truck load planning with a compliance engine. POST cargo, get back the packed plan and a ready-or-blockers compliance verdict (SOLAS VGM, IMDG 7.2.4 segregation, axle loads + US Bridge Formula, McKee carton crush, centre of gravity, securing). API keys come with a paid Business plan: https://loadingmcp.com/pricing",
    "contact": { "url": "https://loadingmcp.com/docs/api" }
  },
  "servers": [{ "url": "https://loadingmcp-api.fly.dev" }],
  "security": [{ "bearerAuth": [] }],
  "paths": {
    "/v1/plan": {
      "post": {
        "operationId": "planLoad",
        "summary": "Compute a 3D load plan + compliance verdict",
        "description": "Stateless load solve. Send cargo items and optionally an equipmentCode; omit it to auto right-size to the cheapest equipment that fits (reefer-gated for refrigerated cargo). Runs the production PackingSolver optimizer; the response reports which engine produced the plan.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PlanRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The packed plan and compliance verdict.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PlanResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid body (missing items, bad dimensions, unknown equipmentCode, dry container for refrigerated cargo, or no container fits)."
          },
          "401": { "description": "Missing or invalid API key." },
          "403": { "description": "The org has no active LoadingMCP subscription." }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from a paid plan, e.g. Authorization: Bearer lmcp_YOUR_KEY"
      }
    },
    "schemas": {
      "CargoItem": {
        "type": "object",
        "required": ["length", "width", "height"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "type": {
            "type": "string",
            "enum": ["box", "pallet", "drum", "cylinder", "bigbag", "roll", "sack"],
            "default": "box",
            "description": "Drives packing realism: drums/cylinders/rolls hex-nest; big bags/sacks are soft cargo that loads on top and is never crushed."
          },
          "length": { "type": "number", "exclusiveMinimum": 0, "description": "mm" },
          "width": { "type": "number", "exclusiveMinimum": 0, "description": "mm" },
          "height": { "type": "number", "exclusiveMinimum": 0, "description": "mm" },
          "weightKg": { "type": "number", "description": "Weight per unit, kg." },
          "quantity": { "type": "integer", "minimum": 1, "default": 1 },
          "stackable": { "type": "boolean", "default": true },
          "maxStackWeightKg": {
            "type": "number",
            "description": "Max weight this unit can carry on top, kg."
          },
          "fragile": {
            "type": "boolean",
            "description": "Implies thisSideUp and upright-only rotations."
          },
          "thisSideUp": { "type": "boolean", "description": "Restricts to upright orientations." },
          "bulky": {
            "type": "boolean",
            "description": "Awkward cargo: never stacked on, nothing on top."
          },
          "refrigerated": { "type": "boolean", "description": "Requires reefer equipment." },
          "hazmatClass": {
            "type": "string",
            "description": "IMDG class, e.g. \"3\", \"5.1\" — enables IMDG 7.2.4 segregation checks."
          },
          "deliveryStop": {
            "type": "integer",
            "minimum": 1,
            "description": "Multi-drop stop number (1 = first drop) for stop-sequenced loading."
          },
          "boardEctLbIn": {
            "type": "number",
            "description": "Corrugated board ECT (lb/in) for the McKee crush limit."
          },
          "boardCaliperMm": {
            "type": "number",
            "description": "Board caliper (mm) for the McKee crush limit."
          },
          "doubleWall": { "type": "boolean" },
          "color": { "type": "string", "description": "Hex colour for the 3D render." }
        }
      },
      "PlanRequest": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "equipmentCode": {
            "type": "string",
            "description": "Equipment code, e.g. 20GP, 40GP, 40HC, 45HC, 20RF, 40RH, TRUCK_EU_13_6, TRUCK_53_DV, PALLET_EUR. Omit to auto right-size."
          },
          "mode": {
            "type": "string",
            "enum": ["sea", "road", "air"],
            "default": "sea",
            "description": "Scopes the auto right-size to usable equipment; ignored when equipmentCode is explicit."
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "items": { "$ref": "#/components/schemas/CargoItem" }
          },
          "options": {
            "type": "object",
            "properties": {
              "multiStuffing": {
                "type": "boolean",
                "default": true,
                "description": "Allow splitting across multiple containers."
              },
              "cogTarget": {
                "type": "object",
                "properties": { "x": { "type": "number" }, "y": { "type": "number" } },
                "description": "Balance point to pack toward (fractional offsets)."
              },
              "vgm": {
                "type": "object",
                "properties": {
                  "declaredKg": {
                    "type": "array",
                    "items": { "type": "number" },
                    "description": "Shipper-declared gross mass per container, kg."
                  },
                  "method": { "type": "string", "enum": ["M1", "M2"] },
                  "dunnageKg": { "type": "number" }
                },
                "description": "SOLAS VGM declaration to cross-check against the computed estimate."
              },
              "jurisdiction": {
                "type": "string",
                "enum": ["EU", "US", "CN"],
                "description": "Road jurisdiction for the axle / gross-weight check (EU 96/53/EC, US 23 CFR 658.17 + Bridge Formula B, CN GB 1589-2016). Default EU."
              },
              "sequenceStops": {
                "type": "boolean",
                "description": "Zone the load by deliveryStop, nose to doors."
              }
            }
          }
        }
      },
      "PlanResponse": {
        "type": "object",
        "properties": {
          "ok": { "type": "boolean" },
          "engine": {
            "type": "string",
            "description": "Which packer produced the plan: \"packingsolver\" (production optimizer) or \"offline-fallback\"."
          },
          "equipmentCode": { "type": "string" },
          "autoSized": {
            "type": "boolean",
            "description": "True when the equipment was chosen by cost-aware right-sizing."
          },
          "plan": {
            "type": "object",
            "description": "The packed 3D plan: bins, placements, and metrics — volume/payload utilization, centre of gravity, and metrics.compliance with { ready, blockers[], vgm, axle, segregation, crush, securing }.",
            "properties": {
              "metrics": {
                "type": "object",
                "properties": {
                  "volumeUtilPct": { "type": "number" },
                  "payloadUtilPct": { "type": "number" },
                  "compliance": {
                    "type": "object",
                    "properties": {
                      "ready": { "type": "boolean" },
                      "blockers": { "type": "array", "items": { "type": "string" } }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
