Fakturnia Developers Szybki start Dokumentacja API English

Magazyn

Moduł magazynowy prowadzi stany towarów metodą księgi ruchów: stan produktu to suma przyjęć i wydań. Przez API zarządzasz magazynami, wystawiasz dokumenty magazynowe (WZ, PZ, PW, RW, MM), rejestrujesz korekty stanów, pobierasz raport stanów na dowolny dzień i wystawiasz dokumenty WZ do faktur sprzedaży.

Moduł wymaga planu MAX na koncie Fakturnia. Bez niego każdy endpoint magazynowy zwraca 403 z kodem SUBSCRIPTION_REQUIRED. W planie MAX nie ma limitu liczby magazynów.

Zakresy uprawnień: warehouse:browse, warehouse:create, warehouse:update, warehouse:delete, warehouse:stock:read, warehouse:adjust, warehouse:wz:create, warehouse:documents:create.

Magazyny

# Lista
curl -s https://prod.api.fakturnia.pl/external/v1/warehouse \
  -H "Authorization: Bearer $TOKEN"

# Utworzenie
curl -s -X POST https://prod.api.fakturnia.pl/external/v1/warehouse \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Magazyn główny", "symbol": "MAG1", "address": "ul. Prosta 1, Warszawa" }'

Pierwszy utworzony magazyn automatycznie staje się domyślny. symbol trafia do numeracji dokumentów magazynowych. Aktualizacja to PUT /warehouse/{id}, usunięcie to DELETE /warehouse/{id}.

Usunięcie jest zablokowane (409 CONFLICT) w dwóch sytuacjach: magazyn ma ruchy magazynowe albo jest jedynym magazynem na koncie.

Dokumenty magazynowe (WZ, PZ, PW, RW, MM)

POST /warehouse/documents wystawia dokument magazynowy i od razu księguje jego ruchy. POST /warehouse/documents/validate przyjmuje to samo ciało i zwraca podgląd bez zapisu: numer, magazyny, pozycje z kartoteki ze stanem przed i po oraz braki towaru. Scope: warehouse:documents:create.

curl -s -X POST https://prod.api.fakturnia.pl/external/v1/warehouse/documents \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "documentType": "PZ",
    "issueDate": "2026-09-27",
    "buyerId": "665d0a1234567890abcdef56",
    "products": [ { "productId": "665f0c1234567890abcdef12", "quantity": 20, "netPrice": 45.5 } ]
  }'
Typ Znaczenie Kontrahent (buyerId / buyer) Magazyn
WZ wydanie zewnętrzne odbiorca warehouseId (domyślnie magazyn domyślny)
PZ przyjęcie zewnętrzne dostawca warehouseId (domyślnie magazyn domyślny)
PW przychód wewnętrzny brak warehouseId (domyślnie magazyn domyślny)
RW rozchód wewnętrzny brak warehouseId (domyślnie magazyn domyślny)
MM przesunięcie między magazynami brak sourceWarehouseId (domyślnie domyślny) i targetWarehouseId (wymagany)

Zasady:

  • Pozycje wskazują produkty z kartoteki (productId); na ten produkt księgowany jest ruch. Nazwa, jednostka i cena pochodzą z kartoteki, jeśli ich nie podasz: przy PZ/PW cena zakupu (purchasePrice), przy WZ/RW/MM cena sprzedaży netto. Usługa użyta na dokumencie magazynowym zostaje oznaczona w kartotece jako towar.
  • Braki towaru blokują wydanie. WZ, RW i MM, które zeszłyby ze stanem poniżej zera (stan minus rezerwacje innych dokumentów oczekujących), są odrzucane z 422 STOCK_SHORTAGE, jak w aplikacji. allowNegativeStock: true wystawia dokument mimo braku.
  • Ustawienia konta działają jak w edytorze: symbol i numeracja typu, miejsce wystawienia, uwagi, podpisy z ustawienia podpisów dokumentów magazynowych, data wydania / otrzymania towaru (WZ, PZ) i tryb potwierdzania wydań (stockStatus: "pending" rezerwuje towar do potwierdzenia w aplikacji). useAccountDefaults: false wyłącza wartości domyślne; każde pole podane jawnie wygrywa.
  • WZ do faktury: sourceInvoiceId wiąże dokumenty w obie strony, a numer WZ trafia na fakturę. Bez buyerId odbiorca jest brany z faktury.
  • Nieznany albo cudzy magazyn, MM bez magazynu docelowego albo z tym samym magazynem: 422 WAREHOUSE_INVALID. Nieznany produkt: 404 PRODUCT_NOT_FOUND.
  • Pozycji wystawionego dokumentu magazynowego nie zmienisz przez PUT/PATCH /documents/{id} (409 WAREHOUSE_LINES_LOCKED): usuń dokument i wystaw nowy. Zmiana daty przesuwa ruchy, a DELETE /documents/{id} je cofa.

Korekty stanów (inwentaryzacja)

Ręczna korekta tworzy ruch typu INW. To także sposób na bilans otwarcia przy starcie modułu:

curl -s -X POST https://prod.api.fakturnia.pl/external/v1/warehouse/adjustments \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "productId": "665f0c1234567890abcdef12",
    "warehouseId": "665e0b1234567890abcdef34",
    "quantity": 10,
    "unitCost": 80,
    "note": "Bilans otwarcia"
  }'
Pole Znaczenie
productId ID produktu z kartoteki (Produkty)
warehouseId ID magazynu
quantity zmiana stanu: dodatnia = przyjęcie, ujemna = wydanie
unitCost koszt jednostkowy netto, podstawa wyceny dla przyjęć (opcjonalny)
date data ruchu YYYY-MM-DD, domyślnie dzisiaj
note opis widoczny w historii ruchów

Raport stanów

curl -s "https://prod.api.fakturnia.pl/external/v1/warehouse/stock?asOf=2026-06-30" \
  -H "Authorization: Bearer $TOKEN"
{
  "success": true,
  "data": {
    "levels": [
      { "productId": "665f0c...", "warehouseId": "665e0b...", "quantity": 9 }
    ],
    "asOf": "2026-06-30"
  }
}

Bez parametrów zwraca stan bieżący. asOf daje stan na koniec wskazanego dnia (np. do remanentu), warehouseId ogranicza raport do jednego magazynu.

Automatyczne WZ do faktury

Po wystawieniu faktury sprzedaży możesz jednym wywołaniem utworzyć dokument WZ i zdjąć towar ze stanu:

curl -s -X POST https://prod.api.fakturnia.pl/external/v1/warehouse/wz-from-invoice/{invoiceId} \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "warehouseId": "665e0b1234567890abcdef34" }'

Zasady:

  • Na WZ trafiają wyłącznie pozycje towarowe: takie, które istnieją w kartotece produktów i mają tam ustawione productType: "goods". Usługi i pozycje spoza kartoteki są pomijane, a ich nazwy wracają w polu skipped.
  • Jeśli żadna pozycja nie jest towarem, dostaniesz 422 z podpowiedzią, żeby oznaczyć produkty jako towar w kartotece.
  • Do jednej faktury może istnieć jeden WZ; ponowna próba zwraca 409 CONFLICT.
  • warehouseId jest opcjonalne, domyślnie używany jest magazyn domyślny; nieznany magazyn to 422 WAREHOUSE_INVALID. issueDate domyślnie jest datą faktury.
  • Dokumenty są powiązane w obie strony (numer WZ trafia na fakturę i do KSeF), a ruchy magazynowe (wydanie) powstają automatycznie.
  • WZ dostaje ustawienia konta jak dokument z edytora (symbol WZ, miejsce, uwagi, podpisy, tryb potwierdzania wydań).
  • Brak towaru odrzuca WZ (422 STOCK_SHORTAGE), chyba że wyślesz allowNegativeStock: true.

Dokumenty WZ znajdziesz na liście dokumentów przez filtr typu: GET /documents?documentType=WZ (zobacz Paginacja i filtrowanie).

Pojedynczy magazyn i księga ruchów

GET /warehouse/{id} zwraca jeden magazyn (404 dla cudzego lub usuniętego). GET /warehouse/movements to księga ruchów, z której liczą się stany: każde przyjęcie i wydanie z dokumentem, ilością, kosztem jednostkowym i osobą, która je zapisała. Filtry productId, warehouseId, documentId, type (lista po przecinku), dateFrom / dateTo; stronicowanie jak w listach. Raport stanów przyjmuje dodatkowo productId, gdy interesuje Cię jeden produkt. Przykłady i kształt wpisu: Historia i aktywność.

Dobre praktyki

  • Stan pobieraj raportem, nie licz go po swojej stronie. GET /warehouse/stock sumuje ruchy dokładnie tak samo jak aplikacja, a asOf daje stan historyczny (np. do remanentu na koniec miesiąca). Własna kopia stanów prędzej czy później się rozjedzie.
  • Wydawaj dokumentem, nie korektą. WZ/RW/MM pilnują stanu (422 STOCK_SHORTAGE), a ujemna korekta (quantity < 0) jest przyjmowana bez weryfikacji. Korekta z quantity: 0 i unitCost to przecena (ruch WYCENA) bez zmiany ilości.
  • Przy przyjęciach podawaj unitCost. To podstawa wyceny stanów; przyjęcia bez kosztu zubażają raporty wartościowe.
  • WZ do faktur twórz przez wz-from-invoice, nie ręcznie. Endpoint sam wiąże dokumenty w obie strony, tworzy ruchy i pilnuje duplikatu (409 przy drugiej próbie), a idempotencję masz za darmo.
  • Utrzymuj kartotekę produktów. Na WZ trafiają tylko pozycje z productType: "goods"; jeśli w polu skipped wracają nazwy, których się nie spodziewasz, najpierw uzupełnij typy w kartotece zamiast obchodzić to po swojej stronie.
  • Dokumenty magazynowe filtruj po typie. GET /documents?documentType=WZ (albo lista po przecinku, np. WZ,PZ) zwraca je razem z resztą metadanych dokumentów.