# Lots

Find named lots, review exact quantities, and understand the age of remaining stock.

Canonical HTML: https://developer.shelfcycle.com/guides/lots

Find named lots, review exact stored quantities, and understand how long the remaining warehouse stock has been present.

## Endpoints

| Endpoint | Scope | Use it for |
| --- | --- | --- |
| `GET /lots` | `lots:read` | Find named lots with their product, warehouse, state, exact quantities, and recorded stock age. |
| `GET /lots/{id}` | `lots:read` | Read one lot and the remaining inventory additions behind its recorded age. |

Lots access works with the acting user's current Product and Lot viewing access. Filtering by supplier and receiving supplier identity also requires `suppliers:read` and current Supplier viewing access. `GET /me` reports availability through `effectiveCapabilities.lots.view` and `effectiveCapabilities.lots.currentStateRefresh`.

## Find lots

Start with the filters that identify the stock question. For example, find on-hand lots for one product and warehouse that were recorded before a selected date:

```bash
curl "$SHELFCYCLE_API_BASE_URL/lots?productId=product-id&warehouseId=warehouse-id&quantityField=qtyOnHand&minimumQuantity=0.01&oldestOnHandAddedBefore=2024-01-01&limit=25" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "X-ShelfCycle-Client: Lot age review"
```

Useful first-page filters include:

| Filter | Use it for |
| --- | --- |
| `search` or `lotNumber` | Find a familiar lot or match an exact lot number. |
| `productId`, `packagingId`, or `warehouseId` | Narrow to the exact product, package, or warehouse selected earlier in the workflow. |
| `supplierId` | Narrow to lots connected to one available supplier. |
| `lotStateCode` | Select `AVAILABLE` or `QUARANTINED` lots. |
| `quantityField` with `minimumQuantity` or `maximumQuantity` | Filter one stored quantity such as on-hand, allocated, available, or on-order. |
| `oldestOnHandAddedBefore` | Find lots whose remaining physical stock includes inventory recorded before an organization calendar date. |

By default, the finder returns lots with physical stock in non-direct-ship warehouses. Allocated and quarantined lots stay visible and carry their state. Add `includeOnOrder=true`, `includeDepleted=true`, or `includePlaceholders=true` when those records belong in the workflow.

## Read quantity basis and quantities together

Each result carries `quantityBasis` beside its stored quantities:

```json
{
  "quantityBasis": {
    "type": "package_count",
    "unitOfMeasure": "DRUM"
  },
  "quantities": {
    "qtyOnOrder": "8",
    "qtyOnHand": "12",
    "qtyAllocated": "3",
    "qtyAvailable": "9"
  }
}
```

Fixed-package products use package count. Variable products use their base unit of measure. Keep the basis with every value when sorting, comparing, or displaying results, and add quantities only when their product, package, and quantity basis match.

The lot row also includes its stable ID, lot number, product code, catalog packaging, warehouse, supplier when available, lot state, quarantine state, manufacture and expiration dates when recorded, and age evidence.

## Understand remaining-stock age

`ageEvidence.recordedAddedAt` is the earliest recorded inventory addition still represented in the lot's current physical stock. `recordedAddedOn` presents that timestamp as an organization calendar date.

This is warehouse stock age. It is separate from manufacture and expiration dates, which remain available as their own fields when recorded. When a reliable remaining-stock date is not available, the date stays `null` and `ageUnavailableReason` explains why.

`cutoverEvidence` identifies dates that coincide with the organization's accounting cutover, so a workflow can present that date as the earliest recorded evidence rather than an earlier physical arrival date.

The response metadata includes:

- `populationCount` for all lots matching the selected filters;
- `recordedDateMatchLotCount` for matching lots with a recorded age date;
- `unresolvedAgeLotCount` for matching lots whose age remains unknown; and
- `observedAt` for the time of the current-state read.

Use those totals when presenting coverage for a lot-age review instead of counting only the returned page.

## Read one lot

After selecting a lot's exact UUID, read its detail:

```bash
curl "$SHELFCYCLE_API_BASE_URL/lots/lot-id" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY" \
  -H "X-ShelfCycle-Client: Lot age review"
```

The detail repeats the lot header and adds `remainingPhysicalLayers` in oldest-first order. Each layer includes its recorded addition time, original quantity, remaining quantity, packaging reference, and source kind. `remainingPhysicalPackagingId` identifies one shared package, `MIXED`, or `UNKNOWN` across those layers.

Use `layerCoverage.remainingLayerCount`, `returnedLayers`, and `truncated` to describe how much of the layer detail is included. The lot header's recorded age is calculated from the complete available history even when the displayed layer list is shortened.

## Continue and refresh

When `meta.hasMore` is true, continue with `meta.nextCursor` by itself:

```bash
curl "$SHELFCYCLE_API_BASE_URL/lots?cursor=$NEXT_CURSOR" \
  -H "Authorization: Bearer $SHELFCYCLE_API_KEY"
```

Lot pages are current-state reads. Periodically restart the original filtered request to refresh the complete view, and use the exact lot UUID for later detail reads.

> **Guardrail**: Keep each named lot, product, package, warehouse, and quantity basis together. Present recorded stock age separately from manufacture and expiration dates.
