{
  "openapi": "3.1.0",
  "info": {
    "title": "StowCargo ERP API",
    "version": "1.0",
    "description": "Send a packing list, get the load plan back in the same response. Field names are Turkish and identical in JSON and StowCargo XML 1.0 (schema: /xml/stowcargo-1.0.xsd). Units: mm and kg unless olcuBirimi / agirlikBirimi say otherwise. Full guide (Turkish): docs/ERP-API.md."
  },
  "servers": [
    {
      "url": "{base}/api/erp/v1",
      "variables": {
        "base": {
          "default": "https://stowcargo.example.com",
          "description": "Your company's StowCargo address (STOWCARGO_PUBLIC_URL)."
        }
      }
    }
  ],
  "security": [
    {
      "anahtar": []
    }
  ],
  "paths": {
    "/planla": {
      "post": {
        "operationId": "planla",
        "summary": "Plan a packing list",
        "description": "Plans the cargo, saves it to the plan archive (tagged ERP) and returns the plan. Response format follows the request (override with Accept).",
        "parameters": [
          {
            "name": "Accept-Language",
            "in": "header",
            "schema": {
              "type": "string",
              "example": "en"
            },
            "description": "Language of error messages (tr default, en)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlanlaIstegi"
              },
              "example": {
                "ref": "SVK-2026-0907",
                "ad": "Münih kamyonu",
                "alici": "Örnek Alıcı GmbH",
                "olcuBirimi": "cm",
                "arac": {
                  "kod": "40hc"
                },
                "secenekler": {
                  "oncelik": "bosluk",
                  "sureMs": 3000
                },
                "kalemler": [
                  {
                    "kod": "KL-1",
                    "ad": "Koli",
                    "boy": 60,
                    "en": 40,
                    "yukseklik": 40,
                    "agirlik": 12,
                    "adet": 300
                  }
                ]
              }
            },
            "application/xml": {
              "schema": {
                "type": "string",
                "description": "StowCargo XML 1.0 <cekiListesi> document."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Planned and saved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "planSurumu": {
                      "type": "integer"
                    },
                    "arsiv": {
                      "type": "string",
                      "format": "uri"
                    },
                    "ozet": {
                      "$ref": "#/components/schemas/Ozet"
                    },
                    "sureMs": {
                      "type": "integer"
                    },
                    "surum": {
                      "type": "string"
                    },
                    "plan": {
                      "$ref": "#/components/schemas/Plan"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Body unreadable, no vehicle, no items or invalid sizes (the message says what is missing).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "401": {
            "description": "Missing, wrong or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "403": {
            "description": "Organization disabled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "413": {
            "description": "Body larger than 8 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit (120 requests per minute per key) or more than 2 concurrent plannings per organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "503": {
            "description": "Planning server busy; retry after a few seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          }
        }
      }
    },
    "/planlar/{id}": {
      "get": {
        "operationId": "plan",
        "summary": "Latest version of an archived plan",
        "description": "If the team edited the plan on the site, the edited version is returned. Includes the warehouse loading status.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "bicim",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "xml"
              ]
            },
            "description": "xml: return StowCargo XML (or send Accept: application/xml)."
          }
        ],
        "responses": {
          "200": {
            "description": "Plan",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "planSurumu": {
                      "type": "integer"
                    },
                    "surum": {
                      "type": "string"
                    },
                    "plan": {
                      "$ref": "#/components/schemas/Plan"
                    },
                    "yukleme": {
                      "oneOf": [
                        {
                          "type": "null"
                        },
                        {
                          "$ref": "#/components/schemas/Yukleme"
                        }
                      ]
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Missing, wrong or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "404": {
            "description": "Plan not found (another organization's plan also returns 404).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          },
          "409": {
            "description": "Plan has no stored result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          }
        }
      }
    },
    "/araclar": {
      "get": {
        "operationId": "araclar",
        "summary": "Built-in vehicle codes and inner dimensions",
        "responses": {
          "200": {
            "description": "Vehicles",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "araclar": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "kod": {
                            "type": "string"
                          },
                          "ad": {
                            "type": "string"
                          },
                          "boy": {
                            "type": "number"
                          },
                          "en": {
                            "type": "number"
                          },
                          "yukseklik": {
                            "type": "number"
                          },
                          "azamiYuk": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, wrong or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Hata"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "planOlayi": {
      "post": {
        "summary": "Plan event (configured by an admin under ERP integration → Webhooks)",
        "description": "Signed with X-StowCargo-Imza: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, \"<t>.<raw body>\")>. Reject signatures older than 5 minutes. Retries: 1 min, 5 min, 30 min, 2 h, 6 h.",
        "parameters": [
          {
            "name": "X-StowCargo-Olay",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-StowCargo-Teslim",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-StowCargo-Imza",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookGovdesi"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "anahtar": {
        "type": "http",
        "scheme": "bearer",
        "description": "ERP key (sc_…) created by an admin under ERP integration → Create key. Shown once."
      }
    },
    "schemas": {
      "Kalem": {
        "type": "object",
        "required": [
          "boy",
          "adet"
        ],
        "properties": {
          "kod": {
            "type": "string",
            "maxLength": 60,
            "description": "ERP stock code; returned unchanged."
          },
          "ad": {
            "type": "string",
            "maxLength": 120,
            "description": "Product name."
          },
          "bicim": {
            "type": "string",
            "enum": [
              "kutu",
              "silindir"
            ],
            "default": "kutu",
            "description": "Shape: box or cylinder (roll, drum, pipe)."
          },
          "boy": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Length (in olcuBirimi). For a cylinder: axis length."
          },
          "en": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Width. Not used for cylinders (use cap)."
          },
          "yukseklik": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Height. Not used for cylinders (use cap)."
          },
          "cap": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Cylinder diameter."
          },
          "agirlik": {
            "type": "number",
            "minimum": 0,
            "description": "Weight of ONE piece (in agirlikBirimi)."
          },
          "toplamAgirlik": {
            "type": "number",
            "minimum": 0,
            "description": "Total weight of the line; used when agirlik is missing (divided by adet)."
          },
          "adet": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100000,
            "description": "Number of pieces (packages) to load."
          },
          "yon": {
            "type": "string",
            "enum": [
              "dik",
              "serbest",
              "sabit",
              "upright",
              "any",
              "fixed"
            ],
            "description": "Orientation: dik/upright = this side up, serbest/any = may be laid down, sabit/fixed = fixed orientation."
          },
          "istiflenebilir": {
            "type": "boolean",
            "default": true,
            "description": "Other cargo may be placed on top (applied only with oncelik=kurallar)."
          },
          "ustYuk": {
            "type": "number",
            "minimum": 0,
            "description": "Max load on top (kg, oncelik=kurallar)."
          },
          "katSiniri": {
            "type": "integer",
            "minimum": 1,
            "description": "Max layers of the same product (oncelik=kurallar)."
          },
          "durak": {
            "type": "integer",
            "minimum": 1,
            "maximum": 99,
            "default": 1,
            "description": "Delivery stop: 1 is unloaded first (nearest the door)."
          },
          "siparis": {
            "type": "string",
            "maxLength": 60,
            "description": "Order group: items of one order are loaded into the same vehicle."
          },
          "sinif": {
            "type": "string",
            "maxLength": 60,
            "description": "Segregation class (e.g. food, chemicals): different classes never share a vehicle."
          },
          "paletle": {
            "type": "boolean",
            "description": "Build onto pallets first, then load pallets."
          },
          "yalnizZemin": {
            "type": "boolean",
            "description": "Floor only: never placed on top of other cargo (may carry load itself). Applied in both priorities."
          },
          "dolgu": {
            "type": "boolean",
            "description": "Fill item: placed after the main cargo, as many as fit (up to adet)."
          }
        }
      },
      "PlanlaIstegi": {
        "type": "object",
        "required": [
          "kalemler"
        ],
        "properties": {
          "ref": {
            "type": "string",
            "maxLength": 60,
            "description": "Your document number. Sending the same ref again adds a new version to the same plan instead of a new plan."
          },
          "alici": {
            "type": "string",
            "maxLength": 120,
            "description": "Consignee (customer) name. Printed on the load report and shipping documents."
          },
          "ad": {
            "type": "string",
            "maxLength": 120,
            "description": "Plan name."
          },
          "olcuBirimi": {
            "type": "string",
            "enum": [
              "mm",
              "cm",
              "m",
              "in"
            ],
            "default": "mm"
          },
          "agirlikBirimi": {
            "type": "string",
            "enum": [
              "kg",
              "t",
              "g",
              "lb"
            ],
            "default": "kg"
          },
          "arac": {
            "type": "object",
            "properties": {
              "kod": {
                "type": "string",
                "description": "Built-in vehicle code from GET /araclar (e.g. tir-tenteli, 40hc)."
              },
              "ad": {
                "type": "string",
                "description": "Custom vehicle name (when no kod)."
              },
              "boy": {
                "type": "number"
              },
              "en": {
                "type": "number"
              },
              "yukseklik": {
                "type": "number"
              },
              "azamiYuk": {
                "type": "number",
                "description": "Max payload (kg) for a custom vehicle."
              }
            }
          },
          "secenekler": {
            "type": "object",
            "properties": {
              "oncelik": {
                "type": "string",
                "enum": [
                  "bosluk",
                  "kurallar"
                ],
                "default": "bosluk",
                "description": "bosluk = space first (stacking bans and top-load limits ignored; orientation and support kept). kurallar = stacking rules applied."
              },
              "sureMs": {
                "type": "integer",
                "minimum": 300,
                "maximum": 10000,
                "default": 2000,
                "description": "Optimization time budget."
              }
            }
          },
          "kalemler": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5000,
            "items": {
              "$ref": "#/components/schemas/Kalem"
            },
            "description": "Max 5,000 lines and 50,000 pieces per request."
          }
        }
      },
      "Ozet": {
        "type": "object",
        "properties": {
          "vehicles": {
            "type": "integer"
          },
          "fill": {
            "type": "number",
            "description": "Average volume utilization 0..1"
          },
          "weight": {
            "type": "number"
          },
          "loadLength": {
            "type": "number",
            "description": "Longest load length (mm)"
          },
          "lines": {
            "type": "integer"
          },
          "pieces": {
            "type": "integer"
          },
          "placed": {
            "type": "integer"
          },
          "unplaced": {
            "type": "integer"
          }
        }
      },
      "Yerlesim": {
        "type": "object",
        "description": "Placements are in loading order (sira). x from the front wall towards the door, y from the right wall, z from the floor (mm).",
        "properties": {
          "sira": {
            "type": "integer"
          },
          "kalem": {
            "type": "integer",
            "description": "Item no (1-based, from kalemler)."
          },
          "palet": {
            "type": "integer",
            "description": "Pallet no when the placement is a pallet."
          },
          "x": {
            "type": "number"
          },
          "y": {
            "type": "number"
          },
          "z": {
            "type": "number"
          },
          "boy": {
            "type": "number"
          },
          "en": {
            "type": "number"
          },
          "yukseklik": {
            "type": "number"
          },
          "agirlik": {
            "type": "number"
          },
          "durak": {
            "type": "integer"
          },
          "icerik": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kalem": {
                  "type": "integer"
                },
                "adet": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Plan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "planSurumu": {
            "type": "integer"
          },
          "ad": {
            "type": "string"
          },
          "ref": {
            "type": "string"
          },
          "alici": {
            "type": "string"
          },
          "oncelik": {
            "type": "string",
            "enum": [
              "bosluk",
              "kurallar"
            ]
          },
          "arsiv": {
            "type": "string",
            "format": "uri"
          },
          "arac": {
            "type": "object",
            "properties": {
              "kod": {
                "type": "string"
              },
              "ad": {
                "type": "string"
              },
              "boy": {
                "type": "number"
              },
              "en": {
                "type": "number"
              },
              "yukseklik": {
                "type": "number"
              },
              "azamiYuk": {
                "type": "number"
              }
            }
          },
          "kalemler": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/Kalem"
                },
                {
                  "type": "object",
                  "properties": {
                    "no": {
                      "type": "integer"
                    }
                  }
                }
              ]
            }
          },
          "sonuc": {
            "type": "object",
            "properties": {
              "aracSayisi": {
                "type": "integer"
              },
              "yerlesen": {
                "type": "integer"
              },
              "toplam": {
                "type": "integer"
              },
              "agirlik": {
                "type": "number"
              },
              "yuklemeler": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "arac": {
                      "type": "integer"
                    },
                    "hacimDoluluk": {
                      "type": "number"
                    },
                    "agirlikDoluluk": {
                      "type": "number"
                    },
                    "agirlik": {
                      "type": "number"
                    },
                    "yukBoyu": {
                      "type": "number"
                    },
                    "agirlikMerkeziX": {
                      "type": "number"
                    },
                    "agirlikMerkeziY": {
                      "type": "number"
                    },
                    "agirlikMerkeziZ": {
                      "type": "number"
                    },
                    "yerlesimler": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Yerlesim"
                      }
                    }
                  }
                }
              },
              "yerlesmeyenler": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "kalem": {
                      "type": "integer"
                    },
                    "adet": {
                      "type": "integer"
                    },
                    "neden": {
                      "type": "string",
                      "enum": [
                        "sigmiyor",
                        "agir",
                        "kapasite"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      },
      "Hata": {
        "type": "object",
        "required": [
          "hata"
        ],
        "properties": {
          "hata": {
            "type": "string",
            "description": "Human-readable message in Turkish, or in English when the request sends Accept-Language: en."
          }
        }
      },
      "Yukleme": {
        "type": "object",
        "description": "Warehouse loading status (null if the warehouse link was never used).",
        "properties": {
          "planSurumu": {
            "type": "integer"
          },
          "tamamlandi": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "guncellendi": {
            "type": "string",
            "format": "date-time"
          },
          "fotograf": {
            "type": "integer"
          },
          "araclar": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "arac": {
                  "type": "integer"
                },
                "yuklenen": {
                  "type": "integer"
                },
                "toplam": {
                  "type": "integer"
                },
                "bitti": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "WebhookGovdesi": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Delivery id; the same delivery may arrive twice — deduplicate on this."
          },
          "olay": {
            "type": "string",
            "enum": [
              "plan.olusturuldu",
              "plan.guncellendi",
              "plan.silindi",
              "plan.geriAlindi",
              "yukleme.tamamlandi",
              "test"
            ]
          },
          "zaman": {
            "type": "string",
            "format": "date-time"
          },
          "firma": {
            "type": "string",
            "format": "uuid"
          },
          "plan": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "planSurumu": {
                "type": "integer"
              },
              "ad": {
                "type": "string"
              },
              "ref": {
                "type": "string"
              },
              "kaynak": {
                "type": "string",
                "enum": [
                  "site",
                  "erp"
                ]
              },
              "ozet": {
                "$ref": "#/components/schemas/Ozet"
              },
              "arsiv": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}