Live — produkcja

Asgard API
Kompleksowa dokumentacja

Produkty, Twoje ceny, znakowania i zamówienia w jednym miejscu. REST API gotowe do integracji.

GET  /api/products-index/ GET  /api/client-products/ GET  /api/marking-data/ POST /api/orders/ 🔒 JWT Bearer
🔒  Zaloguj się do panelu Dokumentacja Swagger 🌐  English
⚡

Pierwsze kroki

Każde żądanie do chronionych endpointów wymaga ważnego tokena JWT w nagłówku. Poniżej trzyetapowy quick-start.

1
Pobierz token JWT
Wyślij POST /api/token/ z loginem i hasłem. Otrzymasz access (ważny 5 min) oraz refresh.
2
Dodaj nagłówek do każdego żądania
Authorization: Bearer <access_token>
3
Odświeżaj token przed wygaśnięciem
Użyj POST /api/token/refresh/ z polem refresh, by dostać nowy access bez ponownego logowania.
👥
Dostęp do API przyznaje opiekun Twojego konta. Swagger UI z pełnym podglądem endpointów dostępny pod adresem /docs/.
🔒

Autoryzacja JWT

API używa JWT (JSON Web Token). Token przekazuj w nagłówku Authorization przy każdym żądaniu.

POST /api/token/
POST /api/token/
Content-Type: application/json

{
  "username": "twoj_login",
  "password": "twoje_haslo"
}
Odpowiedź 200 OK
{
  "access":  "eyJhbGci...",   // <-- używaj tego, wygasa po 5 min
  "refresh": "eyJhbGci..."    // <-- do odświeżenia, ważny 1 dzień
}
Nagłówek w każdym żądaniu
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
⏱
Token access wygasa po 5 minutach. Odświeżaj go przez POST /api/token/refresh/ z ciałem {"refresh": "..."}.
■

Produkty — przegląd

API udostępnia kilka endpointów produktowych zoptymalizowanych pod różne przypadki użycia: pełne dane, Twoje ceny, stany magazynowe i aktualizacje.

GET/api/products-index/pełne dane, lookup po index
GET/api/products-index/{index}/jeden produkt po indeksie
GET/api/client-products/pełne dane + cena katalogowa i Twoja cena zakupu
GET/api/my-prices/Twoje ceny produktów
GET/api/promo-prices/obowiązujące ceny promocyjne
GET/api/promo-prices/{index}/promocja produktu po indeksie
GET/api/products/lista aktywnych (lookup po id)
GET/api/stock-info/tylko indeks + stan magazynowy
GET/api/last-update/zaktualizowane w ostatnich 45 min
✨
Do codziennej synchronizacji polecamy /api/products-index/ — dane zwracane po indeksie produktu, co upraszcza mapowanie do własnych systemów.
📄

Pełna lista produktów

Endpoint /api/products-index/ zwraca aktywne produkty ze wszystkimi powiązanymi danymi zagnieżdżonymi w jednej odpowiedzi.

Pobierz wszystkie produkty
GET  /api/products-index/             // lista wszystkich
GET  /api/products-index/ABC-123/      // jeden produkt po indeksie
Authorization: Bearer <token>

Co zawiera jeden produkt:

PoleTypOpis
indexstringUnikalny kod produktu (klucz w URL)
quantityintegerAktualny stan magazynowy
activebooleanCzy produkt jest aktywny
names[]arrayNazwy w językach: name_pl, name_en, name_de, name_fr, name_cz
descriptions[]arrayOpisy wielojęzyczne
prices[]arrayCeny: pln, eur, chf, czk
madeof[]arraySkład materiałowy (wielojęzyczny)
image[]arrayAdresy URL zdjęć produktu
additional[]arrayAtrybuty dodatkowe (klucz–wartość)
future_delivery[]arrayPlanowane dostawy: data + ilość
marking_data[]arrayDane znakowania (nested: miejsca, opcje)
category / subcategoryintegerID kategorii i podkategorii
new_product, promotion, salebooleanFlagi statusu produktu
💰

Produkty z Twoimi cenami

Endpoint /api/client-products/ zwraca te same dane co /api/products-index/ — wszystkie pola, filtry i wyszukiwanie — uzupełnione o cenę katalogową i Twoją cenę zakupu. Wygodny, gdy budujesz ofertę lub koszyk i potrzebujesz danych produktu razem z ceną w jednym żądaniu.

GET/api/client-products/lista produktów z cenami (100 na stronę)
GET/api/client-products/{index}/jeden produkt po indeksie
?qty=100 ?search=AP8000 ?index=AP800001-01 ?category=12 ?new_product=true ?page=2
Produkt z cenami dla 100 szt.
GET  /api/client-products/AP800001-01/?qty=100
Authorization: Bearer <token>

// Odpowiedź:
{
  "id":                 142,
  "index":              "AP800001-01",
  "quantity":           4520,
  ... // wszystkie pola jak w products-index
  "currency":           "PLN",
  "catalogue_price":    "10.00",   // cena katalogowa netto
  "purchase_price":     "7.90",   // Twoja cena zakupu netto
  "price_source":       "individual",
  "no_discount":        true,
  "discount_percent": "10.00"
}

Pola cenowe (dodatkowe względem products-index):

PoleTypOpis
currencystringWaluta Twojego konta (PLN / EUR / CHF / CZK).
catalogue_pricedecimal | nullCena katalogowa netto za sztukę, przed rabatem.
purchase_pricedecimal | nullTwoja cena zakupu netto za sztukę — tyle zapłacisz w zamówieniu.
price_sourcestringbase / discount / individual / promo — skąd pochodzi cena zakupu.
no_discountbooleantrue — cena indywidualna lub promocyjna, rabat nie jest naliczany.
discount_percentdecimalTwój rabat dla tego produktu (0 gdy produkt nie jest objęty rabatem).
↓
Cena zakupu to najniższa z: ceny katalogowej po Twoim rabacie, Twojej ceny indywidualnej i ceny promocyjnej. Ceny progowe zależą od ilości — podaj ?qty= równe ilości, którą zamawiasz. Szczegóły i progi cenowe: Twoje ceny.
📈

Stany magazynowe

Lekki endpoint zwracający wyłącznie indeks i ilość — idealny do częstej synchronizacji stanów.

GET /api/stock-info/
GET  /api/stock-info/
Authorization: Bearer <token>

// Odpowiedź:
{
  "count":    1250,
  "next":     "/api/stock-info/?page=2",
  "previous": null,
  "results": [
    { "index": "ABC-123", "quantity": 450 },
    { "index": "XYZ-007", "quantity": 0 },
    ...
  ]
}
↻
Endpoint /api/last-update/ zwraca produkty zmienione w ostatnich 45 minutach — używaj go do inkrementalnej synchronizacji zamiast pobierania całego katalogu.
⍂

Filtrowanie i wyszukiwanie

Wszystkie endpointy produktowe obsługują filtrowanie przez parametry GET i paginację (100 wyników na stronę).

Parametry /api/products-index/:

?search=ABC ?index=ABC-123 ?category=5 ?new_product=true ?discount_prices=true ?promotion=true ?sale=true ?page=2
Przykłady filtrowania
// Produkty z kategorii ID=5 z rabatem
GET  /api/products-index/?category=5&discount_prices=true

// Nowości - strona 2
GET  /api/products-index/?new_product=true&page=2

// Szukaj po fragmencie indeksu
GET  /api/products-index/?search=ABC

// Kategorie i podkategorie
GET  /api/categories/
GET  /api/subcategories/
{

Struktura odpowiedzi produktu

Pełna struktura JSON jednego produktu z /api/products-index/{index}/.

Przykład odpowiedzi
{
  "id":              142,
  "index":         "ABC-123",
  "quantity":      450,
  "active":        true,
  "new_product":   false,
  "promotion":     false,
  "sale":          false,
  "discount_prices": true,
  "category":      5,
  "subcategory":   12,

  "names": [
    { "id": 1, "language": "name_pl", "title": "Kubek termiczny 350ml" },
    { "id": 2, "language": "name_en", "title": "Thermal mug 350ml" }
  ],

  "prices": [
    { "pln": "24.90", "eur": "5.80", "chf": "5.50", "czk": "138.00" }
  ],

  "image": [
    { "url": "https://cdn.example.com/products/abc-123-1.jpg" },
    { "url": "https://cdn.example.com/products/abc-123-2.jpg" }
  ],

  "future_delivery": [
    { "quantity": 200, "date": "2026-03-15" }
  ],

  "additional": [
    { "item": "wymiary", "value": "8.5 x 8.5 x 12 cm" },
    { "item": "waga",    "value": "210g" }
  ],

  "marking_data": [ /* patrz sekcja Znakowanie */ ],

  // ... names, descriptions, madeof, marking (text)
}
☍

Znakowanie — architektura danych

Dane znakowania mają hierarchiczną strukturę. Każdy produkt może mieć wiele miejsc znakowania, a każde miejsce — kilka opcji z różnymi cenami.

Produkt
Product
→
Dane znakowania
MarkingData
→
Miejsce
MarkingPlace
→
Opcja / Metoda
MarkingOption
→
Progi cenowe
PriceCode

Jeden produkt → wiele miejsc (np. “Front”, “Tył”) → wiele opcji (np. “Sitodruk”, “Grawerowanie”) → cena zależy od ilości zamówionych sztuk.

Pojęcia kluczowe:

ObiektOpisKluczowe pola
MarkingDataGłówny węzeł znakowania produktu. Zawiera domyślną metodę.product, default_marking_code
MarkingPlaceMiejsce na produkcie gdzie można nanieść oznaczenie.code, name_pl
MarkingOptionKonkretna technika znakowania w danym miejscu.marking_code, option_code, price_code, max_colors
MarkingVariantWariant opcji (np. rozmiar pola znakowania).variant_code, variant_label
MarkingPriceCodeKlucz cenowy — łączy opcję z progami cenowymi.code
PriceCodePróg cenowy dla danej ilości zamówionych sztuk.from_qty, to_qty, price_pln
AdditionalServiceUsługi dodatkowe do znakowania (np. setup, przesyłka wzoru).service_id, service_price_pln
☷

Endpointy znakowania

Dwa tryby dostępu: zagnieżdżony (nested — pełna hierarchia w jednym żądaniu) lub płaski (solo — każdy obiekt osobno, lżejsze odpowiedzi).

Tryb zagnieżdżony (nested):

GET/api/marking-data/pełna hierarchia w jednym żądaniu
GET/api/marking-data/?product=IDznakowanie konkretnego produktu
GET/api/marking-default/domyślna metoda per produkt (szukaj po product__index)

Tryb płaski (solo — do szczegółowego zapytania):

GET/api/marking-solodata/MarkingData, szukaj: ?search=<index>
GET/api/marking-soloplace/MarkingPlace, filtruj: ?marking_data=ID
GET/api/marking-solooption/MarkingOption, filtruj: ?marking_place=ID
GET/api/marking-additional/AdditionalService, filtruj: ?marking_data=ID
GET/api/marking-name/słownik etykiet technik znakowania
Pobierz znakowanie produktu ABC-123 (nested)
// Krok 1 — znajdź ID produktu
GET  /api/products-index/ABC-123/
// → w odpowiedzi znajdziesz "id": 142 oraz zagnieżdżone "marking_data"

// Krok 2 — lub bezpośrednio przez marking-data
GET  /api/marking-data/?product=142

// Odpowiedź (nested):
{
  "id":                    18,
  "product":              142,
  "default_marking_code": "TS-F1",
  "marking_place": [
    {
      "id":      55,
      "code":   "F1",
      "name_pl": "Przód",
      "marking_option": [
        {
          "id":            201,
          "marking_code":  "TS-F1",
          "option_code":   "TS",          // kod techniki
          "price_code":    7,           // ID → /api/marking-price/
          "max_colors":    4,
          "realisation_time_id": 3,
          "marking_variant": []
        }
      ]
    }
  ],
  "additional_service": [
    { "service_id": "SETUP", "service_price_pln": "35.00" }
  ]
}
💳

Progi cenowe znakowania

Cena za sztukę znakowania zależy od zamówionej ilości. Progi pobierasz przez price_code z opcji znakowania.

GET/api/marking-price/kody cenowe z progami (nested)
GET/api/marking-tierprice/?marking_option=IDprogi dla konkretnej opcji
Progi cenowe dla kodu “P3”
GET  /api/marking-price/?code=P3

// Odpowiedź:
{
  "id":   7,
  "code": "P3",
  "main_marking_price": [
    { "from_qty": 25,  "to_qty": 49,  "price_pln": "2.80" },
    { "from_qty": 50,  "to_qty": 99,  "price_pln": "2.20" },
    { "from_qty": 100, "to_qty": 249, "price_pln": "1.60" },
    { "from_qty": 250, "to_qty": 499, "price_pln": "1.10" }
  ]
}
▶

Typowy przepływ integracji znakowania

Jak zbudować konfigurator znakowania krok po kroku.

1
Pobierz produkt
GET /api/products-index/ABC-123/ — w odpowiedzi masz zagnieżdżone marking_data z miejscami i opcjami.
2
Wybierz miejsce i opcję znakowania
Z marking_place[] wybierz miejsce (np. “Przód”), z marking_option[] wybierz technikę (np. “Sitodruk”). Zanotuj price_code i marking_code.
3
Pobierz ceny dla wybranej opcji
GET /api/marking-price/?code=P3 (lub /api/marking-tierprice/?marking_option=ID) — wyświetl progi cenowe dla ilości klienta.
4
Pobierz usługi dodatkowe
GET /api/marking-additional/?marking_data=ID — dodaj koszty setup, przesyłki wzoru itp.
5
Złóż zamówienie
POST /api/orders/ z pozycjami — także ze znakowaniem (marking_place_code, marking_option_code, marking_colors). Zobacz Zamówienie ze znakowaniem.
✓
Zamówienia przez /api/orders/ obsługują znakowanie — kody miejsca i techniki podajesz w pozycjach zamówienia, a pliki projektów przesyłasz osobno.
💰

Twoje ceny

Endpoint /api/my-prices/ zwraca ceny obowiązujące Twoje konto — w Twojej walucie i dla podanej ilości. To te same ceny, które zostaną zastosowane przy składaniu zamówienia.

↓
Obowiązuje zawsze najniższa cena spośród: ceny katalogowej po Twoim rabacie, Twojej ceny indywidualnej i ceny promocyjnej. Od ceny indywidualnej i promocyjnej nie nalicza się rabatu — to ceny ostateczne.
sourceZnaczenie
baseCena katalogowa (produkt bez rabatu lub rabat 0%).
discountCena katalogowa po Twoim rabacie procentowym.
individualTwoja cena indywidualna — cena ostateczna, bez rabatu.
promoCena promocyjna — cena ostateczna, bez rabatu.
GET/api/my-prices/ceny produktów (paginacja 100)
GET/api/my-prices/{index}/cena jednego produktu + progi ilościowe
GET/api/client-products/{index}/produkty jak w products-index + Twoje ceny
📦
Pełne dane produktów razem z cenami zwraca /api/client-products/ — zobacz Produkty z Twoimi cenami.
?qty=100 ?index=AP800001-01,AP800002-10 ?special=1 ?page=2
Cena produktu dla 100 szt.
GET  /api/my-prices/AP800001-01/?qty=100
Authorization: Bearer <token>

// Odpowiedź:
{
  "index":               "AP800001-01",
  "currency":            "PLN",
  "qty":                 100,
  "price":               "7.90",   // obowiązująca cena netto za sztukę
  "source":              "individual",   // base | discount | individual | promo
  "no_discount":         true,   // cena ostateczna
  "base_price":          "10.00",
  "discount_percent":    "10.00",
  "discounted_price":    "9.00",
  "individual_price":    "7.90",
  "promo_price":         null,
  "individual_tiers": [
    { "from_qty": 1,   "to_qty": 99,   "price": "8.40" },
    { "from_qty": 100, "to_qty": null, "price": "7.90" }
  ],
  "promo_tiers": []
}

Pola odpowiedzi:

PoleTypOpis
pricedecimal | nullCena netto za sztukę, którą zapłacisz. null — brak ceny dla produktu.
sourcestringSkąd pochodzi cena (tabela wyżej).
no_discountbooleantrue — cena indywidualna lub promocyjna, rabat nie jest naliczany.
base_price / discounted_pricedecimal | nullCena katalogowa przed i po Twoim rabacie.
individual_price / promo_pricedecimal | nullCena indywidualna / promocyjna dla podanej ilości, jeśli istnieje.
individual_tiers[] / promo_tiers[]arrayProgi ilościowe (tylko /api/my-prices/{index}/).
✓
?special=1 zwraca tylko produkty, dla których masz cenę indywidualną lub trwa promocja. Ceny progowe zależą od ilości — podaj ?qty= równe ilości, którą zamierzasz zamówić.
🏷

Ceny promocyjne

Endpoint /api/promo-prices/ zwraca ceny promocyjne produktów. Promocje adresujesz po indeksie produktu — tak samo jak w /api/products-index/. Ceny są progowe: każdy próg określa zakres ilości i cenę za sztukę w PLN/EUR/CHF/CZK.

⚠
Od ceny promocyjnej nie nalicza się rabatu klienta. Każda odpowiedź zawiera pole "no_discount": true — nie odejmuj od tej ceny swojego rabatu procentowego.
GET/api/promo-prices/lista obowiązujących promocji
GET/api/promo-prices/{index}/promocja jednego produktu po indeksie
GET/api/promo-prices/{index}/price/cena za sztukę dla podanej ilości
Pobierz ceny promocyjne
GET  /api/promo-prices/                  // wszystkie obowiązujące promocje
GET  /api/promo-prices/ABC-123/          // jedna promocja po indeksie
GET  /api/promo-prices/?index=ABC-123,XYZ-007
Authorization: Bearer <token>

// Odpowiedź:
{
  "index":       "ABC-123",
  "active":      true,
  "date_from":   "2026-10-01",
  "date_to":     "2026-12-31",
  "is_current":  true,
  "no_discount": true,          // od tej ceny brak rabatu
  "tiers": [
    { "from_qty": 1,   "to_qty": 99,   "qty_label": "1–99",    "pln": "10.00", "eur": "2.40", "chf": null, "czk": null },
    { "from_qty": 100, "to_qty": null, "qty_label": "100+",    "pln": "8.50",  "eur": "2.05", "chf": null, "czk": null }
  ],
  "updated_at":  "2026-10-01T10:15:00+02:00"
}

Pola promocji:

PoleTypOpis
indexstringIndeks produktu (klucz w URL)
activebooleanCzy promocja jest włączona
date_fromdate | nullPoczątek obowiązywania; null = od zaraz
date_todate | nullKoniec obowiązywania (włącznie); null = bezterminowo
is_currentbooleanCzy promocja obowiązuje dzisiaj
no_discountbooleanZawsze true — od ceny promocyjnej nie ma rabatu
tiers[]arrayProgi cenowe, posortowane rosnąco po from_qty
tiers[].from_qty / to_qtyinteger | nullZakres ilości; to_qty: null = „i więcej”
tiers[].qty_labelstringCzytelna etykieta zakresu, np. "1–99", "100+"
tiers[].pln / eur / chf / czkdecimal | nullCena za sztukę w walucie; null = brak ceny w tej walucie
updated_atdatetimeData ostatniej zmiany
?index=ABC-123,XYZ-007 ?search=ABC ?page=2
ℹ
Lista zawiera tylko promocje obowiązujące dzisiaj (aktywne i mieszczące się w datach). Promocja wygasła lub przyszła zwraca 404. Pojedyncza cena „od 1 szt.” to jeden próg 1+. Promocja jest automatycznie uwzględniana w Twojej cenie zakupu — zobacz Twoje ceny.
💳

Cena promocyjna dla ilości

Zamiast samodzielnie wyszukiwać próg, możesz zapytać o cenę za sztukę dla konkretnej ilości i waluty.

?qty=150 ?currency=PLN | EUR | CHF | CZK
Cena promocyjna dla 150 szt.
GET  /api/promo-prices/ABC-123/price/?qty=150&currency=PLN

// Odpowiedź:
{
  "index":       "ABC-123",
  "qty":         150,
  "currency":    "PLN",
  "unit_price":  "8.50",
  "total":       "1275.00",
  "tier":        "100+",
  "no_discount": true
}
✓
Gdy dla podanej ilości lub waluty nie ma ceny promocyjnej, endpoint zwraca 404 — obowiązuje wtedy zwykła cena produktu (z rabatem klienta).
👤

Profil i uprawnienia

Przed złożeniem pierwszego zamówienia sprawdź swój profil. Kluczowe pola ustawia opiekun Twojego konta — bez nich zamówienie zostanie zablokowane.

GET/api/me/JWT
Odpowiedź
{
  "username":       "firma_abc",
  "email":          "biuro@firma.pl",
  "can_order":        true,           // false = POST /api/orders/ zwróci 403
  "discount_percent": 10.00,          // % rabatu na produkty z discount_prices=true
  "currency":         "PLN",          // waluta używana w zamówieniach
  "payment_method":   "banktransfer", // forma płatności w zamówieniach
  "language":         "pl"
}
PoleOpisKto ustawia
can_orderGdy false — API odrzuca POST /api/orders/ z błędem 403.Opiekun konta
discount_percentRabat procentowy naliczany automatycznie na produkty z discount_prices=true. Nie dotyczy cen indywidualnych i promocyjnych. 0 = brak rabatu.Opiekun konta
currencyWaluta używana we wszystkich zamówieniach tego konta. Wpływa na wybór kolumny cenowej (pln / eur / chf / czk).Opiekun konta
payment_methodForma płatności dla zamówień. Domyślnie banktransfer.Opiekun konta
⚠
Pola profilu ustawia opiekun Twojego konta. Klient nie może ich zmieniać samodzielnie — w razie potrzeby zmiany skontaktuj się z opiekunem.
+

Złóż zamówienie

Wystarczy podać listę produktów. Waluta i forma płatności pobierane są automatycznie z profilu zalogowanego użytkownika. Zamówienie trafia od razu do realizacji.

GET/api/me/sprawdź swój profil i uprawnienia
POST/api/orders/JWT
👤
Przed złożeniem zamówienia sprawdź swój profil przez GET /api/me/. Muszą być ustawione:
• can_order = true — uprawnienie do składania zamówień
• currency i payment_method — pobierane z profilu, nie trzeba podawać w zamówieniu
• discount_percent — rabat na produkty z discount_prices=true; ceny finalne liczone automatycznie
💰
Cenę każdej pozycji ustalamy automatycznie przy złożeniu zamówienia — obowiązuje najniższa z: ceny katalogowej po Twoim rabacie, Twojej ceny indywidualnej i ceny promocyjnej. Sprawdzisz ją wcześniej w /api/client-products/ lub /api/my-prices/ (dla tej samej ilości). Zastosowana cena wraca w items[].unit_price.
Żądanie — minimalne (tylko pozycje)
POST /api/orders/
Authorization: Bearer <access_token>
Content-Type:  application/json

{
  // Twój własny numer zamówienia (opcjonalny)
  "client_reference": "MOJ-NR-2024/001",

  "notes": "Proszę o fakturę VAT",  // opcjonalne

  // Lista produktów — minimum jedna pozycja
  "items": [
    { "product_index": "ABC-123", "quantity": 50 },
    { "product_index": "XYZ-007", "quantity": 10 }
  ]
}

// Waluta i forma płatności z profilu użytkownika — nie trzeba podawać.
201 Created
{
  "id":                42,
  "client_reference": "MOJ-NR-2024/001",
  // ... pola zamawiającego i adresów ...

  "items": [
    { "id": 99, "product_index": "ABC-123", "quantity": 50, "unit_price": "8.90", "price_source": "discount", "marking_place_code": "", "marking_option_code": "", "design_files": [] },
    { "id": 100, "product_index": "XYZ-007", "quantity": 10, "unit_price": "4.20", "price_source": "individual", "marking_place_code": "", "marking_option_code": "", "design_files": [] }
  ],
  "attachments":      [],

  "created_at":       "2026-06-25T10:35:00.123Z",

  // Status realizacji (wypełniany automatycznie)
  "status":           "processing",    // new | processing | confirmed | rejected
  "erp_order_number": "A/2026/0000042",  // numer zamówienia w naszym systemie
  "erp_error":        ""                  // puste = sukces
}
400 Bad Request
{
  "items": [
    {
      "product_index": ["Produkt o indeksie 'XYZ' nie istnieje lub jest nieaktywny."]
    }
  ],
  "billing_city": ["To pole jest wymagane."]
}
401 Unauthorized
{ "detail": "Authentication credentials were not provided." }
☷

Pola zamówienia

Pola żądania (wejściowe):

PoleTypOpis
items[]arrayLista pozycji zamówienia. Minimum jedna.wymagane
items[].product_indexstringIndeks produktu. Musi istnieć i być aktywny.wymagane
items[].quantityintegerIlość sztuk ≥ 1.wymagane
items[].marking_place_codestringKod miejsca znakowania, np. M02. Musi istnieć dla produktu.opcjonalne
items[].marking_option_codestringKod techniki znakowania, np. C1, S1.opcjonalne
items[].marking_colorsintegerLiczba kolorów. Wymagana gdy max_colors > 0.warunkowe
items[].marking_infostringOpis znakowania / instrukcje.opcjonalne
client_referencestringTwój własny numer zamówienia — pojawi się na dokumentach.opcjonalne
notesstringUwagi do zamówienia.opcjonalne

Pola pobierane automatycznie z profilu użytkownika:

PoleOpis
currencyWaluta zamówienia: PLN / EUR / CHF / CZK. Ustawiana przez opiekuna konta w profilu.
payment_methodForma płatności: banktransfer / prepayment / cod. Domyślnie banktransfer.
discount_percentRabat z profilu naliczany automatycznie na produkty z discount_prices=true. Nie dotyczy cen indywidualnych i promocyjnych.

Pola odpowiedzi (tylko do odczytu):

PoleOpis
statusnew — przyjęte  |  processing — w realizacji  |  confirmed — potwierdzone  |  rejected — odrzucone
erp_order_numberNumer zamówienia nadany w naszym systemie, np. A/2026/0000042.
erp_errorKomunikat błędu przy przyjęciu zamówienia. Pusty = sukces.
items[].unit_priceCena netto za sztukę zastosowana w zamówieniu (najniższa obowiązująca).
items[].price_sourceŹródło ceny: base / discount / individual / promo.
attachments[]Ogólne załączniki zamówienia.
📌
Dostępne kody produktów: GET /api/stock-info/. Profil i uprawnienia: GET /api/me/.
☍

Zamówienie ze znakowaniem

Każda pozycja zamówienia może zawierać znakowanie. Podajesz kod miejsca i techniki z danych produktu z API. System weryfikuje, czy takie znakowanie istnieje dla produktu, zanim przyjmie zamówienie.

🔍
Kody miejsc i opcji znakowania pobierasz z GET /api/marking-data/?product={id} lub z zagnieżdżonego marking_data[] w odpowiedzi produktu. Szukaj pól code (miejsce) i option_code (technika).

Pola pozycji ze znakowaniem:

PoleTypOpis
marking_place_codestringKod miejsca znakowania, np. M02. Musi istnieć dla produktu.opcjonalne
marking_option_codestringKod techniki znakowania, np. C1, S1, F1. Musi istnieć w danym miejscu.opcjonalne
marking_colorsintegerLiczba kolorów. Wymagana gdy technika ma max_colors > 0.warunkowe
marking_infostringOpis znakowania / instrukcje dla grafika.opcjonalne
design_files[]arrayLista plików projektu dla tej pozycji (tylko odczyt). Pliki przesyłasz osobnym żądaniem.read-only
Zamówienie z dwoma pozycjami — jedna ze znakowaniem
POST /api/orders/
Authorization: Bearer <token>
Content-Type:  application/json

{
  // ... pola zamawiającego i adresy ...

  "items": [
    {
      "product_index":      "20820-14",
      "quantity":           100,
      "marking_place_code": "M02",        // Tył
      "marking_option_code":"C1",         // DTF 60x50mm
      "marking_info":       "Logo firmowe, projekt w załączniku"
    },
    {
      "product_index":      "20820-14",
      "quantity":           50,
      "marking_place_code": "M02",
      "marking_option_code":"S1",         // Sitodruk 300x250mm
      "marking_colors":     2,            // max_colors=3
      "marking_info":       "Logo 2-kolorowe PMS"
    }
  ]
}

Upload pliku projektu dla pozycji:

POST/api/orders/{id}/items/{item_id}/designJWT
cURL — upload pliku projektu
# Krok 1 — złóż zamówienie, zanotuj id zamówienia i id pozycji
# W odpowiedzi items[0].id = 99 (id pozycji)

# Krok 2 — wyślij plik projektu
curl -X POST https://developers.bluecollection.eu/api/orders/42/items/99/design \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/sciezka/do/logo.pdf"

// Odpowiedź 201:
{
  "id":          7,
  "file":        "/media/order_item_designs/42/logo.pdf",
  "uploaded_at": "2026-06-25T11:30:00.000Z"
}
📎

Załączniki

Do każdego zamówienia możesz dołączyć pliki (PDF, PNG, XLSX itp.). Załączniki są przekazywane do realizacji razem z zamówieniem.

POST/api/orders/{id}/attachments/JWT
Dodaj załącznik (multipart/form-data)
POST /api/orders/42/attachments/
Authorization: Bearer <token>
Content-Type:  multipart/form-data

// Pole formularza: file

// cURL:
curl -X POST https://developers.bluecollection.eu/api/orders/42/attachments/ \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@/path/to/wzor.pdf"

// Odpowiedź 201:
{
  "id":          1,
  "file":        "/media/order_attachments/2026/06/wzor.pdf",
  "uploaded_at": "2026-06-25T11:00:00.000Z"
}
⚠
Załączniki dodawaj zaraz po złożeniu zamówienia. Jeśli dodasz plik, gdy zamówienie jest już w realizacji, poinformuj o tym swojego opiekuna.
↻

Status zamówienia

Każde zamówienie jest automatycznie przekazywane do realizacji zaraz po utworzeniu. Pole status pokazuje, na jakim etapie jest zamówienie.

new
Nowe

Zamówienie przyjęte, oczekuje na przekazanie do realizacji.

processing
W realizacji

Zamówienie przekazane do realizacji. Pole erp_order_number zawiera jego numer.

confirmed
Potwierdzone

Zamówienie potwierdzone.

rejected
Odrzucone

Zamówienie odrzucone — szczegóły w erp_error lub u opiekuna konta.

☰

Lista zamówień

Pobierz i przeszukuj złożone zamówienia. Filtr status pozwala śledzić ich realizację.

GET/api/orders/JWT
GET/api/orders/{id}/szczegóły jednego zamówienia
?status=new ?status=processing ?currency=EUR ?payment_method=cod ?search=Kowalski ?search=ABC-123 ?page=2
Zamówienia oczekujące na realizację
GET  /api/orders/?status=new
Authorization: Bearer <token>
⚠

Kody odpowiedzi

200
OK

Żądanie GET zakończone sukcesem.

201
Created

Zasób (zamówienie) utworzony pomyślnie.

400
Bad Request

Błąd walidacji — sprawdź treść odpowiedzi.

401
Unauthorized

Brak lub nieważny token JWT.

403
Forbidden

Brak uprawnień do zasobu.

404
Not Found

Zasób nie istnieje (np. błędny indeks).

405
Method Not Allowed

Metoda niedostępna dla endpointu (np. zapis do endpointu tylko do odczytu).

429
Too Many Requests

Przekroczony limit: 600 żądań/min po zalogowaniu, 60/min bez logowania. Odczekaj i ponów.

⌀

Przykłady kodu

cURL — token + dane produktów
# 1. Pobierz token
TOKEN=$(curl -s -X POST https://developers.bluecollection.eu/api/token/ \
  -H "Content-Type: application/json" \
  -d '{"username":"login","password":"haslo"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access'])")

# 2. Lista produktów (paginowana)
curl https://developers.bluecollection.eu/api/products/ \
  -H "Authorization: Bearer $TOKEN"

# 3. Szczegóły produktu po indeksie
curl https://developers.bluecollection.eu/api/products-index/ABC-123/ \
  -H "Authorization: Bearer $TOKEN"

# 4. Stany magazynowe
curl https://developers.bluecollection.eu/api/stock-info/ \
  -H "Authorization: Bearer $TOKEN"

# 5. Produkt z Twoimi cenami (100 szt.)
curl "https://developers.bluecollection.eu/api/client-products/ABC-123/?qty=100" \
  -H "Authorization: Bearer $TOKEN"
Python (requests)
import requests

BASE = "https://developers.bluecollection.eu"

# 1. Token
token = requests.post(f"{BASE}/api/token/", json={
    "username": "login", "password": "haslo"
}).json()["access"]
headers = {"Authorization": f"Bearer {token}"}

# 2. Lista produktów (pierwsza strona)
products = requests.get(f"{BASE}/api/products/", headers=headers).json()
print(f"Łącznie produktów: {products['count']}")

# 3. Szczegóły produktu po indeksie
product = requests.get(f"{BASE}/api/products-index/ABC-123/", headers=headers).json()
print(f"Stan: {product['quantity']} szt.")

# 4. Znakowanie produktu
marking = requests.get(f"{BASE}/api/marking-data/?product={product['id']}", headers=headers).json()
print(marking)

# 5. Produkt z Twoimi cenami (100 szt.)
priced = requests.get(f"{BASE}/api/client-products/ABC-123/", params={"qty": 100}, headers=headers).json()
print(f"Cena katalogowa: {priced['catalogue_price']}, Twoja cena: {priced['purchase_price']} {priced['currency']}")
JavaScript (fetch)
const BASE = "https://developers.bluecollection.eu";
const post = (url, body, tok) => fetch(BASE + url, {
  method: "POST", headers: { "Content-Type": "application/json",
    ...(tok && { "Authorization": `Bearer ${tok}` }) },
  body: JSON.stringify(body) }).then(r => r.json());

// 1. Token
const { access } = await post("/api/token/", { username: "login", password: "haslo" });

// 2. Lista produktów
const get = (url) => fetch(BASE + url,
  { headers: { "Authorization": `Bearer ${access}` } }).then(r => r.json());

const products = await get("/api/products/");
console.log(`Łącznie produktów: ${products.count}`);

// 3. Szczegóły produktu po indeksie
const product = await get("/api/products-index/ABC-123/");
console.log(`Stan: ${product.quantity} szt.`);

// 4. Znakowanie produktu
const marking = await get(`/api/marking-data/?product=${product.id}`);
console.log(marking);

// 5. Produkt z Twoimi cenami (100 szt.)
const priced = await get("/api/client-products/ABC-123/?qty=100");
console.log(`Cena katalogowa: ${priced.catalogue_price}, Twoja cena: ${priced.purchase_price} ${priced.currency}`);
PHP (cURL)
<?php
$base = "https://developers.bluecollection.eu";
function apiPost($url, $data, $token = null) {
    $ch = curl_init($url);
    $headers = ["Content-Type: application/json"];
    if ($token) $headers[] = "Authorization: Bearer $token";
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true, CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POSTFIELDS => json_encode($data)]);
    return json_decode(curl_exec($ch));
}

// 1. Token
$auth  = apiPost("$base/api/token/", ["username"=>"login","password"=>"haslo"]);
$token = $auth->access;

// 2. Lista produktów
$ch = curl_init("$base/api/products/");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]]);
$products = json_decode(curl_exec($ch));
echo "Łącznie produktów: {$products->count}\n";

// 3. Szczegóły produktu po indeksie
$ch = curl_init("$base/api/products-index/ABC-123/");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]]);
$product = json_decode(curl_exec($ch));
echo "Stan: {$product->quantity} szt.\n";
print_r($product);

// 5. Produkt z Twoimi cenami (100 szt.)
$ch = curl_init("$base/api/client-products/ABC-123/?qty=100");
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer $token"]]);
$priced = json_decode(curl_exec($ch));
echo "Twoja cena: {$priced->purchase_price} {$priced->currency}\n";
🔗
Adres serwera API: developers.bluecollection.eu. Dane logowania uzyskasz od opiekuna konta.