Dodawanie pojedynczego produktu
Sposób działania
Import produktów to proces dwuetapowy (ładowanie wsadowe):
POST
/import/products/v2/load_data— wgrywa zbiór definicji produktów (plik JSON) do bufora danych. Można go wywołać wielokrotnie z parametremcontinueUpload=1, aby doklejać kolejne paczki do bufora (continueUpload=0czyści bufor przed wgraniem).POST
/import/products/v2/run— przenosi dane z bufora do bazy produkcyjnej (jednorazowo, dla całej zawartości bufora).
Podczas przenoszenia system sprawdza, czy dany kod produktu (pole code) już istnieje. Jeśli produkt o tym kodzie już istnieje — zostaje pominięty (import nie nadpisuje istniejących produktów).
Tworzenie vs aktualizacja — to jest endpoint do DODAWANIA nowych produktów.
Ponieważ istniejące kody są pomijane, nie da się tym endpointem zaktualizować już istniejącego produktu — w szczególności jego flagi stock_enabled, cen ani jednostek sprzedażowych. Ponowny import tego samego code nie wprowadzi żadnych zmian.
Aby zaktualizować istniejący produkt (w tym stock_enabled, ceny, jednostki sprzedażowe), użyj endpointu POST /import/product/update — patrz sekcja Aktualizacja istniejących produktów na końcu artykułu.
Jak wysłać request
Endpoint load_data przyjmuje dane jako multipart/form-data — NIE jako surowe body JSON. Tablica produktów (JSON) jest wysyłana jako plik w polu formularza file. {instancja} = adres API Twojej instancji Saly (np. https://twoja-domena/api).
Krok 1 — token. Wyślij POST na /user/token w formacie application/x-www-form-urlencoded z polami username oraz hasłem. W odpowiedzi otrzymasz access_token — wstaw go do nagłówka autoryzacji (typ Bearer) w kolejnych żądaniach.
Krok 2 — load_data (POST /import/products/v2/load_data), żądanie typu multipart/form-data:
Element żądania | Wartość |
|---|---|
Nagłówek autoryzacji | typ Bearer z tokenem z kroku 1 |
Pole formularza | plik JSON z tablicą definicji produktów, |
Pole formularza |
|
Krok 3 — run (POST /import/products/v2/run): nagłówek Bearer, parametry w query string: truncate_all_products oraz truncate_all_categories (zwykle oba 0). Odpowiedź zawiera report (patrz „Odpowiedź i raport").
Gotowe polecenia curl dla wszystkich trzech kroków znajdziesz w zewnętrznej dokumentacji technicznej API. Najważniejsze: payload to plik w polu file (multipart), a nie surowe body JSON.
Typy produktów
Tym endpointem można dodać dwa typy produktów:
Produkt pojedynczy
Rodzina produktów (warianty)
Produkt pojedynczy — dokumentacja pól
Legenda kolumny typ: * pole wymagane · X dowolne znaki · [0-1] tylko 0 lub 1 · [0-9] liczby · R2 liczba dziesiętna z 2 miejscami · JSON obiekt/tablica JSON · (x) limit znaków · date (YYYY-mm-dd) data.
code WYMAGANE
Opis | Przykład | Typ |
|---|---|---|
Unikalny kod produktu w Saly. Klucz identyfikujący produkt — po nim sprawdzane jest, czy produkt już istnieje. |
| X (255) * |
additional_code
Pole | Opis | Przykład | Typ |
|---|---|---|---|
| Numer EAN (13 cyfr) identyfikujący produkt |
| [0-9] (13) |
| Stock Keeping Unit — kod identyfikujący produkt |
| X (45) |
| Kod produktu nadany przez dostawcę |
| X (255) |
information
Pole | Opis | Typ |
|---|---|---|
| Nazwa produktu w językach (pl, en, de, ru, es, fr, it). Format JSON jak w przykładzie. | JSON |
| Opis produktu w językach (HTML dozwolony). | JSON |
| Czy produkt jest publikowany na froncie (0 = nie [domyślnie], 1 = tak) | [0-1] |
| Czy produkt jest promowany (0 = nie [domyślnie], 1 = tak) | [0-1] |
metadata
Pole | Opis | Typ |
|---|---|---|
| SEO: meta tytuł w językach | JSON |
| SEO: słowa kluczowe w językach | JSON |
| SEO: meta opis w językach | JSON |
| Przyjazny URL w językach | JSON |
categories
Pole | Opis | Typ |
|---|---|---|
| Wszystkie kategorie, w których jest produkt. Pierwsza kategoria jest główną. Pełna ścieżka, separator | JSON |
price
Pole | Opis | Przykład | Typ |
|---|---|---|---|
| Cena katalogowa (sprzedażowa) netto — to jest cena, od której liczone są rabaty i którą widzi klient jako cenę produktu w jednostce podstawowej. |
| R2 |
| Minimalna cena netto, za którą produkt może być sprzedany (próg). |
| R2 |
| Cena zakupu netto. |
| R2 |
| Stawka VAT produktu (cecha produktu). |
| [0-9] |
Cena jednostki sprzedażowej = cena katalogowa × rate tej jednostki, z opcjonalnym rabatem discount — patrz sekcja units.
manufacturer
Pole | Opis | Typ |
|---|---|---|
| Nazwa producenta | X (45) |
| URL do logo producenta | X (255) |
energy_class
Pole | Opis | Typ |
|---|---|---|
| Klasa energetyczna produktu | [A-G] (1) |
| Link do etykiety klasy energetycznej (PDF) | X (255) |
| Link do karty informacyjnej produktu (PDF) | X (255) |
stock — stany magazynowe i flaga "stock impact"
Pole | Opis | Przykład | Typ |
|---|---|---|---|
| Flaga „Włącz stany magazynowe dla produktu" (stock impact). |
| [0-1] |
Ważne o stock_enabled:
To jest tylko flaga (czy produkt śledzi stan), NIE ilość. Poziomy stanu (ilości w magazynach) wgrywa się osobnym importem stanów (
/import/product_stocks), nie tym endpointem.Aktualizacja
stock_enabledna istniejącym produkcie nie zadziała przez ten endpoint (istniejące kody są pomijane) — użyj/import/product/update.Jednostki sprzedażowe definiuje się wyłącznie w bloku
units— polestock.unitnie istnieje i jest ignorowane.
delivery_date — czas dostawy zapisywany do magazynów (tablica wpisów per magazyn):
Pole | Opis | Przykład | Typ |
|---|---|---|---|
| Czas dostawy (w językach). Pusty → dziedziczony z magazynu. |
| JSON |
| Czas dostawy w godzinach |
| [0-9] |
| External ID magazynu, którego dotyczy wpis |
| [0-9] |
| Spodziewana data uzupełnienia |
| date |
units — jednostki sprzedażowe i ich ceny
Sekcja units to tablica jednostek sprzedażowych produktu. Każda jednostka musi odwoływać się (przez external_id) do jednostki wcześniej zdefiniowanej w Słownikach → Jednostki sprzedażowe w panelu administratora.
Model i ceny jednostek
Jednostka podstawowa (primary) — baza wszystkich przeliczeń i jednostka, w której śledzony jest stan magazynowy. Jej
ratejest zawsze 1 (niezmienny).rate(przelicznik) — ile jednostek podstawowych mieści jedna ta jednostka. Cena tej jednostki = cena katalogowa (srp_netto) ×rate.discount(rabat %) — rabat naliczany, gdy wybrana jest ta jednostka.minimum_sales_quantity— minimalna ilość zamówienia w tej jednostce (liczba całkowita > 0).Jednostka domyślna (default) — wstępnie wybrana przy wyświetlaniu; musi być aktywna.
active— czy jednostka jest widoczna i wybieralna przez klienta.
Gwarancja integralności (egzekwowana przez importer): każdy produkt po imporcie ma dokładnie jedną aktywną jednostkę podstawową oraz dokładnie jedną aktywną jednostkę domyślną. Jeśli w bloku units nie oznaczysz żadnej jednostki jako primary_unit=1 (albo jednostka okaże się nieprawidłowa), importer automatycznie wybierze jednostkę podstawową na podstawie domyślnych ustawień Słownika — produkt nigdy nie zostanie bez jednostki podstawowej.
Brak sekcji units — zachowanie słownikowe
Dodanie sekcji units jest opcjonalne. Gdy jej nie podasz, jednostki nowego produktu zostaną ustawione zgodnie z flagami domyślności w Słowniku. Trzy flagi słownika są honorowane niezależnie:
Flaga w Słowniku | Ustawia na produkcie |
|---|---|
Domyślnie aktywna |
|
Domyślnie prezentowana |
|
Domyślna jednostka podstawowa |
|
Niezależność oznacza, że np. jednostka z Domyślnie aktywna = ON i Domyślnie prezentowana = OFF będzie na produkcie aktywna, ale NIE domyślna. Jednostka bez żadnej z flag pozostanie nieaktywna.
Pola jednostki
Pole | Opis | Przykład | Typ |
|---|---|---|---|
| Kod jednostki — musi już istnieć w Słowniku. Nieznany kod → jednostka odrzucona (zgłaszana w raporcie, patrz niżej). |
| X (20) |
| Czy to jednostka podstawowa (przeliczniki i stan liczone względem niej). Maks. jedna na produkt. |
| [0-1] |
| Czy to jednostka domyślna (wstępnie wybrana). Maks. jedna na produkt; musi być aktywna. |
| [0-1] |
| Czy jednostka jest aktywna (widoczna/wybieralna). |
| [0-1] |
| Przelicznik względem jednostki podstawowej (dla primary = 1). |
| R2 |
| Rabat (%) naliczany dla tej jednostki (≥ 0). |
| [0-9] |
| Minimalna ilość zamówienia w tej jednostce (liczba całkowita > 0). |
| [0-9] |
package
Pole | Opis | Typ |
|---|---|---|
| Nazwa opakowania zdefiniowanego wcześniej w systemie | X (255) |
| Wymiary opakowania w centymetrach | R2 |
| Waga opakowania w kilogramach | R2 |
attributes
Parametry techniczne produktu pogrupowane i w docelowej kolejności wyświetlania, w językach (JSON). Format jak w przykładzie poniżej.
multimedia
Pole | Opis | Typ |
|---|---|---|
| Lista URL-i zdjęć produktu (bez limitu) | JSON |
| Lista par | JSON |
Odpowiedź i raport importu
Import jest nieblokujący — poprawne produkty zostaną zaimportowane, a o problemach z poszczególnymi jednostkami dowiesz się z odpowiedzi (batch nie jest odrzucany).
/load_datazwraca m.in. liczniki wgranych wierszy orazstock_unit_ignored— listę kodów produktów, które przysłały nieobsługiwane polestock.unit(przypomnienie: jednostki definiuj w blokuunits)./runzwraca{"status":"ok","report":{...}}, gdziereportzawiera:invalid_units— lista{product_code, external_id, reason}jednostek odrzuconych (np. nieznanyexternal_id, nie-całkowite/ujemneminimum_sales_quantity, ujemnyrate/discount, wiele jednostek domyślnych);products_without_primary_fallback_applied— produkty, dla których importer musiał automatycznie ustalić jednostkę podstawową (gdy payload jej nie wskazał);proc_errors— błędy procedury (jeśli wystąpiły).
Dzięki temu masz pewność, które jednostki zostały przyjęte, a które wymagają poprawy w kolejnym imporcie.
Aktualizacja istniejących produktów
Endpoint /import/products/v2/* tylko dodaje nowe produkty. Aby zmienić dane istniejącego produktu — w tym stock_enabled, ceny i jednostki sprzedażowe — użyj:
POST /import/product/update
Aktualizuje wskazane pola istniejących produktów (m.in.
stock_enabled, ceny, jednostki).Dla jednostek sterowanie trybem przez
units_increase:0= zastąp komplet jednostek nowym zestawem;1= aktualizacja częściowa (modyfikuje/dodaje przesłane jednostki, resetując konkurujące primary/default). Pusta tablicaunits→ istniejące jednostki pozostają bez zmian.Reguły integralności jednostek (dokładnie 1 primary, 1 aktywna default) obowiązują tak samo.
Przykładowy plik
[
{
"code": "5907595646406",
"additional_code": {
"ean": "5907595646406",
"sku": "Mac Book Air 13,3",
"supplier_product_code": "5907595646406"
},
"information": {
"name": { "pl": "MacBook Air 13 gwiezdna szarość", "en": "MacBook Air 13 Space Gray" },
"description": { "pl": "<h4>MacBook Air 13</h4><p>opis</p>" },
"is_active": "1",
"is_promoted": "0"
},
"metadata": {
"metatitle": { "pl": "MacBook Air 13 gwiezdna szarość" },
"keywords": { "pl": "MacBook,Air,13" },
"metadescription": { "pl": "MacBook Air 13 - najlepsza cena" },
"slug": { "pl": "MacBook_Air_13_gwiezdna_szarosc" }
},
"categories": {
"paths": [ { "pl": "Laptopy/Apple/MacBook Air 13" } ]
},
"price": {
"base_netto": "4000.00",
"purchase_netto": "3300.99",
"srp_netto": "4499.99",
"vat": "23"
},
"manufacturer": { "name": "Apple", "logo": "https://www.apple.com/logo.png" },
"energy_class": {
"energy_class": "A",
"energy_label_link": "https://link.pdf",
"energy_card_information_link": "https://link.pdf"
},
"stock": {
"stock_enabled": "1",
"delivery_date": [
{ "delivery_format": {"pl": "7 dni"}, "delivery_hour": "168", "warehouse_external_id": "1", "restocking_date": "2025-02-02" }
]
},
"package": {
"name": "Euro-pallet",
"dimensions": { "height": "100.00", "width": "100.00", "length": "100.00", "weight": "10.00" }
},
"attributes": {
"pl": [ { "Dane techniczne": [ ["Kolor", "czerwony"], ["Rozmiar", "średni"] ] } ]
},
"multimedia": {
"photos": [ "https://example.com/photo1.jpg" ],
"files": [ ["file1.pdf", "https://example.com/file1.pdf"] ]
},
"units": [
{ "external_id": "szt.", "primary_unit": "1", "default_unit": "1", "active": "1", "rate": "1.0", "discount": "0", "minimum_sales_quantity": "1" },
{ "external_id": "opk", "primary_unit": "0", "default_unit": "0", "active": "1", "rate": "10.0", "discount": "10", "minimum_sales_quantity": "1" }
]
}
]