Products and bundles
Items used on invoice lines, with VAT category, unit and price.
Products (and services) are the items the invoice editor and the API can put on lines. Referencing an item by itemId on an invoice line keeps reporting per product consistent; the line still carries its own description, price and VAT values.
Fields
| Field | Notes |
|---|---|
name, nameAr, description | Names; the Arabic name is used on bilingual PDFs |
type | product (default) or service |
sku, barcode | Your codes; GET /products/valid-code?sku= checks that a SKU is free, POST returns 409 on a duplicate |
unitCode | UN/ECE Rec 20 (EA, HUR, KGM, …), default EA |
unitPrice, currency | Net price, default currency AED |
taxCategory, taxRate | standard (5 %), zero_rated, exempt, reverse_charge; the rate defaults from the category |
hsnCode | HS code (commodity classification, BT-158) |
itemNumber | Your item number; the item number series allocates them in the app |
gln | GS1 GLN / GTIN, 8–14 digits |
costPrice | Purchase price; the response adds margin in percent of the net price |
trackInventory, inventoryCount, lowStockThreshold | Stock is reduced by the invoiced quantity when an invoice leaves draft (not for test documents or credit notes) |
category | Free-text group |
isActive | Inactive items stay on old invoices but are hidden from pickers |
Routes
curl "$BASE/products?keyword=consulting&sort=unitPrice&order=desc" -H "X-API-KEY: $KEY"
curl -X POST "$BASE/products" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{ "name": "Consulting hour", "type": "service", "sku": "CONS-H", "unitCode": "HUR", "unitPrice": 500 }'
curl -X POST "$BASE/products/import" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" -d '{ "products": [ … ] }'
DELETE /products/{id} deactivates items that are used on invoice lines instead of deleting them.
Price lists
A price list holds net prices per item with optional quantity breaks, a validity window, and either isDefault: true (applies to every customer without an assignment) or a list of customerIds. A customer can also carry defaultPriceListId.
curl -X POST "$BASE/price-lists" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" -d '{
"name": "Wholesale 2027", "validFrom": "2027-01-01", "validTo": "2027-12-31",
"items": [{ "itemId": "…", "unitPrice": 90 }, { "itemId": "…", "unitPrice": 80, "minQuantity": 10 }],
"customerIds": ["…"]
}'
curl "$BASE/products/{id}/price?customerId=…&quantity=12&date=2027-03-01" -H "X-API-KEY: $KEY"
GET /products/{id}/price resolves the price the editor would use: customer-assigned lists (highest priority first), then default lists, then the item's own price; within a list the row with the largest minQuantity that fits wins. The response names the source and the list. PUT /price-lists/{id}/items and PUT /price-lists/{id}/customers replace the prices or the assignment in one call.
Invoice inputs still take an explicit unitPrice per line; price lists are a lookup for your integration (and for the editor), not a server-side override.
Bundles
A bundle is a set of items with quantities. isSplittable: true (default) means the bundle is invoiced as one line per component, each priced through the price lists; otherwise it is one line at the bundle price (priceMode: "sum" of components or "fixed" with fixedPrice, plus the bundle's own VAT category).
curl -X POST "$BASE/bundles" -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{ "name": "Starter kit", "items": [{ "itemId": "…", "quantity": 3 }, { "itemId": "…", "quantity": 1 }] }'
curl "$BASE/bundles/{id}/lines?quantity=2&customerId=…" -H "X-API-KEY: $KEY"
GET /bundles/{id}/lines returns ready-made items[] for POST /invoices. MCP: expand_bundle, get_product_price, create_price_list, create_bundle.