Inventory API
The Inventory API enables you to query product catalog data and real-time stock levels for your business. Use it to check availability before creating orders or to sync stock data with external systems.
Overview
- List Inventory: Retrieve all products with optional search filtering
- Get Single Item: Look up a specific inventory item by ID
- Declare On-Hand Quantity: Set the absolute stock level for a SKU (requires
inventory:write) - Upsert and Archive Catalog Items: Create, update or archive catalog items by SKU without touching stock (requires
inventory:write)
Authentication
Both inventory endpoints require:
- Scope:
inventory:read - Auth Method: OAuth 2.0 M2M (Machine-to-Machine)
- Format: Bearer token in
Authorizationheader
See the Authentication guide for how to obtain a JWT token with the inventory:read scope.
List Inventory
Retrieve a list of all active inventory items for your business.
Request
GET /e9v3/inventory?search=<query>&limit=100
Authorization: Bearer <jwt-token>
Query Parameters
| Parameter | Type | Required | Default | Max | Description |
|---|---|---|---|---|---|
search |
string | No | — | — | Filter by SKU, product name, category, or barcode (case-insensitive) |
limit |
integer | No | 100 | 500 | Maximum number of results to return per page |
cursor |
string | No | — | — | Previous page’s nextCursor. Omit for the first page — existing clients that only send search/limit are unchanged. |
Response (200 OK)
{
"success": true,
"inventory": [
{
"itemId": "inv_a1b2c3d4",
"businessId": "biz-456",
"sku": "WIDGET-001",
"productName": "Premium Widget",
"description": "High-quality widget for industrial use",
"category": "Widgets",
"brand": "Acme",
"barcode": "9781234567890",
"imageUrl": "https://storage.example.com/widget-001.jpg",
"availableQuantity": 150,
"totalQuantity": 200,
"reservedQuantity": 30,
"orderedQuantity": 20,
"returnsQuantity": 0,
"unitOfMeasure": "pcs",
"isActive": true,
"isComposite": false,
"stockStatus": "inStock"
}
],
"count": 1,
"hasMore": false
}
Response Fields
| Field | Type | Description |
|---|---|---|
itemId |
string | Unique inventory item identifier |
businessId |
string | Business this item belongs to |
sku |
string | Stock Keeping Unit code |
productName |
string | Product display name |
description |
string | Product description |
category |
string | Product category |
brand |
string | Brand name (if set) |
barcode |
string | Barcode / GTIN (if set) |
imageUrl |
string | Product image URL (if set) |
availableQuantity |
integer | Quantity available for new orders |
totalQuantity |
integer | Total stock on hand |
reservedQuantity |
integer | Quantity reserved for pending orders |
orderedQuantity |
integer | Quantity on outstanding purchase orders |
returnsQuantity |
integer | Quantity pending return processing |
unitOfMeasure |
string | Unit of measure (e.g., pcs, kg, m) |
isActive |
boolean | Whether the item is active (inactive items are excluded from listings) |
isComposite |
boolean | Whether the item is a composite/kit product |
stockStatus |
string | Computed status: inStock, lowStock, critical, outOfStock |
metadata |
object | Free-form custom attributes |
List-level paging fields (additive — existing clients that ignore unknown JSON keys are unchanged):
| Field | Type | Description |
|---|---|---|
count |
integer | Number of items in this page |
hasMore |
boolean | true when another page is available |
nextCursor |
string | Pass as cursor on the next request. Omitted when hasMore is false |
Paging:
limitis a page size (max 500), not a cap on the catalog. ExistingGET /e9v3/inventory?limit=100(or?search=&limit=) calls still return the first page withsuccess,inventory, andcount. To dump the whole catalog, loop whilehasMoreis true and passnextCursorascursor.
Data source: list and search both read the versioned InventoryIndex (quantities as of the last IndexRegenerate). Variant SKUs appear as extra rows with
itemIdof the parent product. Get-by-id reads the live Inventory document. Inactive items (isActive: false) are silently excluded from the list endpoint. If no index is published, list returns404with"Inventory index not published".
Stock Status Logic
| Status | Condition |
|---|---|
inStock |
Available > 25% of total |
lowStock |
Available between 10%–25% of total |
critical |
Available below 10% of total |
outOfStock |
Available is 0 or total is 0 |
Get Single Item
Look up a specific inventory item by its ID. This reads the live Inventory document (not the versioned index).
Request
GET /e9v3/inventory/:itemId
Authorization: Bearer <jwt-token>
Response (200 OK)
{
"success": true,
"inventory": [
{
"itemId": "inv_a1b2c3d4",
"sku": "WIDGET-001",
"productName": "Premium Widget",
"availableQuantity": 150,
"totalQuantity": 200,
"stockStatus": "inStock"
}
],
"count": 1
}
Response (404 Not Found)
{
"success": false,
"error": "Inventory item not found"
}
Declare On-Hand Quantity
Set (not adjust) the absolute on-hand quantity for a SKU. This is applied through the platform’s transactional inventory pipeline as an asynchronous job and returns a jobId — poll GET /e9v3/jobs/:jobId for the outcome. Requires the inventory:write scope.
Request
POST /e9v3/inventory/sync
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
"sku": "WIDGET-001",
"quantity": 200,
"sourceRecordId": "stocktake-2024-01-15"
}
Response (200 OK)
{
"success": true,
"jobId": "inventory_1776400267719207348"
}
Notes:
quantityis the new absolute on-hand count, not a delta.- Unlike the order writes, this endpoint validates the SKU — an unknown SKU returns
404. - Retries with the same
sourceRecordIdare deduplicated via a deterministic job id.
See the Endpoints reference for the full schema.
Upsert and Archive Catalog Items
Create, update or archive catalog items by SKU, for example to keep a storefront’s product list in step. These routes change item metadata only: stock quantities are never changed. Requires the inventory:write scope.
| Route | What it does |
|---|---|
POST /e9v3/inventory/items |
Creates or updates one item keyed by sku. Returns { success, itemId, action } where action is created or updated. |
POST /e9v3/inventory/items/batch |
Up to 50 items in { items: [...] }, with a per-item result in results (partial success is allowed). More than 50 items returns 400. |
POST /e9v3/inventory/items/{sku}/archive |
Archives the item (moved to the archive, never hard-deleted). Idempotent when already archived. |
Request
POST /e9v3/inventory/items
Authorization: Bearer <jwt-token>
Content-Type: application/json
{
"sku": "WIDGET-001",
"name": "Widget",
"barcode": "9300000000001",
"weightGrams": 250,
"active": true,
"sourceRecordId": "shopify:my-shop:variant:42"
}
Notes:
skuis required, up to 256 characters.- Upserts with the same
sourceRecordIdand SKU are idempotent. A SKU already owned by a differentsourceRecordIdreturns409. active: falsearchives the item, the same as the archive route.
Common Use Cases
Check stock before creating an order
# 1. Search for the product by SKU
curl -X GET 'https://api.equos.one/e9v3/inventory?search=WIDGET-001' \
-H 'Authorization: Bearer <jwt-token>'
# 2. Verify availableQuantity >= order quantity
# 3. Create the order if stock is sufficient
curl -X POST 'https://api.equos.one/e9v3/orders/send' \
-H 'Authorization: Bearer <jwt-token>' \
-H 'Content-Type: application/json' \
-d '{"customerId": "cust-123", "items": [{"sku": "WIDGET-001", "productName": "Premium Widget", "quantity": 5}]}'
Sync stock levels to an external system
# First page (same call existing integrations already make)
curl -X GET 'https://api.equos.one/e9v3/inventory?limit=500' \
-H 'Authorization: Bearer <jwt-token>'
# Following pages: repeat until hasMore is false
curl -X GET 'https://api.equos.one/e9v3/inventory?limit=500&cursor=<nextCursor>' \
-H 'Authorization: Bearer <jwt-token>'
Filter by category
curl -X GET 'https://api.equos.one/e9v3/inventory?search=Electronics&limit=50' \
-H 'Authorization: Bearer <jwt-token>'
Error Handling
| Status | Meaning |
|---|---|
200 |
Success |
401 |
Invalid or missing Bearer token |
403 |
Token lacks inventory:read scope |
404 |
Item not found (single item lookup), or inventory index not published (list/search) |
429 |
Rate limit exceeded |
500 |
Server error |
Next Steps
- Create Orders using item SKUs from the inventory
- API Tester to try inventory queries interactively
- Webhooks to receive notifications when stock levels change