NutraSoft food manufacturing ERP software
Esc
  • GuideGetting startedThree steps to your first call and your first order, then the two shapes every response takes.
  • GuideAuthentication and keysBearer keys, test and live environments, rotation without an outage, and what each scope grants.
  • GuideTest modeA second NutraSoft account of your own, seeded with realistic data, that you can safely break.
  • PageErrorsEvery error code the API returns, what it means, what to do about it and whether to retry.
  • PageConventionsThe rules every operation follows: money, time, paging, sorting, nulls, PATCH and identifiers.
Menu

Product lots

Stock, lot by lot, in base units, with its quality status. Retired lots are archived.

inventory:readinventory:writehttps://public-api.nutrasoft.ca/v1

The Product lot object

  • idinteger
  • archivedboolean

    Archived lots are retired but stay readable with their history.

  • created_atstringnullable
    • UTC timestamp
  • expiration_datestringnullable
    • UTC timestamp
  • location_codestringnullable
  • location_idintegernullable
  • location_namestringnullable
  • lot_numberstringnullable

    Null on the product's unnumbered lot, which holds stock that was never lotted.

  • lot_originstringnullable

    How the lot came into existence.

    • one ofRECEPTIONINVOICEPRODUCTIONMANUAL_ADJUSTMENTPACKAGINGSHIPPINGINVENTORY_COUNTPRODUCT_FORMSHOPIFY
  • product_codestringnullable
Show 12 more attributes
  • product_idintegernullable
  • product_namestringnullable
  • qc_release_expires_atstringnullable

    When a RELEASED status stops counting. Null means it does not expire.

    • UTC timestamp
  • qc_statusstringnullable

    Two statuses are sellable: AVAILABLE and RELEASED. A production output under positive release moves from ON_HOLD to RELEASED, never to AVAILABLE.

    • one ofAVAILABLEON_HOLDQUARANTINERELEASEDREJECTED
  • qc_status_atstringnullable
    • UTC timestamp
  • qc_status_notestringnullable
  • quantity_basenumbernullable

    On hand, in the product's base unit.

  • unit_of_measure_idintegernullable
  • uom_base_conversionnumbernullable

    Second conversion factor. See uom_qty.

  • uom_base_idintegernullable
  • uom_qtynumbernullable

    First conversion factor. One inventory unit is uom_qty * uom_base_conversion base units.

  • updated_atstringnullable
    • UTC timestamp

Operations

List product lots

get/product-lotsinventory:read

Stock, lot by lot, in each product's base unit. Two quality statuses are sellable: AVAILABLE and RELEASED.

Query parameters

  • product_idintegernullable
    • > 0
  • lot_numberstringnullable

    Partial match.

  • location_idintegernullable
    • > 0
  • warehouse_idintegernullable

    Lots in this warehouse, plus lots with no location.

    • > 0
  • archivedbooleannullable

    Omit for both.

  • searchstringnullable

    Free-text match on the lot number.

  • sortstringnullable

    Comma-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.

  • limitinteger

    Rows to return. Maximum 200.

    • >= 1
    • <= 200
    • default 50
  • offsetinteger

    Rows to skip. Maximum 10000: to read further, narrow the filters or page with updated_since.

    • >= 0
    • <= 10000
    • default 0
  • updated_sincestringnullable

    Only 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.

    • UTC timestamp
Returns
200 A page of ProductLot objects in data, with pagination.
Errors
400 401 403 429 500 503
GET /product-lots
curl "https://public-api.nutrasoft.ca/v1/product-lots?limit=50" \
  -H "Authorization: Bearer $NUTRASOFT_API_KEY"
Response200
{
  "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"
}

Retrieve a product lot

get/product-lots/{lot_id}inventory:read

Path parameters

  • lot_idintegerrequired

    The lot's id.

    • > 0
Returns
200 One ProductLot object in data.
Errors
400 401 403 404 429 500 503
GET /product-lots/{lot_id}
curl "https://public-api.nutrasoft.ca/v1/product-lots/123" \
  -H "Authorization: Bearer $NUTRASOFT_API_KEY"
Response200
{
  "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"
  }
}

Create a product lot

post/product-lotsinventory:write

Puts 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.

Request body

  • product_idintegerrequired

    The product this lot is stock of. Must be one of yours.

    • > 0
  • expiration_datestringnullable

    ISO 8601. Null for stock that does not expire.

    • UTC timestamp
  • location_idintegernullable

    Where the stock sits: one of your warehouses or a location in one.

    • > 0
  • lot_numberstringnullable

    Unique per product and location. Omit it only for the product's unnumbered lot, of which there is at most one.

    • max 100 chars
  • quantity_basenumber

    On hand, in the product's base unit. Stored as sent.

    • >= 0
    • default 0
Returns
201 One ProductLot object in data.
Errors
400 401 403 409 429 500 503
POST /product-lots
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
}'
Response201
{
  "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"
  }
}

Update a product lot

patch/product-lots/{lot_id}inventory:write

Omitted 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.

Path parameters

  • lot_idintegerrequired

    The lot's id.

    • > 0

Request body

  • expiration_datestringnullable
    • UTC timestamp
  • location_idintegernullable
    • > 0
  • lot_numberstringnullable
    • max 100 chars
  • quantity_basenumbernullable

    On hand, in the product's base unit. A correction: it writes no stock movement. Cannot be null.

    • >= 0
Returns
200 One ProductLot object in data.
Errors
400 401 403 404 409 429 500 503
PATCH /product-lots/{lot_id}
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"
}'
Response200
{
  "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"
  }
}

Archive a product lot

post/product-lots/{lot_id}/archiveinventory:write

Archiving 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.

Path parameters

  • lot_idintegerrequired

    The lot's id.

    • > 0
Returns
200 One ProductLot object in data.
Errors
400 401 403 404 409 429 500 503
POST /product-lots/{lot_id}/archive
curl -X POST "https://public-api.nutrasoft.ca/v1/product-lots/123/archive" \
  -H "Authorization: Bearer $NUTRASOFT_API_KEY"
Response200
{
  "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"
  }
}

Unarchive a product lot

post/product-lots/{lot_id}/unarchiveinventory:write

Returns an archived lot to active stock. Refused with 409 for a lot already active and for a product's unnumbered lot.

Path parameters

  • lot_idintegerrequired

    The lot's id.

    • > 0
Returns
200 One ProductLot object in data.
Errors
400 401 403 404 409 429 500 503
POST /product-lots/{lot_id}/unarchive
curl -X POST "https://public-api.nutrasoft.ca/v1/product-lots/123/unarchive" \
  -H "Authorization: Bearer $NUTRASOFT_API_KEY"
Response200
{
  "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"
  }
}