Fakturnia Developers Quickstart API reference Polski

Warehouse

The warehouse module tracks goods with a movement ledger: a product's stock level is the sum of its receipts and issues. Through the API you manage warehouses, issue warehouse documents (WZ, PZ, PW, RW, MM), record stock adjustments, fetch a stock report for any day and issue WZ (goods issue) documents for sales invoices.

The module requires the MAX plan on the Fakturnia account. Without it every warehouse endpoint returns 403 with the SUBSCRIPTION_REQUIRED code. There is no limit on the number of warehouses.

Scopes: warehouse:browse, warehouse:create, warehouse:update, warehouse:delete, warehouse:stock:read, warehouse:adjust, warehouse:wz:create, warehouse:documents:create.

Warehouses

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

# Create
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" }'

The first warehouse automatically becomes the default one. symbol goes into warehouse document numbering. Update with PUT /warehouse/{id}, delete with DELETE /warehouse/{id}.

Deletion is blocked (409 CONFLICT) in two cases: the warehouse has stock movements, or it is the only warehouse on the account.

Warehouse documents (WZ, PZ, PW, RW, MM)

POST /warehouse/documents issues a warehouse document and books its stock movements at once. POST /warehouse/documents/validate takes the same body and returns a preview without saving: the number, warehouses, catalogue lines with the stock before and after, and missing goods. 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 } ]
  }'
Type Meaning Contractor (buyerId / buyer) Warehouse
WZ goods issue recipient warehouseId (defaults to the default one)
PZ goods receipt supplier warehouseId (defaults to the default one)
PW internal receipt none warehouseId (defaults to the default one)
RW internal issue none warehouseId (defaults to the default one)
MM transfer between warehouses none sourceWarehouseId (defaults to the default one) and targetWarehouseId (required)

Rules:

  • Lines reference catalogue products (productId); the movement is booked on that product. Name, unit and price come from the catalogue unless you send them: PZ/PW use the purchase price (purchasePrice), WZ/RW/MM the net sale price. A service used on a warehouse document is marked as goods in the catalogue.
  • Missing goods block an issue. WZ, RW and MM that would take stock below zero (stock minus reservations of other pending documents) are rejected with 422 STOCK_SHORTAGE, like in the app. allowNegativeStock: true issues the document anyway.
  • Account settings apply like in the editor: the type's symbol and numbering, place of issue, comments, signatures from the warehouse signature setting, the goods issue / receipt date (WZ, PZ) and the release confirmation mode (stockStatus: "pending" reserves the goods until confirmed in the app). useAccountDefaults: false switches the defaults off; any field you send wins.
  • WZ for an invoice: sourceInvoiceId links the documents both ways and the WZ number is printed on the invoice. Without buyerId the recipient comes from the invoice.
  • An unknown or foreign warehouse, an MM without a target or with the same warehouse twice: 422 WAREHOUSE_INVALID. An unknown product: 404 PRODUCT_NOT_FOUND.
  • The lines of an issued warehouse document cannot be changed with PUT/PATCH /documents/{id} (409 WAREHOUSE_LINES_LOCKED): delete the document and issue a new one. Changing the date moves the movements, and DELETE /documents/{id} reverses them.

Stock adjustments (stocktaking)

A manual adjustment creates a movement of type INW. It is also how you record the opening balance when starting the module:

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": "Opening balance"
  }'
Field Meaning
productId catalog product ID (Products)
warehouseId warehouse ID
quantity stock change: positive = receipt, negative = issue
unitCost net unit cost, the valuation base for receipts (optional)
date movement date YYYY-MM-DD, defaults to today
note description shown in the movement history

Stock report

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"
  }
}

Without parameters it returns the current state. asOf gives the state at the end of the given day (e.g. for stocktaking), warehouseId limits the report to a single warehouse.

Automatic WZ for an invoice

After issuing a sales invoice, a single call creates a WZ document and takes the goods off stock:

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" }'

Rules:

  • Only goods lines make it onto the WZ: lines that exist in the product catalog with productType: "goods" set. Services and lines not in the catalog are skipped and their names come back in the skipped field.
  • If no line is goods, you get a 422 with a hint to mark products as goods in the catalog.
  • One WZ per invoice; a second attempt returns 409 CONFLICT.
  • warehouseId is optional, the default warehouse is used when omitted; an unknown warehouse is 422 WAREHOUSE_INVALID. issueDate defaults to the invoice date.
  • Documents are linked both ways (the WZ number is printed on the invoice and sent to KSeF) and the stock movements (issue) are generated automatically.
  • The WZ gets the account settings like a document from the editor (WZ symbol, place, comments, signatures, release confirmation mode).
  • Missing goods reject the WZ (422 STOCK_SHORTAGE) unless you send allowNegativeStock: true.

WZ documents appear on the document list through the type filter: GET /documents?documentType=WZ (see Pagination and filtering).

One warehouse and the movement ledger

GET /warehouse/{id} returns one warehouse (404 for a foreign or deleted one). GET /warehouse/movements is the ledger the stock levels are computed from: every receipt and issue with its document, quantity, unit cost and the person who recorded it. Filters productId, warehouseId, documentId, type (comma-separated list), dateFrom / dateTo; paginated like the lists. The stock report additionally accepts productId when you care about one product. Examples and the entry shape: History & activity.

Best practices

  • Read stock from the report, do not compute it yourself. GET /warehouse/stock sums the movements exactly like the app does, and asOf gives a historical level (say, for a month-end stocktake). A local copy of stock levels will drift sooner or later.
  • Issue with a document, not an adjustment. WZ/RW/MM guard the stock level (422 STOCK_SHORTAGE), while a negative adjustment (quantity < 0) is accepted without a check. An adjustment with quantity: 0 and unitCost is a revaluation (WYCENA movement) that keeps the quantity.
  • Provide unitCost on receipts. It is the basis of stock valuation; receipts without a cost impoverish the value reports.
  • Create WZ for invoices through wz-from-invoice, not manually. The endpoint links the documents both ways, generates the movements and guards against duplicates (409 on a second attempt), so idempotency comes for free.
  • Maintain the product catalog. Only lines with productType: "goods" make it onto a WZ; if the skipped field returns names you did not expect, fix the types in the catalog first instead of working around it on your side.
  • Filter warehouse documents by type. GET /documents?documentType=WZ (or a comma-separated list like WZ,PZ) returns them along with the rest of the document metadata.