Skip to main content
Skip table of contents

Dodawanie pojedynczego produktu

Sposób działania

Import produktów to proces dwuetapowy (ładowanie wsadowe):

  1. POST /import/products/v2/load_data — wgrywa zbiór definicji produktów (plik JSON) do bufora danych. Można go wywołać wielokrotnie z parametrem continueUpload=1, aby doklejać kolejne paczki do bufora (continueUpload=0 czyści bufor przed wgraniem).

  2. 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-dataNIE 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 file

plik JSON z tablicą definicji produktów, type=application/jsontutaj trafia payload (nie do treści żądania)

Pole formularza continueUpload

0 = czyści bufor przed wgraniem; 1 = doklej kolejną paczkę

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.

5907595646406

X (255) *

additional_code

Pole

Opis

Przykład

Typ

ean

Numer EAN (13 cyfr) identyfikujący produkt

5907595646406

[0-9] (13)

sku

Stock Keeping Unit — kod identyfikujący produkt

Mac Book Air 13,3

X (45)

supplier_product_code

Kod produktu nadany przez dostawcę

5907595646406

X (255)

information

Pole

Opis

Typ

name

Nazwa produktu w językach (pl, en, de, ru, es, fr, it). Format JSON jak w przykładzie.

JSON

description

Opis produktu w językach (HTML dozwolony).

JSON

is_active

Czy produkt jest publikowany na froncie (0 = nie [domyślnie], 1 = tak)

[0-1]

is_promoted

Czy produkt jest promowany (0 = nie [domyślnie], 1 = tak)

[0-1]

metadata

Pole

Opis

Typ

metatitle

SEO: meta tytuł w językach

JSON

keywords

SEO: słowa kluczowe w językach

JSON

metadescription

SEO: meta opis w językach

JSON

slug

Przyjazny URL w językach

JSON

categories

Pole

Opis

Typ

paths

Wszystkie kategorie, w których jest produkt. Pierwsza kategoria jest główną. Pełna ścieżka, separator /, w językach.

JSON

price

Pole

Opis

Przykład

Typ

srp_netto

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.

4499.99

R2

base_netto

Minimalna cena netto, za którą produkt może być sprzedany (próg).

4000.00

R2

purchase_netto

Cena zakupu netto.

3300.99

R2

vat

Stawka VAT produktu (cecha produktu).

23

[0-9]

Cena jednostki sprzedażowej = cena katalogowa × rate tej jednostki, z opcjonalnym rabatem discount — patrz sekcja units.

manufacturer

Pole

Opis

Typ

name

Nazwa producenta

X (45)

logo

URL do logo producenta

X (255)

energy_class

Pole

Opis

Typ

energy_class

Klasa energetyczna produktu

[A-G] (1)

energy_label_link

Link do etykiety klasy energetycznej (PDF)

X (255)

energy_card_information_link

Link do karty informacyjnej produktu (PDF)

X (255)

stock — stany magazynowe i flaga "stock impact"

Pole

Opis

Przykład

Typ

stock_enabled

Flaga „Włącz stany magazynowe dla produktu" (stock impact). 1 = produkt podlega kontroli stanu magazynowego; 0 = produkt NIE wpływa na stan (np. usługa, produkt na zamówienie). Gdy pominięte — domyślnie 1 (TRUE).

1

[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.

  • Aktualizacjastock_enabled na 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 — pole stock.unitnie istnieje i jest ignorowane.

delivery_date — czas dostawy zapisywany do magazynów (tablica wpisów per magazyn):

Pole

Opis

Przykład

Typ

delivery_format

Czas dostawy (w językach). Pusty → dziedziczony z magazynu.

{"pl":"7 dni"}

JSON

delivery_hour

Czas dostawy w godzinach

168

[0-9]

warehouse_external_id

External ID magazynu, którego dotyczy wpis

1

[0-9]

restocking_date

Spodziewana data uzupełnienia

2025-02-02

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 rate jest 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

active = 1 (jednostka aktywna)

Domyślnie prezentowana

default_unit = 1 (jednostka domyślna/główna)

Domyślna jednostka podstawowa

primary_unit = 1 (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

external_id

Kod jednostki — musi już istnieć w Słowniku. Nieznany kod → jednostka odrzucona (zgłaszana w raporcie, patrz niżej).

szt.

X (20)

primary_unit

Czy to jednostka podstawowa (przeliczniki i stan liczone względem niej). Maks. jedna na produkt.

1

[0-1]

default_unit

Czy to jednostka domyślna (wstępnie wybrana). Maks. jedna na produkt; musi być aktywna.

1

[0-1]

active

Czy jednostka jest aktywna (widoczna/wybieralna).

1

[0-1]

rate

Przelicznik względem jednostki podstawowej (dla primary = 1).

10.00

R2

discount

Rabat (%) naliczany dla tej jednostki (≥ 0).

10

[0-9]

minimum_sales_quantity

Minimalna ilość zamówienia w tej jednostce (liczba całkowita > 0).

1

[0-9]

package

Pole

Opis

Typ

name

Nazwa opakowania zdefiniowanego wcześniej w systemie

X (255)

dimensions.height / width / length

Wymiary opakowania w centymetrach

R2

dimensions.weight

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

photos

Lista URL-i zdjęć produktu (bez limitu)

JSON

files

Lista par [nazwa, URL] plików produktu (bez limitu)

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_data zwraca m.in. liczniki wgranych wierszy oraz stock_unit_ignored — listę kodów produktów, które przysłały nieobsługiwane pole stock.unit (przypomnienie: jednostki definiuj w bloku units).

  • /run zwraca {"status":"ok","report":{...}}, gdzie report zawiera:

    • invalid_units — lista {product_code, external_id, reason} jednostek odrzuconych (np. nieznany external_id, nie-całkowite/ujemne minimum_sales_quantity, ujemny rate/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 tablica units → 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

JSON
[
  {
    "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" }
    ]
  }
]
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.