# Inventory

> Manage products, variants, orders, shipments, locations, and production.

- **Category:** Guides
- HTML version: https://www.ondayzero.com/docs/guides/inventory
- All guides: https://www.ondayzero.com/docs/guides/index.md
- Endpoint catalog: https://www.ondayzero.com/docs/reference/index.md

---

# Inventory

DayZero's inventory module covers products, variants, purchase orders, shipments, warehouse locations, transfers, cycle counts, and production. This feature requires the **Commerce** add-on.

Most inventory routes live under `/api/v1/inventory/…`; purchase orders are at `/api/v1/purchase-orders` and customer order forms at `/api/v1/orders`.

## Products

### Create a Product

```bash
curl -X POST "https://api.ondayzero.com/api/v1/inventory/products" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Widget Pro",
    "type": "manual",
    "category": "Hardware"
  }'
```

`type` is the product's source: `manual` (created here) or `shopify` (synced from a connected store — don't create these yourself). Set `tracks_expiration: true` for perishable goods so cost lots carry expiry dates.

### List Products

```bash
curl "https://api.ondayzero.com/api/v1/inventory/products?type=manual&include_variants=true&archived=false" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `type` | string | `manual` or `shopify` |
| `category` | string | Filter by category |
| `search` | string | Match on product name |
| `include_variants` | boolean | Embed variant data in each product |
| `archived` | boolean | `true` only archived, `false` only live, omit for all |

Plus the standard [pagination](/docs/guides/pagination) parameters.

### Variants

Products can have multiple variants (sizes, colors, etc.). Variants are what you stock, price and put on invoices:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/inventory/products/variants" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "PRODUCT_UUID",
    "name": "Widget Pro - Large",
    "sku": "WP-LG-001",
    "barcode": "0123456789012",
    "unit_price": 2999,
    "unit_cost": 1250,
    "uom": "EA",
    "initial_inventory_quantity": 100
  }'
```

> `unit_price` (sale price) and `unit_cost` are in cents: `2999` = $29.99. For sub-cent costs (ingredients priced per gram) use `unit_cost_precise` in dollars, e.g. `0.0478`.

`GET /api/v1/inventory/products/variants?product_id=…` lists variants; `GET /api/v1/inventory/products/lookup?sku=WP-LG-001` (or `?barcode=…`) finds one for scanning workflows. `PUT /api/v1/inventory/products/variants/{id}/location-quantities` sets opening quantities per warehouse.

## Purchase Orders

Purchase orders to vendors — and the shipments, receipts and bills that follow them — live under `/api/v1/purchase-orders`:

```bash
curl "https://api.ondayzero.com/api/v1/purchase-orders?status=submitted&vendor_id=VENDOR_UUID" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

Statuses run `draft` → `submitted` → `in_production` → `ready` → `shipped` → `partially_received` / `received` → `completed`, or `canceled`. `POST /api/v1/purchase-orders` creates one. Receiving against a PO updates on-hand quantities, and `GET /api/v1/inventory/accounts-payable` lists the vendor bills generated from POs with their three-way-match status (PO ↔ receipt ↔ bill). Customer-facing order forms are separate: `GET` / `POST /api/v1/orders`.

## Locations

Warehouse and storage locations:

```bash
curl "https://api.ondayzero.com/api/v1/inventory/locations" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

`POST /api/v1/inventory/locations` creates one; `POST …/locations/{location_id}/set-default` chooses where unlocated stock movements land; `GET …/locations/{location_id}/inventory` shows what is on hand there and `GET …/locations/summaries` compares all locations at once.

## Shipments

Track inbound and outbound shipments tied to orders:

```bash
curl "https://api.ondayzero.com/api/v1/inventory/shipments" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

## Transfers

Move inventory between locations:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/inventory/transfers" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "from_location_id": "LOCATION_UUID_1",
    "to_location_id": "LOCATION_UUID_2",
    "items": [
      {"variant_id": "VARIANT_UUID", "quantity": 10}
    ]
  }'
```

A transfer is created pending; `POST …/transfers/{transfer_id}/ship` moves the stock in transit and `POST …/transfers/{transfer_id}/receive` lands it at the destination (`/cancel` abandons it). Optional fields: `carrier`, `tracking_number`, `expected_arrival_date`, `shipping_cost` (cents). `GET /api/v1/inventory/transfer-suggestions/suggestions` proposes site-to-site rebalancing.

## Adjustments

Record a manual inventory adjustment (shrinkage, corrections, etc.) — one variant per call:

```bash
curl -X POST "https://api.ondayzero.com/api/v1/inventory/adjustments" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "variant_id": "VARIANT_UUID",
    "location_id": "LOCATION_UUID",
    "quantity_change": -5,
    "reason": "Damaged in transit",
    "reason_code": "damage"
  }'
```

`quantity_change` is signed (negative removes stock). If `location_id` is omitted the default location is used. For a full stock take, use cycle counts instead: `POST /api/v1/inventory/counts` starts one, `POST …/counts/{count_id}/lines` and `PUT …/counts/{count_id}/lines/{line_id}` record counted quantities, and `POST …/counts/{count_id}/post` books the variances. `GET /api/v1/inventory/reports/adjustment-reasons` summarises adjustments by reason.

## Production

Manage recipes (bills of materials) and production runs for manufactured goods:

```bash
curl "https://api.ondayzero.com/api/v1/inventory/production/recipes" \
  -H "Authorization: Bearer dz_your_token_here" \
  -H "x-business-id: YOUR_BUSINESS_ID"
```

`POST /api/v1/inventory/production/runs` schedules a run from a recipe, `POST …/runs/{run_id}/calculate` previews component consumption and cost, and `POST …/runs/{run_id}/complete` consumes the components and adds the finished goods.

## Reports and planning

- `GET /api/v1/inventory/reports/valuation` — current inventory value; `…/reports/aging` and `…/reports/margin-by-sku` for slow movers and margins.
- `GET /api/v1/inventory/cost-history` — landed COGS over time; `GET /api/v1/inventory/lots/expiring` — cost lots approaching expiry.
- `GET /api/v1/inventory/reorder/suggestions` — what to reorder based on reorder points; `POST /api/v1/inventory/reorder/draft` turns suggestions into draft purchase orders and `POST …/reorder/cash-impact` previews the cash effect.
- `GET /api/v1/inventory/forecast/skus` — per-SKU demand forecasts (`POST …/forecast/recompute` to refresh).
- `GET /api/v1/inventory/activity` — a unified movement log across receipts, sales, transfers, adjustments and production.

## Import

Bulk import products, variants, locations and stock levels from a spreadsheet using a 3-phase AI-assisted flow:

1. **Analyze** — `POST /api/v1/inventory/import/analyze` (multipart `file`) returns a `task_id`; poll `GET /api/v1/inventory/import/analyze/{task_id}` until the AI has mapped the sheets and columns.
2. **Preview** — `POST /api/v1/inventory/import/preview` with the `file_id`, `selected_sheets` and (optionally corrected) `sheet_mappings` returns exactly what would be created or updated.
3. **Apply** — `POST /api/v1/inventory/import/apply` with the `file_id` and the reviewed `products`, `locations` and `levels` decisions.

The same pattern under `/api/v1/inventory/po-import/…` turns a manufacturer's order spreadsheet into a purchase order with SKU matching.
