Products
Managing your product catalog — create, update, and sync products across branches
Products
Products are the foundation of your catalog. Each product has bilingual names, pricing, VAT configuration, and optional brand/category associations. When you create a product, Linkit generates a SKU for that product at every existing branch.
The Product Object
{
"id": "r1234567890abcdef",
"iv_id": "PROD-001",
"organization_id": "org_abc123",
"name_en": "Panadol Extra",
"name_ar": "بنادول إكسترا",
"average_price": 15.50,
"vat_value": 15,
"barcode": "6281001210016",
"brand_id": "brand_gsk",
"category_id": "cat_pharma",
"generic_id": "gen_paracetamol",
"is_enabled": true,
"is_deleted": false,
"created": "2024-01-15T10:30:00Z",
"updated": "2024-01-16T14:22:00Z"
}Fields
| Field | Type | Description |
|---|---|---|
id | string | Internal Linkit ID (auto-generated) |
iv_id | string | Your external identifier for this product |
name_en | string | Product name in English |
name_ar | string | Product name in Arabic |
average_price | number | Default price |
vat_value | number | VAT percentage (e.g., 15) |
barcode | string | Product barcode / EAN |
brand_id | string | Associated brand ID |
category_id | string | Associated category ID |
generic_id | string | Associated generic medicine ID |
is_enabled | boolean | Whether the product is active |
is_deleted | boolean | Soft-delete flag |
List Products
GET /api/v1/productsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number |
limit | integer | 20 | Items per page (max 100) |
search | string | - | Search in product names |
brand_id | string | - | Filter by brand |
category_id | string | - | Filter by category |
is_enabled | boolean | - | Filter by active status |
sort | string | -created | Sort field (prefix - for descending) |
Example Request
curl -X GET "https://linkit.works/api/v1/products?search=panadol&limit=25" \
-H "Authorization: Bearer your_token_here"const response = await fetch(
'https://linkit.works/api/v1/products?search=panadol&limit=25',
{
headers: {
'Authorization': 'Bearer your_token_here'
}
}
);
const products = await response.json();import requests
response = requests.get(
'https://linkit.works/api/v1/products',
params={'search': 'panadol', 'limit': 25},
headers={'Authorization': 'Bearer your_token_here'}
)
products = response.json()Response
{
"data": [
{
"id": "r1234567890abcdef",
"iv_id": "PROD-001",
"name_en": "Panadol Extra",
"name_ar": "بنادول إكسترا",
"average_price": 15.50,
"is_enabled": true,
"created": "2024-01-15T10:30:00Z"
}
],
"count": 25,
"total_count": 1234,
"page": 1,
"limit": 25,
"has_next": true,
"meta": {}
}Get Single Product
GET /api/v1/products/code/{ivId}Path Parameters
| Parameter | Type | Description |
|---|---|---|
ivId | string | Product's external ID (iv_id) |
Example
curl -X GET "https://linkit.works/api/v1/products/code/PROD-001" \
-H "Authorization: Bearer your_token_here"Returns the full product object.
Create Product
POST /api/v1/productsRequest Body
{
"iv_id": "PROD-NEW",
"name_en": "New Product",
"name_ar": "منتج جديد",
"average_price": 29.99,
"vat_value": 15,
"barcode": "1234567890123",
"brand_id": "brand_123",
"category_id": "cat_456",
"is_enabled": true
}Required Fields
| Field | Type | Constraints |
|---|---|---|
iv_id | string | Max 50 chars, unique per organization |
Optional Fields
| Field | Type | Constraints |
|---|---|---|
name_en | string | Max 255 chars |
name_ar | string | Max 255 chars |
average_price | number | >= 0 |
vat_value | number | 0–100 |
barcode | string | Max 50 chars |
brand_id | string | Must reference existing brand |
category_id | string | Must reference existing category |
is_enabled | boolean | Default: true |
When a product is created, Linkit automatically generates one SKU for each existing branch. The SKU's iv_id follows the pattern {product_iv_id}_{branch_iv_id}.
Response (201 Created)
{
"success": true,
"message": "Product created successfully",
"data": {
"id": "r1234567890abcdef",
"iv_id": "PROD-NEW"
},
"timestamp": "2024-01-15T10:30:00Z"
}Update Product
PUT /api/v1/products/code/{ivId}Full replacement — include all fields you want to keep.
Example
curl -X PUT "https://linkit.works/api/v1/products/code/PROD-001" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json" \
-d '{
"iv_id": "PROD-001",
"name_en": "Panadol Extra (Updated)",
"name_ar": "بنادول إكسترا",
"average_price": 16.50,
"vat_value": 15,
"is_enabled": true
}'Delete Product
DELETE /api/v1/products/code/{ivId}Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
force | boolean | false | Delete even if the product has associated SKUs |
Deletion behavior
By default, products with existing SKUs cannot be deleted. Use force=true to override — this removes the product and its associated SKUs.
Response (204 No Content)
Success returns no body.
Bulk Operations
Process up to 1,000 products in a single request.
POST /api/v1/products/bulkRequest Body
{
"mode": "upsert",
"products": [
{
"iv_id": "PROD-001",
"name_en": "Product One",
"average_price": 49.99,
"is_enabled": true
},
{
"iv_id": "PROD-002",
"name_en": "Product Two",
"average_price": 79.99,
"is_enabled": true
}
]
}Modes
| Mode | Behavior |
|---|---|
create | Insert only — fails if product exists |
update | Update only — fails if product not found |
upsert | Create or update as appropriate |
Response
{
"success": true,
"message": "Processed 100 products successfully",
"data": {
"succeeded": 98,
"failed": 2,
"errors": {
"PROD-050": "Invalid brand_id: brand_xyz does not exist",
"PROD-075": "Duplicate barcode: 1234567890123"
}
},
"timestamp": "2024-01-15T10:30:00Z"
}Error Responses
404 Not Found
{
"code": 404,
"error": "Product not found",
"details": { "iv_id": "NONEXISTENT" }
}409 Conflict
{
"code": 409,
"error": "Product with this iv_id already exists",
"details": { "iv_id": "PROD-001", "existing_id": "r1234567890" }
}422 Validation Error
{
"code": 422,
"error": "Validation failed",
"details": { "iv_id": "Required field" }
}