Inventory
Update stock levels for individual products or in bulk. Supports absolute set and relative adjust modes.
Inventory
Update stock levels for individual products or in bulk. The inventory API supports two modes: set (absolute stock level) and adjust (relative delta), with per-variant granularity.
Single stock update
Update the stock quantity for a single product and/or its variants.
PATCH /dev/store/products/{id}/stockRequest body
| Field | Type | Required | Description |
|---|---|---|---|
quantity | integer | No | New product-level stock quantity |
variants | array | No | Variant stock updates (see below) |
Variant stock object
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Variant label (case-insensitive match) |
quantity | integer | Yes | New stock quantity for this variant |
curl -X PATCH https://api.elebne.ai/api/v1/dev/store/products/THIEB-001/stock \
-H "Authorization: Bearer sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"quantity": 50,
"variants": [
{ "label": "Normal", "quantity": 35 },
{ "label": "Grand", "quantity": 15 }
]
}'const response = await fetch(
'https://api.elebne.ai/api/v1/dev/store/products/THIEB-001/stock',
{
method: 'PATCH',
headers: {
'Authorization': 'Bearer sk_test_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
quantity: 50,
variants: [
{ label: 'Normal', quantity: 35 },
{ label: 'Grand', quantity: 15 },
],
}),
}
);
const { data } = await response.json();
console.log(data.quantity); // 50response = requests.patch(
'https://api.elebne.ai/api/v1/dev/store/products/THIEB-001/stock',
headers={
'Authorization': 'Bearer sk_test_YOUR_KEY',
'Content-Type': 'application/json',
},
json={
'quantity': 50,
'variants': [
{'label': 'Normal', 'quantity': 35},
{'label': 'Grand', 'quantity': 15},
],
},
)
data = response.json()['data']
print(data['quantity']) # 50Returns the full updated product object.
Bulk inventory update
Update stock for up to 200 products in a single request. Products are matched by externalId (SKU).
PATCH /dev/store/inventory/bulkExternalId required
Bulk inventory uses externalId to match products. Make sure your products have externalId set (via create, update, or CSV import).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
items | array | Yes | Up to 200 inventory updates |
Item object
| Field | Type | Required | Description |
|---|---|---|---|
externalId | string | Yes | Product SKU / external ID |
mode | string | No | set or adjust. Default: adjust. |
quantity | integer | No | Absolute stock level (used when mode: "set") |
quantityDelta | integer | No | Stock change (used when mode: "adjust"). Positive to add, negative to subtract. |
variants | array | No | Per-variant updates (see below) |
Variant bulk object
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Variant label (case-insensitive) |
mode | string | No | Overrides the item-level mode |
quantity | integer | No | Absolute stock (for set mode) |
quantityDelta | integer | No | Stock delta (for adjust mode) |
Set mode vs adjust mode
Set mode (mode: "set") replaces the stock level with an absolute value. Use this when your warehouse system reports current quantities.
Adjust mode (mode: "adjust") applies a delta to the current stock. Stock cannot go below 0. Use this when processing sales or restocks.
curl -X PATCH https://api.elebne.ai/api/v1/dev/store/inventory/bulk \
-H "Authorization: Bearer sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"externalId": "THIEB-001",
"mode": "set",
"quantity": 50,
"variants": [
{ "label": "Normal", "quantity": 35 },
{ "label": "Grand", "quantity": 15 }
]
},
{
"externalId": "YASSA-002",
"mode": "adjust",
"quantityDelta": -5
},
{
"externalId": "MAFE-003",
"mode": "adjust",
"quantityDelta": 20
}
]
}'const response = await fetch(
'https://api.elebne.ai/api/v1/dev/store/inventory/bulk',
{
method: 'PATCH',
headers: {
'Authorization': 'Bearer sk_test_YOUR_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
items: [
{
externalId: 'THIEB-001',
mode: 'set',
quantity: 50,
variants: [
{ label: 'Normal', quantity: 35 },
{ label: 'Grand', quantity: 15 },
],
},
{ externalId: 'YASSA-002', mode: 'adjust', quantityDelta: -5 },
{ externalId: 'MAFE-003', mode: 'adjust', quantityDelta: 20 },
],
}),
}
);
const { data } = await response.json();
console.log(data.updated); // 3
console.log(data.failed); // 0response = requests.patch(
'https://api.elebne.ai/api/v1/dev/store/inventory/bulk',
headers={
'Authorization': 'Bearer sk_test_YOUR_KEY',
'Content-Type': 'application/json',
},
json={
'items': [
{
'externalId': 'THIEB-001',
'mode': 'set',
'quantity': 50,
'variants': [
{'label': 'Normal', 'quantity': 35},
{'label': 'Grand', 'quantity': 15},
],
},
{'externalId': 'YASSA-002', 'mode': 'adjust', 'quantityDelta': -5},
{'externalId': 'MAFE-003', 'mode': 'adjust', 'quantityDelta': 20},
],
},
)
data = response.json()['data']
print(f"Updated: {data['updated']}, Failed: {data['failed']}")Response
{
"success": true,
"data": {
"updated": 3,
"failed": 0,
"errors": []
}
}When some items fail, the response includes per-item errors while the successful items are still applied:
{
"success": true,
"data": {
"updated": 2,
"failed": 1,
"errors": [
{ "externalId": "UNKNOWN-SKU", "error": "Product not found" }
]
}
}List inventory
Get a compact inventory view of all tracked products (those with quantity set).
GET /dev/store/inventory?lowStock=true&page=1&limit=100| Parameter | Type | Default | Description |
|---|---|---|---|
lowStock | string | -- | Set to true to only show items below the low-stock threshold |
page | integer | 1 | Page number |
limit | integer | 100 | Results per page (max 100) |
curl "https://api.elebne.ai/api/v1/dev/store/inventory?lowStock=true" \
-H "Authorization: Bearer pk_test_YOUR_KEY"const response = await fetch(
'https://api.elebne.ai/api/v1/dev/store/inventory?lowStock=true',
{
headers: { 'Authorization': 'Bearer pk_test_YOUR_KEY' },
}
);
const { items, total, hasMore } = await response.json();
for (const item of items) {
if (item.isLowStock) {
console.log(`Low stock: ${item.name} (${item.quantity} left)`);
}
}response = requests.get(
'https://api.elebne.ai/api/v1/dev/store/inventory',
headers={'Authorization': 'Bearer pk_test_YOUR_KEY'},
params={'lowStock': 'true'},
)
result = response.json()
for item in result['items']:
if item['isLowStock']:
print(f"Low stock: {item['name']} ({item['quantity']} left)")Response
{
"success": true,
"data": {
"items": [
{
"productId": "6612f1a2b3c4d5e6f7890123",
"externalId": "THIEB-001",
"name": "Thiéboudienne Royale",
"quantity": 3,
"lowStockThreshold": 5,
"isLowStock": true,
"variants": [
{ "variantId": "6612f...", "label": "Normal", "quantity": 2 },
{ "variantId": "6612f...", "label": "Grand", "quantity": 1 }
]
}
],
"total": 1,
"page": 1,
"hasMore": false
}
}Error responses
| Error code | HTTP | Description |
|---|---|---|
VARIANT_NOT_FOUND | 400 | Variant label does not match any variant on the product |
VARIANT_LABEL_AMBIGUOUS | 400 | Multiple variants share the same label |
TOO_MANY_ITEMS | 400 | Bulk request exceeds 200 items |
PRODUCT_NOT_FOUND | 404 | Product not found by ID or externalId |
Next steps
- Products -- create products with variants before updating stock
- CSV Import -- bulk import products with initial quantities
- Webhook Events -- get notified on
product.stock_lowandproduct.stock_out
Was this page helpful?