Stock, lot by lot, in base units, with its quality status. Retired lots are archived.
idintegerarchivedbooleanArchived lots are retired but stay readable with their history.
created_atstringnullableexpiration_datestringnullablelocation_codestringnullablelocation_idintegernullablelocation_namestringnullablelot_numberstringnullableNull on the product's unnumbered lot, which holds stock that was never lotted.
lot_originstringnullableHow the lot came into existence.
RECEPTIONINVOICEPRODUCTIONMANUAL_ADJUSTMENTPACKAGINGSHIPPINGINVENTORY_COUNTPRODUCT_FORMSHOPIFYproduct_codestringnullableproduct_idintegernullableproduct_namestringnullableqc_release_expires_atstringnullableWhen a RELEASED status stops counting. Null means it does not expire.
qc_statusstringnullableTwo statuses are sellable: AVAILABLE and RELEASED. A production output under positive release moves from ON_HOLD to RELEASED, never to AVAILABLE.
AVAILABLEON_HOLDQUARANTINERELEASEDREJECTEDqc_status_atstringnullableqc_status_notestringnullablequantity_basenumbernullableOn hand, in the product's base unit.
unit_of_measure_idintegernullableuom_base_conversionnumbernullableSecond conversion factor. See uom_qty.
uom_base_idintegernullableuom_qtynumbernullableFirst conversion factor. One inventory unit is uom_qty * uom_base_conversion base units.
updated_atstringnullable/product-lotsinventory:readStock, lot by lot, in each product's base unit. Two quality statuses are sellable: AVAILABLE and RELEASED.
product_idintegernullablelot_numberstringnullablePartial match.
location_idintegernullablewarehouse_idintegernullableLots in this warehouse, plus lots with no location.
archivedbooleannullableOmit for both.
searchstringnullableFree-text match on the lot number.
sortstringnullableComma-separated field:direction pairs, e.g. id:desc. Sortable: created_at, expiration_date, id, lot_number, product_name, quantity_base, updated_at. id is always added last, so paging is stable.
limitintegerRows to return. Maximum 200.
offsetintegerRows to skip. Maximum 10000: to read further, narrow the filters or page with updated_since.
updated_sincestringnullableOnly rows changed after this instant, as an ISO 8601 timestamp; without an offset it is read as UTC. Tracks the record itself, not its child rows, and deletions are not reported, so reconcile by re-listing from time to time.
data, with pagination.curl "https://public-api.nutrasoft.ca/v1/product-lots?limit=50" \
-H "Authorization: Bearer $NUTRASOFT_API_KEY"{
"data": [
{
"id": 123,
"archived": false,
"created_at": "2026-09-10T14:30:00Z",
"expiration_date": "2026-09-10T14:30:00Z",
"location_code": "SAMPLE-01",
"location_id": 123,
"location_name": "Sample name",
"lot_number": "LOT-2026-0142",
"lot_origin": "RECEPTION",
"product_code": "SAMPLE-01",
"product_id": 123,
"product_name": "Sample name",
"qc_release_expires_at": "2026-09-10T14:30:00Z",
"qc_status": "AVAILABLE",
"qc_status_at": "2026-09-10T14:30:00Z",
"qc_status_note": "string",
"quantity_base": 12.5,
"unit_of_measure_id": 123,
"uom_base_conversion": 12.5,
"uom_base_id": 123,
"uom_qty": 12.5,
"updated_at": "2026-09-10T14:30:00Z"
}
],
"pagination": {
"limit": 50,
"offset": 0,
"total": 1,
"has_more": false
},
"order": "id:asc"
}/product-lots/{lot_id}inventory:readlot_idintegerrequiredThe lot's id.
data.curl "https://public-api.nutrasoft.ca/v1/product-lots/123" \
-H "Authorization: Bearer $NUTRASOFT_API_KEY"{
"data": {
"id": 123,
"archived": false,
"created_at": "2026-09-10T14:30:00Z",
"expiration_date": "2026-09-10T14:30:00Z",
"location_code": "SAMPLE-01",
"location_id": 123,
"location_name": "Sample name",
"lot_number": "LOT-2026-0142",
"lot_origin": "RECEPTION",
"product_code": "SAMPLE-01",
"product_id": 123,
"product_name": "Sample name",
"qc_release_expires_at": "2026-09-10T14:30:00Z",
"qc_status": "AVAILABLE",
"qc_status_at": "2026-09-10T14:30:00Z",
"qc_status_note": "string",
"quantity_base": 12.5,
"unit_of_measure_id": 123,
"uom_base_conversion": 12.5,
"uom_base_id": 123,
"uom_qty": 12.5,
"updated_at": "2026-09-10T14:30:00Z"
}
}/product-lotsinventory:writePuts stock on the books with the PRODUCT_FORM stock movement that explains it, in one transaction. quantity_base is stored as sent, in the product's base unit. A second lot with the same number at the same location is refused with 409.
product_idintegerrequiredThe product this lot is stock of. Must be one of yours.
expiration_datestringnullableISO 8601. Null for stock that does not expire.
location_idintegernullableWhere the stock sits: one of your warehouses or a location in one.
lot_numberstringnullableUnique per product and location. Omit it only for the product's unnumbered lot, of which there is at most one.
quantity_basenumberOn hand, in the product's base unit. Stored as sent.
data.curl -X POST "https://public-api.nutrasoft.ca/v1/product-lots" \
-H "Authorization: Bearer $NUTRASOFT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"product_id": 123
}'{
"data": {
"id": 123,
"archived": false,
"created_at": "2026-09-10T14:30:00Z",
"expiration_date": "2026-09-10T14:30:00Z",
"location_code": "SAMPLE-01",
"location_id": 123,
"location_name": "Sample name",
"lot_number": "LOT-2026-0142",
"lot_origin": "RECEPTION",
"product_code": "SAMPLE-01",
"product_id": 123,
"product_name": "Sample name",
"qc_release_expires_at": "2026-09-10T14:30:00Z",
"qc_status": "AVAILABLE",
"qc_status_at": "2026-09-10T14:30:00Z",
"qc_status_note": "string",
"quantity_base": 12.5,
"unit_of_measure_id": 123,
"uom_base_conversion": 12.5,
"uom_base_id": 123,
"uom_qty": 12.5,
"updated_at": "2026-09-10T14:30:00Z"
}
}/product-lots/{lot_id}inventory:writeOmitted fields are left unchanged. quantity_base corrects the lot and writes no stock movement: use it to reconcile a count. Archiving has its own operations, and the quality status is not writable.
lot_idintegerrequiredThe lot's id.
expiration_datestringnullablelocation_idintegernullablelot_numberstringnullablequantity_basenumbernullableOn hand, in the product's base unit. A correction: it writes no stock movement. Cannot be null.
data.curl -X PATCH "https://public-api.nutrasoft.ca/v1/product-lots/123" \
-H "Authorization: Bearer $NUTRASOFT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"expiration_date": "2026-09-10T14:30:00Z"
}'{
"data": {
"id": 123,
"archived": false,
"created_at": "2026-09-10T14:30:00Z",
"expiration_date": "2026-09-10T14:30:00Z",
"location_code": "SAMPLE-01",
"location_id": 123,
"location_name": "Sample name",
"lot_number": "LOT-2026-0142",
"lot_origin": "RECEPTION",
"product_code": "SAMPLE-01",
"product_id": 123,
"product_name": "Sample name",
"qc_release_expires_at": "2026-09-10T14:30:00Z",
"qc_status": "AVAILABLE",
"qc_status_at": "2026-09-10T14:30:00Z",
"qc_status_note": "string",
"quantity_base": 12.5,
"unit_of_measure_id": 123,
"uom_base_conversion": 12.5,
"uom_base_id": 123,
"uom_qty": 12.5,
"updated_at": "2026-09-10T14:30:00Z"
}
}/product-lots/{lot_id}/archiveinventory:writeArchiving is how a lot is retired: lots are never deleted. Refused with 409 for a lot already archived and for a product's unnumbered lot.
lot_idintegerrequiredThe lot's id.
data.curl -X POST "https://public-api.nutrasoft.ca/v1/product-lots/123/archive" \
-H "Authorization: Bearer $NUTRASOFT_API_KEY"{
"data": {
"id": 123,
"archived": false,
"created_at": "2026-09-10T14:30:00Z",
"expiration_date": "2026-09-10T14:30:00Z",
"location_code": "SAMPLE-01",
"location_id": 123,
"location_name": "Sample name",
"lot_number": "LOT-2026-0142",
"lot_origin": "RECEPTION",
"product_code": "SAMPLE-01",
"product_id": 123,
"product_name": "Sample name",
"qc_release_expires_at": "2026-09-10T14:30:00Z",
"qc_status": "AVAILABLE",
"qc_status_at": "2026-09-10T14:30:00Z",
"qc_status_note": "string",
"quantity_base": 12.5,
"unit_of_measure_id": 123,
"uom_base_conversion": 12.5,
"uom_base_id": 123,
"uom_qty": 12.5,
"updated_at": "2026-09-10T14:30:00Z"
}
}/product-lots/{lot_id}/unarchiveinventory:writeReturns an archived lot to active stock. Refused with 409 for a lot already active and for a product's unnumbered lot.
lot_idintegerrequiredThe lot's id.
data.curl -X POST "https://public-api.nutrasoft.ca/v1/product-lots/123/unarchive" \
-H "Authorization: Bearer $NUTRASOFT_API_KEY"{
"data": {
"id": 123,
"archived": false,
"created_at": "2026-09-10T14:30:00Z",
"expiration_date": "2026-09-10T14:30:00Z",
"location_code": "SAMPLE-01",
"location_id": 123,
"location_name": "Sample name",
"lot_number": "LOT-2026-0142",
"lot_origin": "RECEPTION",
"product_code": "SAMPLE-01",
"product_id": 123,
"product_name": "Sample name",
"qc_release_expires_at": "2026-09-10T14:30:00Z",
"qc_status": "AVAILABLE",
"qc_status_at": "2026-09-10T14:30:00Z",
"qc_status_note": "string",
"quantity_base": 12.5,
"unit_of_measure_id": 123,
"uom_base_conversion": 12.5,
"uom_base_id": 123,
"uom_qty": 12.5,
"updated_at": "2026-09-10T14:30:00Z"
}
}