Inventory Reports
A single endpoint generates five report types via the reportType parameter. The response shape changes completely between types — don't assume a shared schema across reports.
Endpoint
Generates a report of the requested type. Requires inventory:read.
reportTypestringrequiredinventory, transfers, adjustments, counts, or valuation.
startDatestringISO 8601 start date. Applies to transfers, adjustments, and counts.
endDatestringISO 8601 end date.
locationIdstringFilters by location. Applies to inventory, adjustments, counts, and valuation.
formatstringjson or csv. See the warning below — it has no effect.
The exact shape of data/summary depends on reportType — see the detail for each below. This example uses reportType=adjustments:
{
"data": [
{ "id": "adj_01H...", "sku": "CAM-ROJO-M", "adjustmentQuantity": -3, "reason": "damage" }
],
"summary": { "total": 1, "totalQuantityAdjusted": -3, "byReason": { "damage": 1 } }
}
{ "code": "bad-request/missing-type" }
{ "code": "bad-request/invalid-report" }
format is not implemented
The format parameter is accepted (json or csv) but does not change the response: JSON is always returned, regardless of the value sent. Do not build a CSV export flow assuming this parameter produces it.
The entire response follows the { data, summary } shape, where data and summary change structure depending on reportType:
reportType=inventory
Snapshot of current stock, up to 10,000 records, filtered by locationId if sent. Not a paginated report.
{
"data": [
{ "sku": "CAM-ROJO-M", "locationId": "loc_cedis_cdmx", "stock": 137 }
],
"summary": { "totalItems": 1, "locationId": "loc_cedis_cdmx" }
}
reportType=transfers
Transfers filtered by date (startDate/endDate).
{
"data": [
{ "id": "trf_01H...", "originId": "loc_a", "destinationId": "loc_b", "status": "received" }
],
"summary": { "total": 1, "byStatus": { "pending": 0, "approved": 0, "received": 1, "cancelled": 0 } }
}
reportType=adjustments
Adjustments filtered by date and locationId.
{
"data": [
{ "id": "adj_01H...", "sku": "CAM-ROJO-M", "adjustmentQuantity": -3, "reason": "damage" }
],
"summary": { "total": 1, "totalQuantityAdjusted": -3, "byReason": { "damage": 1 } }
}
reportType=counts
Counts filtered by date and locationId.
{
"data": [
{ "id": "cnt_01H...", "name": "Conteo cíclico julio", "status": "completed" }
],
"summary": { "total": 1, "byStatus": { "draft": 0, "in_progress": 0, "completed": 1, "cancelled": 0 } }
}
reportType=valuation
This report is broken in production today
data is built by reading item.unitCost directly from the Inventory document — but the canonical Inventory schema (Lib/Services/Inventory/src/model/schema.ts) has no unitCost field. That value is always undefined, so totalValue and averageUnitCost from this report are effectively 0 for every record. It's dead functionality on the base Inventory collection — not a minor rounding bug.
The correct, active valuation in production lives in the FIFO lots subsystem: use GET /inventory/lots/valuation or GET /inventory/lots/sku/{sku}/valuation instead.
{
"data": [
{ "sku": "CAM-ROJO-M", "productName": "Camisa Roja Talla M", "stock": 137, "unitCost": 0, "totalValue": 0, "locationId": "loc_cedis_cdmx" }
],
"summary": { "totalItems": 1, "totalUnits": 137, "totalValue": 0, "averageUnitCost": 0 }
}
Errors
| Code | HTTP | Cause |
|---|---|---|
bad-request/missing-type | 400 | reportType was not sent. |
bad-request/invalid-report | 400 | reportType is not one of the five valid values. |
See the Error Catalog for the errors common to the whole domain.
Examples
curl -G https://api.fenicia.io/inventory/reports \
-H "Authorization: Bearer fkapi_your_api_key" \
--data-urlencode "reportType=adjustments" \
--data-urlencode "startDate=2026-07-01T00:00:00Z" \
--data-urlencode "endDate=2026-07-21T23:59:59Z"Next steps
- Lots and FIFO Valuation — today's correct valuation source.
- Inventory adjustments
- Transfers between locations
- Cyclic and physical counts
- Error Catalog