Inventory Management
All routes under /api/v1/inventory require authentication.
Categories
GET /inventory/categories
List all categories for the current organisation.
Auth: Required
Response (200):
{
"success": true,
"data": [
{
"id": "uuid",
"name": "Beverages",
"description": "Drinks and beverages",
"sort_order": 0,
"is_active": true,
"product_count": 15,
"created_at": "2024-01-01T00:00:00Z"
}
]
}POST /inventory/categories
Create a new category.
Auth: Required
Request Body:
{
"name": "Beverages",
"description": "Drinks and beverages"
}Response: Category object.
PATCH /inventory/categories/:id
Update a category.
Auth: Required
Request Body (all optional):
{
"name": "Soft Drinks",
"description": "Non-alcoholic beverages",
"sort_order": 1,
"is_active": true
}Response: Category object.
DELETE /inventory/categories/:id
Delete a category.
Auth: Required
Response (204): No Content
Products
GET /inventory/products
List products with filtering and pagination.
Auth: Required
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search | string | Search by name/SKU |
category_id | uuid | Filter by category |
status | string | active or inactive |
low_stock | boolean | Only low-stock products |
page | int | Page number (default: 1) |
page_size | int | Items per page (default: 20) |
Response: Paginated product list.
POST /inventory/products
Create a new product.
Auth: Required
Request Body:
{
"name": "Pepsi 500ml",
"category_id": "uuid",
"sku": "BEV-001",
"barcode": "1234567890123",
"cost_price": 800,
"selling_price": 1500,
"stock": 100,
"reorder_point": 20,
"image": "https://...",
"tax_rate": 18.0,
"description": "500ml bottle of Pepsi",
"is_service": false,
"is_active": true
}Response: Product object.
GET /inventory/products/:id
Get a single product by ID.
Auth: Required
Response: Product object with full details.
PATCH /inventory/products/:id
Update a product. All fields optional.
Auth: Required
Request Body: Same as POST /inventory/products but all fields are optional.
Response: Product object.
DELETE /inventory/products/:id
Delete a product.
Auth: Required
Response (204): No Content
GET /inventory/products/barcode/:code
Look up a product by barcode.
Auth: Required
Response: Product object.
POST /inventory/products/:id/adjust
Manually adjust stock level.
Auth: Required
Request Body:
{
"qty_change": -5,
"reason": "damaged",
"note": "5 units damaged during delivery"
}Response: Updated Product object.
GET /inventory/products/:id/adjustments
View stock adjustment audit trail.
Auth: Required
Query: limit (default: 50, max: 200)
Response: Array of StockAdjustment objects:
{
"id": "uuid",
"product_id": "uuid",
"qty_change": -5,
"reason": "damaged",
"note": "5 units damaged during delivery",
"adjusted_by": "user-uuid",
"created_at": "2024-01-15T10:30:00Z"
}GET /inventory/low-stock
List products at or below reorder point.
Auth: Required
Response: Array of Product objects with is_low_stock: true.
Product Input Schema
{
"name": "string (required)",
"category_id": "uuid (optional)",
"sku": "string (optional, unique within org)",
"barcode": "string (optional, unique within org)",
"cost_price": 0.0,
"selling_price": 0.0,
"stock": 0,
"reorder_point": 5,
"image": "string (URL, optional)",
"tax_rate": 18.0,
"description": "string (optional)",
"is_service": false,
"is_active": true
}