Catalogue and inventory over the API
The endpoints to read and write stock, suppliers, warehouses, counts and transfers, and to read the stock signal and the day's work.
On this page
All of these routes are under /inventory. Reads work with a read key; writes need a write key. If the key is limited to some warehouses, it only sees and touches those.
Stock per SKU
| Method and route | What it does | Key |
|---|---|---|
GET /inventory/stock/page | Paged stock list. Parameters: limit, offset, q (search), warehouse. | read |
GET /inventory/stock | All stock at once (unpaged). | read |
GET /inventory/stock/lookup | Looks up stock records. | read |
GET /inventory/stock/{sku} | One record. | read |
GET /inventory/stock/{sku}/history | A SKU's stock history. | read |
PUT /inventory/stock/{sku} | Creates or replaces the record. current_stock is required. | write |
PATCH /inventory/stock/{sku} | Changes some fields of a record that already exists. Never creates one. | write |
DELETE /inventory/stock/{sku} | Deletes the stock record. | write |
PATCH /inventory/stock/{sku}/product-type | Changes the product type (finished good, component…). | write |
GET / PUT / DELETE /inventory/stock/{sku}/suppliers[/{supplier_id}] | The suppliers linked to a SKU. | read / write |
curl "https://app.stockai.es/api/v1/inventory/stock/page?limit=50&offset=0&warehouse=principal&q=SKU-0" \
-H "Authorization: Bearer $STOCKAI_KEY"# Create or replace a SKU's record (current_stock is required)
curl -X PUT https://app.stockai.es/api/v1/inventory/stock/SKU-001 \
-H "Authorization: Bearer $STOCKAI_KEY" -H "Content-Type: application/json" \
-d '{"current_stock":120,"min_stock":20,"lead_time_days":7,"unit_cost":2.5,
"moq":12,"supplier":"Distribuidora Andina","warehouse":"principal"}'
# Change one field of a record that already exists (never creates one)
curl -X PATCH https://app.stockai.es/api/v1/inventory/stock/SKU-001 \
-H "Authorization: Bearer $STOCKAI_KEY" -H "Content-Type: application/json" \
-d '{"current_stock":118}'Fields PUT/PATCH accept: display_name, current_stock, min_stock, lead_time_days, unit_cost, moq, supplier, notes, sale_price, category, family, brand, unit_of_measure, barcode, warehouse. The response is the full record:
{
"sku": "SKU-001", "display_name": "SKU-001", "warehouse": "principal",
"current_stock": 120.0, "min_stock": 0.0, "lead_time_days": 7,
"unit_cost": 2.5, "moq": 12.0, "supplier": "Distribuidora Andina",
"product_type": "finished_good", "service_level": 0.95,
"lead_time_set_by": "user", "unit_cost_set_by": "user", "moq_set_by": "user",
"updated_at": "2026-10-01T08:00:00+00:00"
}The *_set_by fields say who set each value (user, file, supplier_rule…). What you write through the API counts as your own data.
Importing stock from a file
# 1. Preview: what was detected and what would be written. Writes nothing.
curl -X POST https://app.stockai.es/api/v1/inventory/bulk/preview \
-H "Authorization: Bearer $STOCKAI_KEY" -F "file=@stock.csv"
# 2. Import. Optional fields: mapping (JSON text), warehouse, thousands_dot, only_fill_missing
curl -X POST https://app.stockai.es/api/v1/inventory/bulk \
-H "Authorization: Bearer $STOCKAI_KEY" -F "file=@stock.csv" -F "warehouse=principal"/inventory/bulk/preview touches no row: it tells you which columns it detected (detected_mapping), which it did not use and what it would write. If a sync profile owns any of those fields, it warns in synced_overwrites. GET /inventory/template.csv downloads the template with the recognised headers.
The stock signal and the day's work
GET /inventory/status- The stock signal per SKU: signal, coverage, reorder point and recommended quantity. Optional parameters:
session_id(without it, the active session),signal,supplier,abc,by_warehouse,q,skus,without_forecast,service_level,sort,order,limit,offset. GET /inventory/morning-briefing- The day's work: risks, recommendations with their reason, demand changes and KPIs. Parameters:
session_id,service_level. GET /inventory/dashboard-summary- The dashboard's figures.
GET /inventory/optimize- Purchases and transfers suggested by the optimizer, per SKU and warehouse (
session_id,horizon_days). GET /inventory/setup-gaps- SKUs missing setup (cost, lead time…).
GET /inventory/dead-capital,/margin-erosion,/supplier-cost-inflation,/forecast-money- Tied-up capital, eroding margin, cost inflation and projected revenue, cost and margin.
curl "https://app.stockai.es/api/v1/inventory/status?signal=PEDIR_YA&supplier=Andina" \
-H "Authorization: Bearer $STOCKAI_KEY"{
"period": "daily", "coverage_unit": "day",
"items": [{
"sku": "SKU-002", "signal": "PEDIR_YA",
"current_stock": 42.0, "reorder_point": 5919.28, "recommended_qty": 5878.0,
"coverage_days": 0.1,
"lead_time_days": 7, "lead_time_source": "user",
"unit_cost": 5.2, "unit_cost_source": "user",
"moq": 25.0, "moq_source": "user",
"supplier": "Granos del Valle",
"explanation_code": "inventory_explain_reorder",
"explanation_params": { "signal": "PEDIR_YA", "daily_demand": 757.97, "coverage_days": 0.1,
"current_stock": 42.0, "reorder_point": 5919.28,
"lead_time_days": 7, "lead_time_source": "user" },
...
}]
}signal | Meaning |
|---|---|
PEDIR_YA | Order now: stock does not cover the lead time. |
PEDIR_PRONTO | Order soon. |
OK | Covered. |
SOBRESTOCK | More than needed. |
SIN_DATOS | No stock on record: unknown, which is not the same as "fine". |
The lead_time_source, unit_cost_source and moq_source fields say where each assumption came from: user (you typed it), file (it came in your file), supplier_rule (a supplier rule), learned (learned from your receptions; lead time only) or default (StockAI assumed it). Handle all five. The reason behind each recommendation comes structured in explanation_code + explanation_params: decide on that, not on the explanation text.
Suppliers
| Method and route | What it does |
|---|---|
GET /inventory/suppliers, GET /inventory/suppliers/page | List (whole, or paged with limit, offset, q). |
POST /inventory/suppliers | Creates a supplier. Only name is required. |
PATCH /inventory/suppliers/{id} | Changes its details. |
DELETE /inventory/suppliers/{id} / POST .../{id}/reactivate | Deactivates / reactivates it (it is not deleted). |
POST /inventory/suppliers/import/preview, POST /inventory/suppliers/import | Import from a file (template at GET /inventory/suppliers/import/template). |
GET /inventory/suppliers/scorecard, /lead-time-alerts, /contact-health | Performance, suppliers taking longer than usual, and missing contact details. |
POST /inventory/suppliers/{id}/price-breaks, GET /inventory/price-breaks | Volume discounts. |
curl -X POST https://app.stockai.es/api/v1/inventory/suppliers \
-H "Authorization: Bearer $STOCKAI_KEY" -H "Content-Type: application/json" \
-d '{"name":"Distribuidora Andina","email":"ventas@andina.example",
"lead_time_days":7,"payment_terms":"30 dias","payment_terms_days":30,
"erp_code":"PRV-0042"}'Fields: name, email, phone, whatsapp, lead_time_days, lead_time_std, review_period_days, payment_terms, payment_terms_days, notes and erp_code. The erp_code is the supplier's code in your ERP: it is what the order feed uses to match documents.
Warehouses
GET /inventory/warehouseslists warehouses (id,name,is_default…).POSTcreates one andPATCH /inventory/warehouses/{name}changes it. The number of warehouses has a per-plan ceiling.GET/PUT/DELETE /inventory/warehouses/lanes: transfer lanes between warehouses.
Physical counts
# Open a count for one warehouse
curl -X POST https://app.stockai.es/api/v1/inventory/stock-counts \
-H "Authorization: Bearer $STOCKAI_KEY" -H "Content-Type: application/json" \
-d '{"warehouse":"principal","notes":"Monthly count"}'
# Record what was counted, line by line
curl -X PUT https://app.stockai.es/api/v1/inventory/stock-counts/$COUNT_ID/lines \
-H "Authorization: Bearer $STOCKAI_KEY" -H "Content-Type: application/json" \
-d '{"sku":"SKU-001","quantity":117,"mode":"set"}'
# mode "add" (default) accumulates, e.g. one scan = one unit; "set" replaces the counted total.
# client_ref (optional): an id per scan, so a retried request is ignored.
# See the differences, then apply them to the stock
curl https://app.stockai.es/api/v1/inventory/stock-counts/$COUNT_ID/preview -H "Authorization: Bearer $STOCKAI_KEY"
curl -X POST https://app.stockai.es/api/v1/inventory/stock-counts/$COUNT_ID/apply -H "Authorization: Bearer $STOCKAI_KEY"A count is opened (POST), its lines filled (PUT .../lines, DELETE .../lines/{sku}), reviewed (GET .../preview) and applied (POST .../apply) or closed / cancelled (.../close, .../cancel). Applying sets the stock to what was counted.
Transfers between warehouses
curl -X POST https://app.stockai.es/api/v1/inventory/transfers \
-H "Authorization: Bearer $STOCKAI_KEY" -H "Content-Type: application/json" \
-d '{"from_warehouse":"principal","to_warehouse":"norte",
"items":[{"sku":"SKU-001","qty":10}],"notes":"Weekly rebalancing"}'Then: POST /inventory/transfers/{id}/receive when it arrives, .../close to close it and .../cancel to void it. GET /inventory/transfers lists them.
Other inventory resources
- Demand events
/inventory/eventsand its catalogue: seasons and dates that move demand, with their multipliers.- Bills of materials
/inventory/bom/{parent_sku}: an assembled product's components;GET /inventory/production-requirementsexplodes demand into components.- Shrinkage
GET/POST /inventory/shrinkageand its reasons.- Money
/inventory/cash-calendar,/inventory/roi,/inventory/roi/monthly.- Report
GET /inventory/report/pdfdownloads the inventory report as a PDF.