Inventory Management
Multi-location stock tracking, transfers, audits, cost layers, and unit-level QR tracking.
Overview
The inventory API gives you real-time visibility into stock across every location. Track quantities at the product and variant level, move stock between warehouses and stores, run cycle count audits, maintain cost layers for accurate COGS reporting, and optionally track individual units by serial number or QR code.
Multi-location
Track stock independently at each warehouse, store, or fulfillment center.
Real-time levels
Quantities update instantly on sales, returns, adjustments, and transfers.
Transfers
Move stock between locations with full audit trail and status tracking.
Cycle counts
Run inventory audits with variance detection and reconciliation.
Cost layers
FIFO, LIFO, or weighted average costing for accurate COGS.
Unit tracking
Serial numbers and QR codes for individual item lifecycle tracking.
Stock Levels
Query current stock quantities by product, variant, or location. Each inventory record includes the on-hand quantity, committed (reserved for orders), and available (on-hand minus committed).
const whale = new WhaleClient("wk_live_...");
// List stock at a specific location
const stock = await whale.inventory.list({
location_id: "loc_warehouse_east",
limit: 50
});
// Response
{
"object": "list",
"data": [
{
"id": "inv_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"product_id": "prod_001",
"variant_id": "var_001_blue_m",
"location_id": "loc_warehouse_east",
"on_hand": 150,
"committed": 12,
"available": 138,
"reorder_point": 25,
"updated_at": "2026-03-10T08:30:00.000Z"
}
]
}Adjust Stock
Increase or decrease stock with a reason code for audit compliance. Adjustments create a permanent ledger entry — quantities are never silently changed. Common reasons include received, damaged, shrinkage, and correction.
// Add stock after receiving a shipment
await whale.inventory.adjust({
product_id: "prod_001",
variant_id: "var_001_blue_m",
location_id: "loc_warehouse_east",
quantity_change: 50,
reason: "received",
reference: "PO-2026-0342",
notes: "Spring collection restock"
});
// Remove damaged units
await whale.inventory.adjust({
product_id: "prod_001",
variant_id: "var_001_blue_m",
location_id: "loc_warehouse_east",
quantity_change: -3,
reason: "damaged",
notes: "Water damage in transit"
});
// Response
{
"object": "inventory_adjustment",
"id": "adj_f1e2d3c4-b5a6-7890-abcd-ef1234567890",
"product_id": "prod_001",
"location_id": "loc_warehouse_east",
"quantity_change": -3,
"reason": "damaged",
"previous_on_hand": 200,
"new_on_hand": 197,
"created_at": "2026-03-10T09:15:00.000Z"
}Transfer Between Locations
Move stock from one location to another. Transfers go through a lifecycle: pending (created), in_transit (shipped between locations), and completed (received at destination). Source quantities are decremented immediately; destination quantities increase on completion.
const transfer = await whale.inventory.transfer({
from_location: "loc_warehouse_east",
to_location: "loc_store_downtown",
items: [
{
product_id: "prod_001",
variant_id: "var_001_blue_m",
quantity: 20
},
{
product_id: "prod_002",
variant_id: "var_002_black_l",
quantity: 10
}
],
notes: "Restocking downtown store for weekend sale"
});
// Response
{
"object": "inventory_transfer",
"id": "txfr_c3d4e5f6-a7b8-9012-cdef-1234567890ab",
"status": "pending",
"from_location": "loc_warehouse_east",
"to_location": "loc_store_downtown",
"items": [
{ "product_id": "prod_001", "variant_id": "var_001_blue_m", "quantity": 20 },
{ "product_id": "prod_002", "variant_id": "var_002_black_l", "quantity": 10 }
],
"created_at": "2026-03-10T10:00:00.000Z"
}Inventory Audits
Run cycle count audits to verify physical stock matches system records. Create an audit for a location, submit counted quantities, and the system calculates variances automatically. Audits can be approved to reconcile discrepancies.
// Create a cycle count audit
const audit = await whale.inventoryAudits.create({
location_id: "loc_store_downtown",
type: "cycle_count",
notes: "Monthly cycle count — Zone A shelves"
});
// Submit counted items
await whale.inventoryAudits.update(audit.id, {
status: "counted",
items: [
{
product_id: "prod_001",
variant_id: "var_001_blue_m",
expected_quantity: 45,
counted_quantity: 43
},
{
product_id: "prod_002",
variant_id: "var_002_black_l",
expected_quantity: 30,
counted_quantity: 30
}
]
});
// Response
{
"object": "inventory_audit",
"id": "aud_d4e5f6a7-b8c9-0123-defg-234567890abc",
"location_id": "loc_store_downtown",
"status": "counted",
"type": "cycle_count",
"total_items": 2,
"variance_count": 1,
"items": [
{
"product_id": "prod_001",
"expected_quantity": 45,
"counted_quantity": 43,
"variance": -2
},
{
"product_id": "prod_002",
"expected_quantity": 30,
"counted_quantity": 30,
"variance": 0
}
],
"created_at": "2026-03-10T11:00:00.000Z"
}Cost Layers
Track the landed cost of inventory using FIFO, LIFO, or weighted average methods. Each receipt creates a cost layer with the purchase price, shipping, duties, and other landed costs. When stock is sold, cost layers are consumed according to the configured method for accurate COGS reporting.
// List cost layers for a product
const layers = await whale.inventoryCostLayers.list({
product_id: "prod_001",
limit: 10
});
// Response
{
"object": "list",
"data": [
{
"id": "cl_e5f6a7b8-c9d0-1234-efgh-345678901bcd",
"product_id": "prod_001",
"variant_id": "var_001_blue_m",
"costing_method": "fifo",
"unit_cost": 12.50,
"landed_cost": 14.20,
"quantity_received": 100,
"quantity_remaining": 67,
"reference": "PO-2026-0298",
"received_at": "2026-02-15T08:00:00.000Z"
},
{
"id": "cl_f6a7b8c9-d0e1-2345-fghi-456789012cde",
"product_id": "prod_001",
"variant_id": "var_001_blue_m",
"costing_method": "fifo",
"unit_cost": 13.00,
"landed_cost": 14.85,
"quantity_received": 50,
"quantity_remaining": 50,
"reference": "PO-2026-0342",
"received_at": "2026-03-10T09:00:00.000Z"
}
]
}Unit Tracking
Track individual items by serial number or QR code throughout their lifecycle. Each unit records its current status, location, and full history — from receipt to sale or return. Useful for high-value goods, warranty tracking, and anti-counterfeiting.
// Register a new tracked unit
const unit = await whale.inventoryUnits.create({
product_id: "prod_003",
variant_id: "var_003_gold",
serial_number: "SN-2026-00451",
qr_code: "https://wh.al/u/SN-2026-00451",
location_id: "loc_warehouse_east",
cost: 245.00,
metadata: {
batch: "B2026-03",
inspection_date: "2026-03-08"
}
});
// List units with filters
const units = await whale.inventoryUnits.list({
product_id: "prod_003",
status: "in_stock",
location_id: "loc_warehouse_east"
});
// Response
{
"object": "list",
"data": [
{
"id": "unit_a7b8c9d0-e1f2-3456-ghij-567890123def",
"product_id": "prod_003",
"serial_number": "SN-2026-00451",
"qr_code": "https://wh.al/u/SN-2026-00451",
"status": "in_stock",
"location_id": "loc_warehouse_east",
"cost": 245.00,
"history": [
{ "event": "received", "at": "2026-03-09T08:00:00.000Z", "location": "loc_warehouse_east" },
{ "event": "inspected", "at": "2026-03-09T10:30:00.000Z", "by": "staff_mike" }
],
"created_at": "2026-03-09T08:00:00.000Z"
}
]
}API Reference
| Method | Path | Description |
|---|---|---|
| GET | /v1/stores/{store_id}/inventory | List stock levels. Filter by location_id, product_id, or variant_id. |
| GET | /v1/stores/{store_id}/inventory/{id} | Get a single inventory record with quantity breakdown. |
| POST | /v1/stores/{store_id}/inventory/adjust | Adjust stock quantity with a reason code. |
| POST | /v1/stores/{store_id}/inventory/transfer | Transfer stock between two locations. |
| GET | /v1/stores/{store_id}/inventory-audits | List inventory audits. Filter by location_id or status. |
| GET | /v1/stores/{store_id}/inventory-audits/{id} | Get a single audit with counted items. |
| POST | /v1/stores/{store_id}/inventory-audits | Create a new cycle count audit for a location. |
| PATCH | /v1/stores/{store_id}/inventory-audits/{id} | Update audit status or submit counted items. |
| GET | /v1/stores/{store_id}/inventory-cost-layers | List cost layers. Filter by product_id or costing method. |
| GET | /v1/stores/{store_id}/inventory-cost-layers/{id} | Get a single cost layer with receipt history. |
| GET | /v1/stores/{store_id}/inventory-units | List tracked units. Filter by serial_number, product_id, or status. |
| GET | /v1/stores/{store_id}/inventory-units/{id} | Get a single unit with full lifecycle history. |
| POST | /v1/stores/{store_id}/inventory-units | Register a new tracked unit with serial number or QR code. |
| PATCH | /v1/stores/{store_id}/inventory-units/{id} | Update unit status, location, or metadata. |