Products Service
Overview
Products represent sellable items in the Catalog module. They aggregate core product data together with pricing, stock and dynamic properties.
The Products service is a central integration point between:
- Catalog
- Inventory
- Pricing
- Sales
All product operations are tenant-aware and scoped to the current tenant.
Endpoints
GET
/api/v1/Products
Returns a paginated, filterable list of products for the current tenant.
Query parameters:
page- page number (1-based, default: 1)pageSize- items per page (default: 20, max: 100)sortBy- field to sort by:sku,title,createdAt,brand,pricesortDesc- sort descending (default: false)search- search across SKU, title, descriptionisActive- filter by active status (true/false/null for all)brandId- filter by brand IDcategoryId/categorySlug- filter by categorysupplierId- filter by suppliercolourId/sizeId- filter by colour/size variantminPrice/maxPrice- price range filterpriceListId- price list used for price filteringinStock- only products with stock (true/false)
Behavior:
- Returns paginated
PagedResponse<ProductModel>including per product:brand— full brand object{ Id, Name, Code }(no separate brand request needed)unitPrice— product-level base pricestock— product-level stock listproductVariants— each variant includes its ownunitPriceandstock(perProductVariantId)- product properties, images, SEO, dimension types
- Uses batch loading to avoid N+1 query issues
Errors:
- Returns
404if no products exist
Authorization:
[AllowAnonymous]— no token required
GET
/api/v1/Products/sku/{sku}
Returns a single product identified by its SKU.
Behavior:
- Looks up product by
SKU - Loads related stock and properties
- Returns
404if product does not exist
Authorization:
- Requires Bearer Token
POST
/api/v1/Products
Creates one or more new products.
Request body:
- Array of
UploadProductModel
Behavior:
- Supports bulk product creation
- Each product is validated individually
- Duplicate SKUs are skipped
- Brands are resolved by name:
- Existing brands are reused
- Missing brands are created automatically
- Empty brand defaults to "Unknown brand"
- Creates:
- Product record
- Initial price
- Initial stock (if provided)
- Product properties (if provided)
- All operations are executed in a single transaction
- Successful creation writes audit log entries
Errors:
- Returns
400if no valid products are provided
Authorization:
- Requires Bearer Token
POST
/api/v1/Products/import
Imports products from a CSV file.
Request:
multipart/form-data- CSV file upload
Behavior:
- Validates CSV structure and content
- Supports large files via batch processing (
1000) - Automatically splits records into:
- new products
- existing products (updates)
- Performs:
- product creation
- product updates
- pricing updates
- stock updates
- property updates
- Partial failures are logged
- Import completes even if some rows are invalid
Errors:
- Returns
400if import - - CSV parsing errors are logged with row number
Authorization:
- Requires Bearer Token
PUT
/api/v1/Products/{id}
Updates an existing product.
Request:
- Product ID is taken from the route
- Request body is a list of
UploadProductModel(single-item list is expected for ID-based update)
Behavior:
- Updates product core fields:
- name
- description
- summary
- tax code
- active flag
- Updates pricing if
UnitPriceis provided - Updates or creates stock entries per warehouse
- Updates or creates product properties
- Changes are applied selectively (field-by-field comparison)
- All updates run inside a transaction
- Audit logs are written only if changes occur
Errors:
- Returns
400if update - or product does not exist
Authorization:
- Requires Bearer Token
DELETE
/api/v1/Products/{id}
Deletes a product by its identifier.
Behavior:
- Performs a hard delete
- Removes:
- product
- stock items
- product prices
- product property values
- Successful deletion writes an audit log entry
Errors:
- Returns
400if product does not exist or deletion -
Authorization:
- Requires Bearer Token
Notes
- Validation is enforced in the service layer
- Product updates are transactional
- Bulk operations are optimized for large datasets
- Batch size:
1000 - Large dataset threshold:
1000 - All state-changing operations are audited
- Internal errors are logged and not exposed to clients