API dla partnerów

.md

Dostęp do katalogu, zamówień i dokumentów konta B2B. Ceny są takie same jak na stronie po zalogowaniu.

Adres: https://b2b.z-ecoenergy.com/api/v1. Zapytanie przez HTTP zwraca 400 https_required bez przekierowania.

Logowanie

POST /api/v1/login
Content-Type: application/json

{"email": "biuro@twojafirma.pl", "password": "…", "accept_price_confidentiality": true}

accept_price_confidentiality: true oznacza zgodę na poufność cen, tę samą co przy logowaniu na stronie.

Token jest ważny 2 godziny i jest przesyłany w nagłówku każdego zapytania:

Authorization: Bearer zk1.…

Wygasły token zwraca 401 unauthorized.

Produkty

Produkt jest identyfikowany linkiem na stronie (url).

GET /api/v1/products
GET /api/v1/products?url=/product/produkt-1&url=/product/produkt-2
GET /api/v1/products?currency=EUR

Bez parametrów zwracany jest cały katalog. url przyjmuje pełny link albo ścieżkę. currency: PLN (domyślnie), EUR, USD.

{
  "currency": "PLN",
  "products": [
    {"url": "https://b2b.z-ecoenergy.com/product/produkt-1", "name": "Przykładowy produkt", "code": "PRODUKT-1",
     "stock": 12, "price_net": 100.00, "price_gross": 123.00},
    {"url": "https://b2b.z-ecoenergy.com/product/produkt-2", "name": "Przykładowy moduł", "code": "PRODUKT-2",
     "stock": 900, "price_net": 300.00, "price_gross": 369.00, "pack": 36,
     "tiers": [{"min_quantity": 180, "price_net": 290.00, "price_gross": 356.70}]}
  ]
}
  • code: kod produktu.
  • price_net, price_gross: cena konta za sztukę. null oznacza cenę na zapytanie. W EUR i USD price_gross jest null.
  • pack: wielkość opakowania. Pole występuje tylko przy produktach sprzedawanych w opakowaniach, zamawiana ilość jest jego wielokrotnością.
  • tiers: ceny od danej ilości. Pole występuje tylko przy produktach z progami ilościowymi.

Odpowiedź zawiera nagłówek ETag. Zapytanie z tą wartością w If-None-Match zwraca pustą odpowiedź 304, jeśli dane się nie zmieniły.

Zamówienie

POST /api/v1/orders
Authorization: Bearer zk1.…
Content-Type: application/json

{
  "items": [
    {"url": "https://b2b.z-ecoenergy.com/product/produkt-1", "quantity": 2},
    {"code": "PRODUKT-2", "quantity": 36}
  ],
  "currency": "PLN",
  "payment": "transfer",
  "delivery": {
    "company": "Firma Klienta", "first_name": "Jan", "last_name": "Kowalski",
    "street": "Polna 1", "postcode": "95-030", "city": "Rzgów", "country": "PL",
    "phone": "600100200"
  },
  "reference": "10234",
  "notes": "Proszę o kontakt przed dostawą",
  "accept_terms": true
}
PoleOpis
itemsurl produktu albo jego code (kod produktu, ten sam co w plikach z ofertą) oraz quantity (liczba całkowita, przy produktach z pack wielokrotność pack)
currencyPLN, EUR lub USD. Firma z siedzibą w Polsce zawsze dostaje proformę w PLN z VAT, niezależnie od tego pola. Firma zagraniczna dostaje proformę w podanej walucie, bez VAT; PLN zamieniamy wtedy na EUR.
paymenttransfer (przelew), cash_on_delivery (za pobraniem, tylko z dostawą) lub cash (gotówka, tylko odbiór osobisty)
pickuptrue: odbiór osobisty w Rzgowie, bez delivery
deliveryAdres dostawy. Wymagane first_name, postcode, city. country: kod kraju ISO, np. DE.
referenceNumer zamówienia po stronie klienta: litery, cyfry, . _ / -, do 40 znaków
notesUwagi, do 300 znaków
accept_termstrue: akceptacja regulaminu

Zamówienie jest zapisywane w ERP jako proforma. Stany są sprawdzane przy każdym zamówieniu. Brak na stanie lub ilość niebędąca wielokrotnością pack zwraca błąd.

Odstęp między zamówieniami z jednego konta wynosi co najmniej 2 minuty. Wcześniejsze zamówienie zwraca 429 order_too_soon.

Odpowiedź nie zawiera numeru proformy. Proformę zwraca GET /api/v1/proformas?reference=10234, również po zerwanym połączeniu, gdy odpowiedź na zamówienie nie dotarła.

Proformy

GET /api/v1/proformas
GET /api/v1/proformas?reference=10234

pdf_url wymaga tego samego nagłówka Authorization. null oznacza, że PDF proformy nie jest dostępny przez API. Nowa proforma ma status "Nie weryfikowana" i pdf_url równe null, dopóki biuro nie doliczy transportu i jej nie zatwierdzi.

Faktury i wysyłki

GET /api/v1/invoices
GET /api/v1/shipments

Pola faktury: number, date, currency, net, gross, pdf_url. Wysyłka:

{"shipments": [{
  "number": "WZ/RZ /26/000001", "date": "2026-09-28", "status": "Wysłane",
  "carrier": "DPD", "tracking_number": "0000000000000",
  "pdf_url": "https://b2b.z-ecoenergy.com/api/v1/shipments/WZ-RZ-26-000001/pdf"
}]}

carrier i tracking_number są null do wydania paczki z magazynu.

Numery seryjne

GET /api/v1/serial-numbers

url zwraca numery seryjne z dokumentu:

{"number": "WZ/1  /26/000001", "items": [{"name": "Przykładowy produkt", "serial": "SN0000001"}]}

Błędy

Błąd ma postać {"error": "kod"}, niektóre z dodatkowymi polami.

HTTPerrorZnaczenie
400https_requiredZapytanie przez HTTP
400credentials_required, confidentiality_required, invalid_json, currency_invalidNiepoprawne zapytanie
400items_required, duplicate_item, quantity_invalid (z urls), quantity_not_pack_multiple (z items), terms_required, payment_invalid, payment_not_allowed, delivery_required, postcode_invalid, phone_invalid, country_invalid, reference_invalidNiepoprawne zamówienie
401wrong_credentials, unauthorizedBłędne dane logowania lub wygasły token
404not_found, pdf_not_availableBrak zasobu na tym koncie
405method_not_allowedNieobsługiwana metoda HTTP
409pdf_not_readyProforma czeka na weryfikację przez biuro, PDF będzie dostępny po niej
409unknown_items (z urls: wysłane url lub code), unavailable_items, stock_exceeded (z items: url, requested, available)Pozycje nieznane, niedostępne lub ponad stan
413, 415body_too_large, json_requiredTreść ponad 1 MB lub typ inny niż application/json
422order_rejectedZamówienie odrzucone przez ERP
429order_too_soon, rate_limitedLimit zapytań, czas w nagłówku Retry-After
502, 503order_failed, unavailable, pdf_unavailableChwilowa niedostępność ERP

Integracje

Pliki z ofertą konta do importu w sklepie internetowym. Link zawiera klucz konta i przestaje działać po zmianie hasła. Linki są też w polu feed odpowiedzi na logowanie. Zamiast klucza można użyć HTTP Basic (e-mail i hasło konta): GET /api/v1/feed.xml, feed.csv, feed.ceneo.xml, feed.skyshop.xml, feed.full.xml.

r = requests.get(f"{API}/feed.xml", auth=("biuro@twojafirma.pl", "…"))

XML / CSV

currency: PLN (domyślnie), EUR, USD. W EUR i USD price_gross jest puste. separator=semicolon: CSV ze średnikiem jako separatorem. Puste price_net oznacza cenę na zapytanie.

GET /api/v1/feed/{klucz}.xml
GET /api/v1/feed/{klucz}.csv
GET /api/v1/feed/{klucz}.xml?currency=EUR
GET /api/v1/feed/{klucz}.csv?separator=semicolon

Ceneo

Format Ceneo, ceny netto konta w PLN. avail: 1 na stanie, 90 na zamówienie. Produkty bez ceny są pominięte.

GET /api/v1/feed/{klucz}.ceneo.xml

Skyshop

Format Skyshop w PLN. prod_price: cena brutto, prod_tax_id: cena netto, prod_weight: waga w gramach. Produkty bez ceny są pominięte.

GET /api/v1/feed/{klucz}.skyshop.xml

Pełny XML

Wszystko, co system ma o produkcie, w jednym pliku z polskimi nazwami pól: kategoria, kod, nazwa, zdjęcia, dokumenty (karty katalogowe, certyfikaty), opis HTML, cena netto konta, stan, producent, waga w kg oraz parametry odczytane z katalogu: liczba faz, moc (moduły w Wp, falowniki w W), wymiary i kolor ramy modułów, pojemność magazynów. Pola, których system nie zna dla danego produktu, są pominięte. Produkty bez ceny są pominięte.

kategoria: tylko ta kategoria, podana identyfikatorem albo nazwą z pola <kategoria>, np. gotowe-zestawy lub Gotowe zestawy. Identyfikatory: gotowe-zestawy, panele-sloneczne, magazyny-energii, ladowarki, optymalizatory-mocy, akcesoria-do-inwerterow, systemy-montazowe, pompy-ciepla, falowniki. Bez parametru plik zawiera te dziewięć kategorii, każdy produkt raz, w pierwszej z nich w tej kolejności.

wszystkie=1: dołącza też pozostałe kategorie sklepu, po tych dziewięciu: akcesoria-do-magazynow-energii, akcesoria-fotowoltaiczne, podgrzewacze-cwu, klimatyzatory, rekuperatory. Każda z nich działa też osobno w kategoria. currency: PLN (domyślnie), EUR, USD.

Pierwsze zapytanie po restarcie serwera może zwrócić 503 unavailable z nagłówkiem Retry-After, dopóki plik nie zostanie zbudowany.

GET /api/v1/feed/{klucz}.full.xml
GET /api/v1/feed/{klucz}.full.xml?kategoria=falowniki
GET /api/v1/feed/{klucz}.full.xml?wszystkie=1