{
 "openapi": "3.0.3",
 "info": {
  "title": "Ikonka ordersAPI",
  "version": "0.9.0",
  "description": "API zamówień B2B Ikonki. Jedno żądanie składa całe zamówienie: API sprawdza je tak samo jak sklep internetowy i zwraca numer zamówienia albo **wszystkie** powody odmowy naraz.\n\n**Logowanie** - HTTP Basic: e-mail i hasło konta B2B w sklepie internetowym Ikonki. Dostęp do API ma każde konto B2B - nie trzeba go zamawiać ani włączać.\n\n**Testy** - wyślij zamówienie z `\"checkOnly\": true`: pełne sprawdzenie, nic nie jest zapisywane. Można wołać dowolnie często.\n\n**Ponawianie** - jeden `externalId` to jedno zamówienie. Gdy minie limit czasu albo zerwie się połączenie, wyślij to samo zamówienie ponownie **z tym samym `externalId`** - nie powstanie drugi raz.\n\n**Błędy** - każda odmowa ma stały kod (`code`) i komunikat (`message`) po polsku. Obsługę błędów opieraj na `code`; `message` służy do wyświetlenia. Lista kodów jest przy schemacie `Error`.\n\n**Zgodność** - mogą dojść nowe pola i kody; nieznane pola należy pomijać.\n"
 },
 "servers": [
  {
   "url": "https://orders-api.ikonka.eu"
  }
 ],
 "security": [
  {
   "basicAuth": []
  }
 ],
 "tags": [
  {
   "name": "Orders",
   "description": "Składanie i sprawdzanie zamówień."
  },
  {
   "name": "Catalog",
   "description": "Co można wybrać w zamówieniu."
  },
  {
   "name": "Service"
  }
 ],
 "paths": {
  "/v1/orders": {
   "post": {
    "tags": [
     "Orders"
    ],
    "summary": "Złożenie zamówienia (albo sprawdzenie przez checkOnly)",
    "description": "Zamówienie przechodzi naraz przez wszystkie kroki sklepu internetowego. Odpowiedź to numer zamówienia albo wszystkie powody odmowy. Z `\"checkOnly\": true` - to samo sprawdzenie bez zapisu.\n\nNie czekamy, aż zamówienie trafi do systemu magazynowego - `201` oznacza, że zamówienie istnieje w Ikonce.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/Order"
       },
       "example": {
        "externalId": "ZAM-2026-0001",
        "lines": [
         {
          "code": "KX9644",
          "quantity": 12
         },
         {
          "code": "KX3127",
          "quantity": 6
         }
        ],
        "shippingMethod": "dpd_courier",
        "paymentMethod": "bank_transfer",
        "comments": "Zamówienie tygodniowe - sklep Poznań",
        "checkOnly": true
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Zamówienie złożone.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PlacedOrder"
        },
        "example": {
         "orderNumber": "1023456",
         "externalId": "ZAM-2026-0001",
         "status": "new"
        }
       }
      }
     },
     "200": {
      "description": "Wynik `checkOnly` albo zamówienie z tym `externalId` już istnieje (`\"repeated\": true`).",
      "content": {
       "application/json": {
        "schema": {
         "oneOf": [
          {
           "$ref": "#/components/schemas/CheckResult"
          },
          {
           "$ref": "#/components/schemas/PlacedOrder"
          }
         ]
        }
       }
      }
     },
     "202": {
      "description": "Zamówienie jest przetwarzane - numer zamówienia nie jest jeszcze znany. Po kilku minutach wyślij je ponownie z tym samym `externalId`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/PendingOrder"
        }
       }
      }
     },
     "400": {
      "description": "Niepoprawne żądanie: treść nie jest JSON-em, pole ma zły typ, pole spoza kontraktu albo brak `externalId`. Nic nie zapisano.",
      "content": {
       "application/json": {
        "schema": {
         "oneOf": [
          {
           "$ref": "#/components/schemas/CheckResult"
          },
          {
           "$ref": "#/components/schemas/ErrorResponse"
          }
         ]
        }
       }
      }
     },
     "409": {
      "description": "Zamówienie z tym `externalId` jest właśnie przetwarzane - poczekaj na wynik pierwszego żądania.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "ORDER_IN_PROGRESS",
           "message": "Zamówienie o tym numerze jest właśnie przetwarzane."
          }
         ]
        }
       }
      }
     },
     "413": {
      "description": "Żądanie przekracza dopuszczalny rozmiar (32 MB).",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "BODY_TOO_LARGE",
           "message": "Żądanie za duże."
          }
         ]
        }
       }
      }
     },
     "422": {
      "description": "Zamówienie odrzucone - wszystkie powody w `errors`. Nic nie zapisano; po poprawieniu wyślij ponownie z tym samym `externalId`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/CheckResult"
        }
       }
      }
     },
     "502": {
      "description": "Zamówienie nie zostało przyjęte - skontaktuj się z Ikonką, podając `externalId`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "ORDER_REJECTED",
           "message": "Zamówienie nie zostało przyjęte."
          }
         ]
        }
       }
      }
     },
     "401": {
      "description": "Nieprawidłowy e-mail lub hasło.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "UNAUTHORIZED",
           "message": "Nieprawidłowy e-mail lub hasło."
          }
         ]
        }
       }
      }
     },
     "403": {
      "description": "Konto bez dostępu do API.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "ACCOUNT_API_ACCESS_MISSING",
           "message": "Konto nie ma dostępu do API."
          }
         ]
        }
       }
      }
     },
     "429": {
      "description": "Logowanie czasowo zablokowane po nieudanych próbach.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "LOGIN_LOCKED",
           "message": "Logowanie zablokowane - spróbuj za 15 min."
          }
         ]
        }
       }
      }
     },
     "503": {
      "description": "Usługa czasowo niedostępna - ponów później.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "SERVICE_UNAVAILABLE",
           "message": "Usługa jest chwilowo niedostępna - spróbuj ponownie za chwilę."
          }
         ]
        }
       }
      }
     },
     "500": {
      "description": "Nieoczekiwany błąd. Nie wysyłaj zamówienia z nowym `externalId`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "INTERNAL_ERROR",
           "message": "Wystąpił nieoczekiwany błąd."
          }
         ]
        }
       }
      }
     }
    }
   }
  },
  "/v1/catalog": {
   "get": {
    "tags": [
     "Catalog"
    ],
    "summary": "Formy dostawy i płatności dla konta i kraju",
    "description": "Lista wszystkich aliasów, także niedostępnych - z powodem w `reason`. Limity wagi i wartości zależą od zamówienia - sprawdza je `checkOnly`.",
    "parameters": [
     {
      "name": "country",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "example": "DEU",
      "description": "Kraj dostawy, ISO 3166-1 alfa-3. Domyślnie kraj z adresu dostawy na koncie."
     },
     {
      "name": "dropshipping",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "1"
       ]
      },
      "description": "`1` - formy dla dropshippingu."
     }
    ],
    "responses": {
     "200": {
      "description": "Katalog.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Catalog"
        }
       }
      }
     },
     "401": {
      "description": "Nieprawidłowy e-mail lub hasło.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "UNAUTHORIZED",
           "message": "Nieprawidłowy e-mail lub hasło."
          }
         ]
        }
       }
      }
     },
     "403": {
      "description": "Konto bez dostępu do API.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "ACCOUNT_API_ACCESS_MISSING",
           "message": "Konto nie ma dostępu do API."
          }
         ]
        }
       }
      }
     },
     "429": {
      "description": "Logowanie czasowo zablokowane po nieudanych próbach.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "LOGIN_LOCKED",
           "message": "Logowanie zablokowane - spróbuj za 15 min."
          }
         ]
        }
       }
      }
     },
     "503": {
      "description": "Usługa czasowo niedostępna - ponów później.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "SERVICE_UNAVAILABLE",
           "message": "Usługa jest chwilowo niedostępna - spróbuj ponownie za chwilę."
          }
         ]
        }
       }
      }
     },
     "500": {
      "description": "Nieoczekiwany błąd. Nie wysyłaj zamówienia z nowym `externalId`.",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ErrorResponse"
        },
        "example": {
         "valid": false,
         "errors": [
          {
           "code": "INTERNAL_ERROR",
           "message": "Wystąpił nieoczekiwany błąd."
          }
         ]
        }
       }
      }
     }
    }
   }
  },
  "/health": {
   "get": {
    "tags": [
     "Service"
    ],
    "summary": "Czy usługa działa",
    "security": [],
    "responses": {
     "200": {
      "description": "Usługa odpowiada.",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "state": {
           "type": "string",
           "enum": [
            "alive"
           ]
          }
         }
        },
        "example": {
         "state": "alive"
        }
       }
      }
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "basicAuth": {
    "type": "http",
    "scheme": "basic",
    "description": "E-mail i hasło konta B2B w sklepie internetowym."
   }
  },
  "schemas": {
   "Order": {
    "type": "object",
    "required": [
     "externalId",
     "lines",
     "shippingMethod",
     "paymentMethod"
    ],
    "additionalProperties": false,
    "description": "Pole spoza tej listy to odmowa `UNKNOWN_FIELD`. Ceny, koszty dostawy i termin płatności wynikają z warunków handlowych konta - nie przesyła się ich.",
    "properties": {
     "externalId": {
      "type": "string",
      "pattern": "^[A-Za-z0-9._-]{1,64}$",
      "example": "ZAM-2026-0001",
      "description": "Numer zamówienia w Twoim systemie. Jeden `externalId` to jedno zamówienie - ponowne wysłanie zwraca istniejące zamiast tworzyć drugie. Przy `checkOnly` nie jest potrzebny. Nie używaj numerów różniących się tylko wielkością liter."
     },
     "lines": {
      "type": "array",
      "minItems": 1,
      "maxItems": 200,
      "items": {
       "$ref": "#/components/schemas/OrderLine"
      },
      "description": "Pozycje zamówienia. Każdy kod produktu może wystąpić tylko raz."
     },
     "shippingMethod": {
      "type": "string",
      "enum": [
       "dpd_courier",
       "gls_courier",
       "inpost_courier",
       "inpost_locker",
       "own_courier_parcels",
       "own_dpd",
       "own_gls",
       "own_inpost",
       "own_other",
       "own_ups",
       "pallet_pickup",
       "pallet_raben",
       "personal_pickup"
      ],
      "example": "dpd_courier",
      "description": "Alias formy dostawy. Dostępność dla konta i kraju: `GET /v1/catalog`.\n\n| Alias | Forma | Uwagi |\n|---|---|---|\n| `personal_pickup` | Odbiór osobisty |  |\n| `own_dpd` | Odbiór własny DPD (Allegro SMART!) | Transport własny - etykieta w zamówieniu (`labelRequired` w katalogu). |\n| `own_gls` | Odbiór własny GLS (Allegro SMART!) | Tylko w sklepie internetowym - przez API odmowa. |\n| `own_inpost` | Odbiór własny Inpost (Allegro SMART!) | Transport własny - etykieta w zamówieniu (`labelRequired` w katalogu). |\n| `own_ups` | Odbiór własny Orlen Paczka/UPS/Kolporter (Allegro) / Allegro One Kurier | Transport własny - etykieta w zamówieniu (`labelRequired` w katalogu). |\n| `own_other` | Odbiór własny INNY (dropshipping) | Transport własny - etykieta w zamówieniu (`labelRequired` w katalogu). |\n| `own_courier_parcels` | Odbiór własny kurier - paczki | Etykiety przekazuje się e-mailem opiekunowi handlowemu. |\n| `pallet_pickup` | Odbiór Palet | Etykiety przekazuje się e-mailem opiekunowi handlowemu. |\n| `inpost_locker` | InPost Paczkomaty 24/7 | Forma dla kraju dostawy dobierana automatycznie. Wymaga `pickupPoint`. |\n| `dpd_courier` | DPD kurier | Forma dla kraju dostawy dobierana automatycznie. |\n| `gls_courier` | GLS kurier | Forma dla kraju dostawy dobierana automatycznie. |\n| `inpost_courier` | InPost kurier | Forma dla kraju dostawy dobierana automatycznie. |\n| `pallet_raben` | Paleta RABEN PL | Forma dla kraju dostawy dobierana automatycznie. |"
     },
     "paymentMethod": {
      "type": "string",
      "enum": [
       "bank_transfer",
       "bank_transfer_dropshipping",
       "cash_on_delivery",
       "cash_on_delivery_dropshipping"
      ],
      "example": "bank_transfer",
      "description": "Alias formy płatności.\n\n| Alias | Płatność | Uwagi |\n|---|---|---|\n| `bank_transfer` | Przelew |  |\n| `bank_transfer_dropshipping` | Przelew (dropshipping) |  |\n| `cash_on_delivery` | Za pobraniem | Tylko w sklepie internetowym - przez API odmowa. |\n| `cash_on_delivery_dropshipping` | Za pobraniem (dropshipping) | Tylko w sklepie internetowym - przez API odmowa. |"
     },
     "pickupPoint": {
      "type": "string",
      "example": "ADM01A",
      "description": "Kod punktu odbioru - wymagany przy `inpost_locker`."
     },
     "currency": {
      "type": "string",
      "example": "EUR",
      "description": "Waluta zamówienia, ISO 4217. Domyślnie waluta konta. Jeśli dla konta obowiązuje określona waluta, inna to odmowa `CURRENCY_FORCED`."
     },
     "recipient": {
      "$ref": "#/components/schemas/Recipient"
     },
     "dropshipping": {
      "type": "boolean",
      "description": "Wysyłka bezpośrednio do Twojego klienta końcowego. Wymaga `recipient` i dropshippingu włączonego na koncie. Formy dla tego trybu: `GET /v1/catalog?dropshipping=1`."
     },
     "labels": {
      "type": "array",
      "maxItems": 1,
      "items": {
       "$ref": "#/components/schemas/Label"
      },
      "description": "Etykieta przewozowa przy transporcie własnym - tylko przy formach z `labelRequired` w katalogu."
     },
     "comments": {
      "type": "string",
      "maxLength": 1000,
      "description": "Uwagi do zamówienia. Zwykły tekst, bez HTML."
     },
     "checkOnly": {
      "type": "boolean",
      "description": "`true` - pełne sprawdzenie bez zapisu."
     }
    }
   },
   "OrderLine": {
    "type": "object",
    "required": [
     "code",
     "quantity"
    ],
    "additionalProperties": false,
    "properties": {
     "code": {
      "type": "string",
      "example": "KX9644",
      "description": "Kod produktu jak w ofercie Ikonki."
     },
     "quantity": {
      "type": "integer",
      "minimum": 1,
      "maximum": 9999,
      "example": 12,
      "description": "Ilość w sztukach."
     }
    }
   },
   "Recipient": {
    "type": "object",
    "additionalProperties": false,
    "description": "Adres dostawy inny niż adres z konta. Wymagane: `company` albo `firstName` + `lastName` oraz `street`, `streetNumber1`, `postcode`, `city`, `country`. Faktura jest zawsze wystawiana na dane z konta. Teksty dłuższe niż dopuszczalne to odmowa `TEXT_TOO_LONG`.",
    "properties": {
     "firstName": {
      "type": "string"
     },
     "lastName": {
      "type": "string"
     },
     "company": {
      "type": "string"
     },
     "street": {
      "type": "string"
     },
     "streetNumber1": {
      "type": "string",
      "description": "Numer budynku."
     },
     "streetNumber2": {
      "type": "string",
      "description": "Numer lokalu."
     },
     "postcode": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "country": {
      "type": "string",
      "example": "POL",
      "description": "ISO 3166-1 alfa-3: `POL`, `DEU`, `CZE`..."
     },
     "email": {
      "type": "string",
      "format": "email"
     },
     "phone": {
      "type": "string",
      "description": "Zalecany przy wysyłce kurierskiej."
     }
    }
   },
   "Label": {
    "type": "object",
    "required": [
     "trackingNumber",
     "pdfBase64"
    ],
    "additionalProperties": false,
    "properties": {
     "trackingNumber": {
      "type": "string",
      "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$",
      "description": "Numer przesyłki z etykiety. Nie może być użyty w innym zamówieniu."
     },
     "pdfBase64": {
      "type": "string",
      "format": "byte",
      "description": "Plik PDF w base64: jedna strona A6, do 5 MB przed zakodowaniem."
     }
    }
   },
   "PlacedOrder": {
    "type": "object",
    "required": [
     "orderNumber",
     "externalId",
     "status"
    ],
    "properties": {
     "orderNumber": {
      "type": "string",
      "example": "1023456",
      "description": "Numer zamówienia w Ikonce."
     },
     "externalId": {
      "type": "string",
      "example": "ZAM-2026-0001"
     },
     "status": {
      "$ref": "#/components/schemas/OrderStatus"
     },
     "repeated": {
      "type": "boolean",
      "description": "`true` - zamówienie z tym `externalId` już istniało; nic nowego nie powstało."
     }
    }
   },
   "OrderStatus": {
    "type": "string",
    "example": "new",
    "description": "Status zamówienia. Mogą dojść nowe wartości - nieznane traktuj jak `unknown`.\n\n- `awaiting_payment` - Oczekuje na płatność\n- `cancelled` - Anulowane\n- `new` - Nowe - oczekuje na weryfikację\n- `new_fast_payment` - Nowe - szybka płatność\n- `new_temporary` - Nowe - tymczasowe\n- `unknown` - inny status"
   },
   "PendingOrder": {
    "type": "object",
    "properties": {
     "externalId": {
      "type": "string",
      "example": "ZAM-2026-0001"
     },
     "status": {
      "type": "string",
      "enum": [
       "pending"
      ]
     },
     "message": {
      "type": "string",
      "example": "Zamówienie jest przetwarzane. Wyślij je ponownie z tym samym externalId za kilka minut, żeby otrzymać numer zamówienia."
     }
    }
   },
   "CheckResult": {
    "type": "object",
    "required": [
     "valid",
     "errors"
    ],
    "description": "Wynik sprawdzenia. `steps`: 1 - produkty, 2 - dostawa, 3 - płatność, 4 - adres. Krok, który zatrzymał zamówienie, ma `\"valid\": false` i własną listę `errors`.",
    "properties": {
     "valid": {
      "type": "boolean"
     },
     "errors": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Error"
      }
     },
     "steps": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CheckStep"
      }
     },
     "checkedOnly": {
      "type": "boolean",
      "description": "`true` - to był `checkOnly`, nic nie zapisano."
     }
    }
   },
   "CheckStep": {
    "type": "object",
    "properties": {
     "step": {
      "type": "integer",
      "enum": [
       1,
       2,
       3,
       4
      ]
     },
     "valid": {
      "type": "boolean"
     },
     "errors": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Error"
      }
     },
     "options": {
      "type": "object",
      "additionalProperties": true,
      "description": "Co ustalił krok. Krok 1: `netValue`, `currency`. Krok 2: `available`, `shippingMethodId`, `shippingMethodName`, `shippingCostNet`, `shippingCostGross`, `packages`. Krok 3: `available`, `statusAfterPlacing`. W kroku 2 `available` to formy dostawy, które przyjmą to zamówienie (produkty, waga, wartość, kraj, konto, forma płatności) - można zmienić `shippingMethod` na dowolną z nich. Forma wymagająca punktu odbioru albo etykiety jest na liście tylko wtedy, gdy żądanie je zawiera. Kolejność jest alfabetyczna, nie według kosztu - koszt formy podaje `checkOnly` z tą formą. W kroku 3 `available` to wszystkie formy płatności obsługiwane w zamówieniach."
     }
    }
   },
   "Error": {
    "type": "object",
    "required": [
     "code",
     "message"
    ],
    "properties": {
     "code": {
      "type": "string",
      "example": "PRODUCT_NOT_FOUND",
      "description": "Stały kod - na nim opieraj obsługę błędów. Mogą dojść nowe kody; nieznany traktuj jak ogólną odmowę.\n\n| Kod | Znaczenie |\n|---|---|\n| **Żądanie i konto** | |\n| `BODY_INVALID` | Treść nie jest poprawnym JSON-em. |\n| `BODY_TOO_LARGE` | Żądanie przekracza dopuszczalny rozmiar. |\n| `SCHEMA_INVALID` | Pole ma niewłaściwy typ. |\n| `UNKNOWN_FIELD` | Pole spoza kontraktu (np. `price`). |\n| `NOT_FOUND` | Nieznana ścieżka. |\n| `METHOD_NOT_ALLOWED` | Nieobsługiwana metoda HTTP. |\n| `EXTERNAL_ID_REQUIRED` | Brak `externalId`. |\n| `EXTERNAL_ID_INVALID` | `externalId` zawiera niedozwolone znaki. |\n| `UNAUTHORIZED` | Nieprawidłowy e-mail lub hasło. |\n| `ACCOUNT_API_ACCESS_MISSING` | Konto bez dostępu do API. |\n| `ACCOUNT_INACTIVE` | Konto nie może składać zamówień. |\n| `ACCOUNT_NOT_ALLOWED` | Konto nie może składać zamówień. |\n| `ACCOUNT_ADDRESS_MISSING` | Konto bez adresu dostawy lub adresu do faktury. |\n| `LOGIN_LOCKED` | Logowanie czasowo zablokowane po nieudanych próbach. |\n| `LOGIN_PAUSED` | Logowanie czasowo wstrzymane - spróbuj później. |\n| **Pozycje i produkty** | |\n| `LINES_REQUIRED` | Zamówienie bez pozycji. |\n| `LINES_TOO_MANY` | Ponad 200 pozycji. |\n| `LINE_CODE_REQUIRED` | Pozycja bez kodu. |\n| `LINE_DUPLICATE` | Kod powtórzony - ilości należy zsumować. |\n| `LINE_QUANTITY_INVALID` | Ilość nie jest liczbą całkowitą większą od 0. |\n| `LINE_QUANTITY_TOO_LARGE` | Ponad 9999 szt. na pozycję. |\n| `PRODUCT_NOT_FOUND` | Nieznany kod produktu. |\n| `PRODUCT_NOT_AVAILABLE` | Produkt niedostępny w ofercie. |\n| `PRODUCT_NOT_SELLABLE` | Produkt czasowo niedostępny w sprzedaży. |\n| `OUT_OF_STOCK` | Niewystarczający stan magazynowy. |\n| `QUANTITY_NOT_MULTIPLE` | Ilość nie jest wielokrotnością opakowania. |\n| `QUANTITY_BELOW_MINIMUM` | Ilość poniżej minimum dla produktu. |\n| `QUANTITY_ABOVE_MAXIMUM` | Ilość powyżej maksimum dla produktu. |\n| `CART_BELOW_MINIMUM` | Wartość poniżej minimum zamówienia. |\n| `CURRENCY_UNKNOWN` | Nieznana waluta. |\n| `CURRENCY_FORCED` | Dla zamówienia obowiązuje inna waluta. |\n| **Dostawa i etykiety** | |\n| `SHIPPING_METHOD_REQUIRED` | Nie wybrano formy dostawy. |\n| `SHIPPING_METHOD_NOT_ALLOWED` | Nieznany albo niedostępny alias. |\n| `SHIPPING_METHOD_UNAVAILABLE` | Forma czasowo niedostępna. |\n| `SHIPPING_METHOD_WEBSITE_ONLY` | Forma dostępna wyłącznie w sklepie internetowym. |\n| `SHIPPING_METHOD_NOT_IN_COUNTRY` | Forma niedostępna dla kraju dostawy. |\n| `SHIPPING_METHOD_EXCLUDED_FOR_ACCOUNT` | Forma wyłączona dla konta. |\n| `SHIPPING_METHOD_EXCLUDED_BY_PRODUCT` | Produktu nie można wysłać tą formą. |\n| `SHIPPING_METHOD_WEIGHT_LIMIT` | Przekroczony limit wagi formy. |\n| `SHIPPING_METHOD_CART_VALUE_LIMIT` | Wartość zamówienia poza zakresem formy. |\n| `SHIPPING_METHOD_DROPSHIPPING_MISMATCH` | Forma nie pasuje do trybu dropshippingu. |\n| `SHIPPING_METHOD_AMBIGUOUS` | Nie można ustalić formy dostawy dla kraju dostawy. |\n| `PICKUP_POINT_REQUIRED` | Brak kodu punktu odbioru. |\n| `PICKUP_POINT_UNKNOWN` | Punkt nie istnieje lub jest nieaktywny. |\n| `PICKUP_POINT_NOT_ALLOWED` | Forma nie obsługuje punktów odbioru. |\n| `LABEL_REQUIRED` | Forma wymaga etykiety. |\n| `LABEL_NOT_ALLOWED` | Forma nie przyjmuje etykiety. |\n| `LABEL_TOO_MANY` | Więcej niż jedna etykieta. |\n| `LABEL_INVALID` | Etykieta nie jest poprawnym plikiem PDF w base64. |\n| `LABEL_TOO_LARGE` | Etykieta przekracza 5 MB. |\n| `LABEL_FILE_TYPE_NOT_ALLOWED` | Niedozwolony typ pliku etykiety. |\n| `LABEL_FORMAT_NOT_ALLOWED` | Etykieta nie jest jedną stroną w formacie A6. |\n| `LABEL_REFERENCE_INVALID` | Niepoprawny numer przesyłki (`trackingNumber`). |\n| `LABEL_TRACKING_NUMBER_TAKEN` | Numer przesyłki już użyty. |\n| `OWN_TRANSPORT_ONE_PACKAGE` | Transport własny: jedna paczka na zamówienie. |\n| **Płatność** | |\n| `PAYMENT_METHOD_REQUIRED` | Nie wybrano płatności. |\n| `PAYMENT_METHOD_NOT_ALLOWED` | Nieznany albo niedostępny alias. |\n| `PAYMENT_METHOD_UNAVAILABLE` | Płatność czasowo niedostępna. |\n| `PAYMENT_METHOD_WEBSITE_ONLY` | Płatność dostępna wyłącznie w sklepie internetowym (np. pobranie). |\n| `SHIPPING_PAYMENT_PAIR_NOT_ALLOWED` | Płatność niedostępna z tą formą dostawy. |\n| `PAYMENT_METHOD_DROPSHIPPING_MISMATCH` | Płatność nie pasuje do trybu dropshippingu. |\n| `PAYMENT_METHOD_NOT_IN_COUNTRY` | Płatność niedostępna dla kraju. |\n| `PAYMENT_METHOD_NOT_IN_CURRENCY` | Płatność niedostępna dla waluty. |\n| `PAYMENT_METHOD_EXCLUDED_FOR_ACCOUNT` | Płatność wyłączona dla konta. |\n| `PAYMENT_METHOD_EXCLUDED_BY_PRODUCT` | Produkt wyklucza tę płatność. |\n| **Adres i teksty** | |\n| `RECIPIENT_INVALID` | Adres dostawy nie jest obiektem. |\n| `RECIPIENT_INCOMPLETE` | Adres dostawy niekompletny. |\n| `RECIPIENT_COUNTRY_UNKNOWN` | Nieznany kraj (kod ISO 3166-1 alfa-3). |\n| `RECIPIENT_EMAIL_INVALID` | Niepoprawny format e-maila odbiorcy. |\n| `DROPSHIPPING_NOT_ALLOWED` | Konto bez dropshippingu. |\n| `DROPSHIPPING_RECIPIENT_REQUIRED` | Dropshipping bez adresu odbiorcy. |\n| `COMMENT_TOO_LONG` | Tekst przekracza dopuszczalną długość. |\n| `TEXT_TOO_LONG` | Tekst przekracza dopuszczalną długość. |\n| `TEXT_CONTROL_CHARACTERS` | Znak sterujący w polu jednowierszowym. |\n| `TEXT_UNSUPPORTED_CHARACTERS` | Nieobsługiwany znak (np. emoji). |\n| `TEXT_NOT_ALLOWED` | Znacznik HTML lub skrypt w tekście. |\n| **Przetwarzanie** | |\n| `ORDER_IN_PROGRESS` | Zamówienie z tym `externalId` jest właśnie przetwarzane. |\n| `ORDER_REJECTED` | Zamówienie nie zostało przyjęte. |\n| `SERVICE_UNAVAILABLE` | Usługa czasowo niedostępna - ponów później z tym samym `externalId`. |\n| `INTERNAL_ERROR` | Nieoczekiwany błąd. |"
     },
     "message": {
      "type": "string",
      "description": "Komunikat po polsku, do wyświetlenia."
     },
     "field": {
      "type": "string",
      "example": "lines[0]",
      "description": "Pole żądania, którego dotyczy błąd."
     },
     "step": {
      "type": "integer",
      "enum": [
       1,
       2,
       3,
       4
      ]
     },
     "hint": {
      "type": "string",
      "example": "najbliższe: 6 albo 12"
     }
    }
   },
   "ErrorResponse": {
    "type": "object",
    "required": [
     "errors"
    ],
    "properties": {
     "valid": {
      "type": "boolean",
      "enum": [
       false
      ]
     },
     "errors": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Catalog": {
    "type": "object",
    "properties": {
     "country": {
      "type": "string",
      "example": "DEU",
      "description": "Kraj dostawy, którego dotyczy lista."
     },
     "countrySource": {
      "type": "string",
      "example": "account",
      "description": "`query` - z parametru `country`, `account` - z adresu dostawy na koncie, `default` - domyślny kraj sklepu."
     },
     "countryChecked": {
      "type": "boolean"
     },
     "dropshipping": {
      "type": "boolean"
     },
     "dropshippingAllowed": {
      "type": "boolean",
      "nullable": true,
      "description": "Czy konto ma dropshipping."
     },
     "shipping": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CatalogEntry"
      }
     },
     "payment": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/CatalogEntry"
      }
     }
    }
   },
   "CatalogEntry": {
    "type": "object",
    "required": [
     "alias",
     "name",
     "available"
    ],
    "properties": {
     "alias": {
      "type": "string",
      "description": "Wartość dla `shippingMethod` / `paymentMethod`."
     },
     "name": {
      "type": "string"
     },
     "available": {
      "type": "boolean"
     },
     "reason": {
      "type": "string",
      "description": "Dlaczego pozycja jest niedostępna."
     },
     "method": {
      "type": "object",
      "description": "Forma dostawy właściwa dla tego kraju.",
      "properties": {
       "id": {
        "type": "integer"
       },
       "name": {
        "type": "string"
       }
      }
     },
     "labelRequired": {
      "type": "boolean",
      "description": "Zamówienie musi zawierać etykietę."
     },
     "excludedForAccount": {
      "type": "boolean",
      "description": "Wyłączona dla konta - zmienia to opiekun handlowy."
     },
     "availableOnWebsite": {
      "type": "boolean",
      "description": "Dostępna wyłącznie w sklepie internetowym."
     },
     "info": {
      "type": "string"
     },
     "description": {
      "type": "string"
     }
    }
   }
  }
 }
}