The Inventory API lets external systems read product stock levels, push stock updates, and view stock movement history. Use it to keep SalesPro Hub in sync with your warehouse or ERP system.
Endpoints
List Products
GET /api/v1/inventoryPermission required: inventory:read
Retrieve a deterministic, paginated list of tenant products with their current stock levels. Results are ordered by SKU and then internal ID.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
is_active | boolean | Optional active/inactive filter |
updated_since | ISO 8601 | Only products updated at or after this timestamp |
per_page | integer | Results per page (1-100, default 100) |
page | integer | Page number (minimum 1) |
Example
curl -X GET "https://portal.salesrepsoftware.co.za/api/v1/inventory" \
-H "X-API-Key: sk_your_key" \
-H "Accept: application/json"Response
{
"success": true,
"data": [
{
"id": 1,
"sku": "WDG-001",
"name": "Widget A",
"stock_qty": 150,
"reserved_qty": 20,
"available_qty": 130,
"reservation_shortfall_qty": 0,
"low_stock_threshold": 25,
"is_low_stock": false,
"is_out_of_stock": false,
"is_active": true
},
{
"id": 2,
"sku": "WDG-002",
"name": "Widget B",
"stock_qty": 8,
"reserved_qty": 3,
"available_qty": 5,
"reservation_shortfall_qty": 0,
"low_stock_threshold": 10,
"is_low_stock": true,
"is_out_of_stock": false,
"is_active": true
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 100,
"total": 2,
"synced_at": "2026-02-09T12:00:00+02:00"
}
}Stock Quantity Fields
| Field | Description |
|---|---|
stock_qty | Total physical stock on hand |
reserved_qty | Quantity reserved by pending/confirmed orders |
available_qty | Stock available to sell (stock_qty - reserved_qty) |
reservation_shortfall_qty | Reserved demand above physical on-hand stock; zero when reservations are fully covered |
low_stock_threshold | Alert threshold configured per product |
is_low_stock | true when stock_qty <= low_stock_threshold and stock_qty > 0 |
is_out_of_stock | true when stock_qty <= 0 |
Get Single Product
GET /api/v1/inventory/{sku}Permission required: inventory:read
Look up a single product by its SKU.
Example
curl -X GET "https://portal.salesrepsoftware.co.za/api/v1/inventory/WDG-001" \
-H "X-API-Key: sk_your_key" \
-H "Accept: application/json"Response
{
"success": true,
"data": {
"id": 1,
"sku": "WDG-001",
"name": "Widget A",
"stock_qty": 150,
"reserved_qty": 20,
"available_qty": 130,
"reservation_shortfall_qty": 0,
"low_stock_threshold": 25,
"is_low_stock": false,
"is_out_of_stock": false,
"is_active": true
}
}Update Stock for Single Product
PUT /api/v1/inventory/{sku}Permission required: inventory:write
Set the stock quantity for a single product. This performs an absolute update (sets the stock to the given value, not a relative adjustment).
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
stock_qty | integer | Yes | New stock quantity (minimum 0) |
reference | string | No | Idempotency reference for this update (e.g., ERP event ID). Max 255 characters. |
Example
curl -X PUT "https://portal.salesrepsoftware.co.za/api/v1/inventory/WDG-001" \
-H "X-API-Key: sk_your_key" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"stock_qty": 200, "reference": "WH-RECEIPT-1234"}'Response
{
"success": true,
"data": {
"sku": "WDG-001",
"name": "Widget A",
"stock_qty": 200,
"reserved_qty": 20,
"available_qty": 180,
"reservation_shortfall_qty": 0,
"changed": true,
"replayed": false
},
"message": "Stock updated successfully"
}What Happens on Update
- The product row is locked so concurrent order and ERP writes cannot calculate from stale stock.
- A stock movement record is created with type
syncfor the audit trail. - A non-empty
referenceacts as an idempotency key for that SKU. Replaying the same reference and quantity returns the current stock without overwriting a newer update. - Reusing the reference for a different quantity returns HTTP
409with codeinventory_reference_conflict. - A changed stock level emits
StockLevelChangedonly after the database transaction commits.
An authoritative ERP snapshot may be lower than SalesPro Hub's existing
reservations. SalesPro Hub keeps the physical quantity accurate, returns
reservation_shortfall_qty, blocks a delivery deduction that would make stock
negative, and requires the shortage to be reconciled.
Bulk Update Stock
POST /api/v1/inventory/bulkPermission required: inventory:write
Update stock for multiple products in a single request. Efficient for daily warehouse syncs.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
products | array | Yes | Array of products to update (1-500 items) |
products[].sku | string | Yes | Product SKU; each SKU may appear only once per request |
products[].stock_qty | integer | Yes | New stock quantity (minimum 0) |
reference | string | No | Idempotency reference applied independently to each SKU. Max 255 characters. |
Example
curl -X POST "https://portal.salesrepsoftware.co.za/api/v1/inventory/bulk" \
-H "X-API-Key: sk_your_key" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"products": [
{"sku": "WDG-001", "stock_qty": 200},
{"sku": "WDG-002", "stock_qty": 50},
{"sku": "WDG-003", "stock_qty": 0},
{"sku": "INVALID-SKU", "stock_qty": 10}
],
"reference": "DAILY-SYNC-20260209"
}'Response
{
"success": true,
"data": {
"updated": 3,
"replayed": 0,
"failed": 1,
"errors": [
"SKU 'INVALID-SKU' not found"
]
},
"message": "Updated 3 products, 1 failed"
}The bulk endpoint processes all valid products even if some fail. Check
replayed and the errors array; a partial failure is still returned with
HTTP 200 so the connector can reconcile each SKU.
Get Stock Movement History
GET /api/v1/inventory/movementsPermission required: inventory:read
View the audit trail of all stock changes. Useful for reconciliation and debugging stock discrepancies.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
sku | string | Filter by product SKU |
type | string | Filter by movement type (see table below) |
from_date | date | Movements created on or after this date |
to_date | date | Movements created on or before this date |
per_page | integer | Results per page (1-100, default 50) |
Movement Types
| Type | Description |
|---|---|
reservation | Stock reserved when order submitted |
deduction | Stock deducted when order delivered |
release | Reserved stock released when order cancelled |
adjustment | Manual stock adjustment by admin |
sync | Stock updated via API |
import | Stock set during CSV/bulk import |
Example
curl -X GET "https://portal.salesrepsoftware.co.za/api/v1/inventory/movements?sku=WDG-001&type=sync&per_page=10" \
-H "X-API-Key: sk_your_key" \
-H "Accept: application/json"Response
{
"success": true,
"data": [
{
"id": 456,
"product": {
"id": 1,
"sku": "WDG-001",
"name": "Widget A"
},
"order": null,
"type": "sync",
"quantity": 50,
"stock_before": 150,
"stock_after": 200,
"reserved_before": 20,
"reserved_after": 20,
"reference": "DAILY-SYNC-20260209",
"notes": "Stock synced from external system",
"created_at": "2026-02-09T06:00:00+02:00"
}
],
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 10,
"total": 1
}
}Recommended Sync Strategy
Daily Full Sync
Run once daily (e.g., 6:00 AM before business hours):
# Export all stock levels from your warehouse system, then:
curl -X POST "https://portal.salesrepsoftware.co.za/api/v1/inventory/bulk" \
-H "X-API-Key: sk_your_key" \
-H "Content-Type: application/json" \
-d '{
"products": [
{"sku": "WDG-001", "stock_qty": 200},
{"sku": "WDG-002", "stock_qty": 50}
],
"reference": "DAILY-SYNC-20260209"
}'Real-Time Updates
For systems that need tighter sync, update individual products as stock changes:
curl -X PUT "https://portal.salesrepsoftware.co.za/api/v1/inventory/WDG-001" \
-H "X-API-Key: sk_your_key" \
-H "Content-Type: application/json" \
-d '{"stock_qty": 195, "reference": "WH-PICK-789"}'Bi-Directional Sync
Depending on the tenant's configured inventory policy, SalesPro Hub can also change stock levels when:
- Orders are submitted — stock is reserved or deducted
- Orders are delivered — reserved stock is deducted
- Orders are cancelled — reserved stock is released
- Admins adjust stock — manual corrections
To capture these changes in your external system, use webhooks with the inventory.* events, or poll the movements endpoint:
curl -X GET "https://portal.salesrepsoftware.co.za/api/v1/inventory/movements?from_date=2026-02-09&type=deduction" \
-H "X-API-Key: sk_your_key"Choose one physical-stock system of record. Do not deduct the same delivery in both the ERP and SalesPro Hub.