Master Product Management Guide
Overview
Master products are the top-level blueprints that define a product's identity and govern how variants are created beneath it. Every sellable product in SynthesQ Operations belongs to a master product - whether it is a standalone item with no variants or one of many size-and-colour combinations generated automatically from attribute definitions. The master product holds the base pricing, physical dimensions, category assignment, supplier linkage, and media assets that child variants inherit unless explicitly overridden.
The master product acts as the aggregate root for the product family. All variant creation, deletion, and bulk pricing changes flow through it, ensuring invariants such as duplicate-combination prevention and active-inventory checks are enforced at the domain boundary. Clients never write directly to a variant product; they instruct the master product through the API endpoints documented here.
Product Configuration Strategies
A master product can be configured in one of three ways, determined by whether variant_attributes is provided and how variants are subsequently created:
| Strategy | variant_attributes | How Variants Are Created | Typical Use Case |
|---|---|---|---|
| Single Product | null (omitted) | One product created manually at the product level | A unique item with no sizing or colour options |
| Predefined Variants | Provided on creation | Created one at a time via POST /variants with an explicit variant_selection | A clothing line where only selected size-colour pairs are stocked |
| Generated Variants | Provided on creation | All combinations auto-generated via POST /variants/generate | Electronics with well-defined attribute matrices (storage × colour) |
Variant Configuration is Immutable While Variants Exist
Once variants exist, changing variant_attributes requires passing regenerate_variants: true on the update request, which deletes all current variants before re-generating. Variants with active inventory records cannot be deleted.
Master Product Fields
| Field | Type | Description | Required |
|---|---|---|---|
name | string (max 255) | Human-readable product name | Yes |
slug | string | URL-safe identifier; auto-generated from name if omitted | No |
description | string | Long-form product description | No |
short_description | string | Brief summary for catalog listings | No |
category_id | ULID string | Product category identifier | No |
supplier_id | ULID string | Supplier identifier | No |
brand | string | Brand name | No |
model | string | Model or part number | No |
base_price | float | Default selling price inherited by variants (in currency) | No |
base_cost_price | float | Default cost price inherited by variants | No |
currency | string (ISO 4217) | 3-letter currency code (e.g., USD, EUR); defaults to USD | No |
base_weight | float | Default weight in kg inherited by variants | No |
base_dimensions | object | Default dimensions {length, width, height, unit} - unit: cm, in, m, mm | No |
variant_attributes | object | Variant configuration with attributes array; each entry has name and values | No |
images | array | Array of image URLs or identifiers | No |
tags | array | String tags for categorization and filtering | No |
status | string | One of: draft, active, inactive, archived; defaults to draft | No |
is_visible | boolean | Whether visible in storefront; defaults to false | No |
is_featured | boolean | Whether to surface in featured collections; defaults to false | No |
sort_order | integer | Manual ordering weight; defaults to 0 | No |
requires_shipping | boolean | Whether physical shipment is required; defaults to true | No |
is_taxable | boolean | Whether tax applies; defaults to true | No |
tax_class | string | Tax class identifier | No |
meta_title | string | SEO page title | No |
meta_description | string | SEO meta description | No |
meta_keywords | string | SEO keywords | No |
API Endpoints
All endpoints are under the authenticated prefix /api/v1/operations and require a valid Bearer token.
List Master Products
Endpoint: GET /api/v1/operations/master-products
Authentication: Required (Bearer token)
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search | string | Full-text search across name and slug |
status | string | Filter by status (draft, active, inactive, archived) |
category_id | ULID string | Filter by category |
supplier_id | ULID string | Filter by supplier |
brand | string | Filter by brand name |
has_variants | boolean | Filter to only masters with (true) or without (false) variant configuration |
is_visible | boolean | Filter by storefront visibility |
is_featured | boolean | Filter to featured products only |
min_price | float | Minimum base price |
max_price | float | Maximum base price |
tags | array | Filter by tags (any match) |
sort_by | string | Sort field: name, base_price, status, created_at, sort_order (default: created_at) |
sort_direction | string | asc or desc (default: desc) |
page | integer | Page number (default: 1) |
per_page | integer | Results per page, max 100 (default: 15) |
Example Request:
GET /api/v1/operations/master-products?status=active&has_variants=true&sort_by=name&sort_direction=asc&per_page=25Response (200 OK):
{
"success": true,
"message": "Master products retrieved successfully",
"data": [
{
"id": "01hwxyz123abc456def789ghi0",
"name": "Premium Running Shoe",
"slug": "premium-running-shoe",
"short_description": "Lightweight trail shoe with adaptive cushioning",
"status": "active",
"is_visible": true,
"is_featured": false,
"base_price": 129.99,
"base_cost_price": 54.00,
"currency": "USD",
"base_weight": 0.32,
"variant_attributes": {
"attributes": [
{ "name": "Size", "values": ["US7", "US8", "US9", "US10", "US11"] },
{ "name": "Color", "values": ["Midnight Black", "Arctic White"] }
]
},
"category_id": "01hwcat000aaa111bbb222ccc3",
"supplier_id": "01hwsup000aaa111bbb222ddd4",
"created_at": "2026-01-15T09:00:00+00:00",
"updated_at": "2026-02-10T14:30:00+00:00"
}
],
"meta": {
"pagination": {
"current_page": 1,
"per_page": 25,
"total": 48,
"last_page": 2
}
}
}Create Master Product
Endpoint: POST /api/v1/operations/master-products
Authentication: Required (Bearer token)
Request Body - Single Product (no variants):
{
"name": "Industrial Safety Helmet",
"short_description": "EN397-certified hard hat for industrial environments",
"category_id": "01hwcat000aaa111bbb222ccc3",
"supplier_id": "01hwsup000aaa111bbb222ddd4",
"brand": "SteelGuard",
"model": "SG-H400",
"base_price": 34.99,
"base_cost_price": 12.50,
"currency": "USD",
"base_weight": 0.42,
"status": "active",
"is_visible": true,
"is_taxable": true,
"requires_shipping": true,
"tags": ["ppe", "safety", "head-protection"]
}Request Body - With Variant Configuration:
{
"name": "Premium Running Shoe",
"short_description": "Lightweight trail shoe with adaptive cushioning",
"category_id": "01hwcat000aaa111bbb222ccc3",
"supplier_id": "01hwsup000aaa111bbb222ddd4",
"brand": "SwiftStep",
"base_price": 129.99,
"base_cost_price": 54.00,
"currency": "USD",
"base_weight": 0.32,
"base_dimensions": {
"length": 32.0,
"width": 12.0,
"height": 11.0,
"unit": "cm"
},
"variant_attributes": {
"attributes": [
{
"name": "Size",
"values": ["US7", "US8", "US9", "US10", "US11"]
},
{
"name": "Color",
"values": ["Midnight Black", "Arctic White"]
}
]
},
"status": "draft",
"is_visible": false,
"tags": ["running", "trail", "footwear"]
}Response (201 Created):
{
"success": true,
"message": "Master product created successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"name": "Premium Running Shoe",
"slug": "premium-running-shoe",
"short_description": "Lightweight trail shoe with adaptive cushioning",
"description": null,
"status": "draft",
"is_visible": false,
"is_featured": false,
"base_price": 129.99,
"base_cost_price": 54.00,
"currency": "USD",
"base_weight": 0.32,
"variant_attributes": {
"attributes": [
{ "name": "Size", "values": ["US7", "US8", "US9", "US10", "US11"] },
{ "name": "Color", "values": ["Midnight Black", "Arctic White"] }
]
},
"category_id": "01hwcat000aaa111bbb222ccc3",
"category": {
"id": "01hwcat000aaa111bbb222ccc3",
"name": "Footwear"
},
"supplier_id": "01hwsup000aaa111bbb222ddd4",
"supplier": {
"id": "01hwsup000aaa111bbb222ddd4",
"name": "SwiftStep Manufacturing"
},
"created_at": "2026-03-11T08:00:00+00:00",
"updated_at": "2026-03-11T08:00:00+00:00"
},
"meta": {}
}Error Response (422 Unprocessable Entity):
{
"success": false,
"message": "Validation failed",
"errors": {
"name": ["The name field is required."],
"currency": ["Currency must be a valid 3-letter ISO code (e.g., USD, EUR)"]
}
}Get Master Product
Endpoint: GET /api/v1/operations/master-products/{id}
Authentication: Required (Bearer token)
Query Parameters:
include(string, optional) - Comma-separated relationships to eager-load:variants,category,supplier
Example:
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0?include=variants,category,supplierResponse (200 OK):
{
"success": true,
"message": "Master product retrieved successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"name": "Premium Running Shoe",
"slug": "premium-running-shoe",
"description": "A high-performance trail shoe engineered for technical terrain and long distances.",
"short_description": "Lightweight trail shoe with adaptive cushioning",
"status": "active",
"is_visible": true,
"is_featured": false,
"base_price": 129.99,
"base_cost_price": 54.00,
"currency": "USD",
"base_weight": 0.32,
"variant_attributes": {
"attributes": [
{ "name": "Size", "values": ["US7", "US8", "US9", "US10", "US11"] },
{ "name": "Color", "values": ["Midnight Black", "Arctic White"] }
]
},
"category_id": "01hwcat000aaa111bbb222ccc3",
"category": {
"id": "01hwcat000aaa111bbb222ccc3",
"name": "Footwear"
},
"supplier_id": "01hwsup000aaa111bbb222ddd4",
"supplier": {
"id": "01hwsup000aaa111bbb222ddd4",
"name": "SwiftStep Manufacturing"
},
"products_count": 10,
"created_at": "2026-01-15T09:00:00+00:00",
"updated_at": "2026-02-10T14:30:00+00:00"
},
"meta": {}
}Update Master Product
Endpoint: PUT /api/v1/operations/master-products/{id}
Authentication: Required (Bearer token)
Partial updates are supported - only the fields provided will be changed. To change variant_attributes while variants already exist, include "regenerate_variants": true, which deletes all existing variants and re-generates them from the new configuration.
Request Body:
{
"status": "active",
"is_visible": true,
"base_price": 119.99,
"meta_title": "Premium Trail Running Shoes | SwiftStep",
"meta_description": "Shop the SwiftStep Premium Running Shoe. Lightweight, durable, built for trail."
}Response (200 OK):
{
"success": true,
"message": "Master product updated successfully",
"data": {
"id": "01hwxyz123abc456def789ghi0",
"name": "Premium Running Shoe",
"slug": "premium-running-shoe",
"status": "active",
"is_visible": true,
"base_price": 119.99,
"currency": "USD",
"updated_at": "2026-03-11T10:45:00+00:00"
},
"meta": {}
}Delete Master Product
Endpoint: DELETE /api/v1/operations/master-products/{id}
Authentication: Required (Bearer token)
Soft-deletes the master product record. The master cannot be deleted while active variants with inventory records exist; delete all variants first.
Response (200 OK):
{
"success": true,
"message": "Master product deleted successfully",
"data": null,
"meta": {}
}Soft Delete
Deletion is a soft delete - the record is retained in the database and can be restored by support. Consider setting status to archived instead to de-list a product while preserving all data.
Generate All Variant Combinations
Endpoint: POST /api/v1/operations/master-products/{id}/variants/generate
Authentication: Required (Bearer token)
Automatically creates every possible attribute combination from the master's variant_attributes. Combinations that already exist are skipped; only new ones are created.
Request Body:
{
"auto_generate_sku": true,
"sku_prefix": "PRR",
"initial_stock": 0
}| Field | Type | Description | Default |
|---|---|---|---|
auto_generate_sku | boolean | Generate SKUs from master slug + attribute values | true |
sku_prefix | string | Optional prefix prepended to generated SKUs | "" |
initial_stock | integer | Starting stock quantity per variant | 0 |
Response (201 Created):
{
"success": true,
"message": "Generated 10 variant(s) successfully",
"data": [
{
"id": "01hwvar111aaa222bbb333ccc4",
"name": "Premium Running Shoe - US7 / Midnight Black",
"sku": "PREMIUM-RUN-US7-MIDNIGHT-BLACK",
"status": "draft",
"variant_selection": {
"Size": "US7",
"Color": "Midnight Black"
},
"selling_price": 129.99,
"currency": "USD"
},
{
"id": "01hwvar111aaa222bbb333ccc5",
"name": "Premium Running Shoe - US7 / Arctic White",
"sku": "PREMIUM-RUN-US7-ARCTIC-WHITE",
"status": "draft",
"variant_selection": {
"Size": "US7",
"Color": "Arctic White"
},
"selling_price": 129.99,
"currency": "USD"
}
],
"meta": {
"total_generated": 10
}
}Idempotent Generation
Re-running generate is safe. The system compares variant_selection combinations against existing variants and only creates the missing ones.
Create a Single Variant
Endpoint: POST /api/v1/operations/master-products/{id}/variants
Authentication: Required (Bearer token)
Creates one variant product with a specific attribute combination. Use this when you want to add a variant selectively rather than generating all possible combinations.
Request Body:
{
"variant_selection": {
"Size": "US10",
"Color": "Arctic White"
},
"selling_price": 124.99,
"sku": "PRR-US10-ARCTIC-WHITE"
}Response (201 Created):
{
"success": true,
"message": "Variant created successfully",
"data": {
"id": "01hwvar222bbb333ccc444ddd5",
"name": "Premium Running Shoe - US10 / Arctic White",
"sku": "PRR-US10-ARCTIC-WHITE",
"status": "draft",
"variant_selection": {
"Size": "US10",
"Color": "Arctic White"
},
"selling_price": 124.99,
"currency": "USD",
"master_product_id": "01hwxyz123abc456def789ghi0"
},
"meta": {}
}List Variants
Endpoint: GET /api/v1/operations/master-products/{id}/variants
Authentication: Required (Bearer token)
Returns all variant products belonging to this master product, ordered by SKU.
Response (200 OK):
{
"success": true,
"message": "Variants retrieved successfully",
"data": [
{
"id": "01hwvar111aaa222bbb333ccc4",
"name": "Premium Running Shoe - US7 / Midnight Black",
"sku": "PREMIUM-RUN-US7-MIDNIGHT-BLACK",
"status": "active",
"variant_selection": { "Size": "US7", "Color": "Midnight Black" },
"selling_price": 129.99,
"currency": "USD",
"stock_quantity": 24
},
{
"id": "01hwvar111aaa222bbb333ccc5",
"name": "Premium Running Shoe - US7 / Arctic White",
"sku": "PREMIUM-RUN-US7-ARCTIC-WHITE",
"status": "active",
"variant_selection": { "Size": "US7", "Color": "Arctic White" },
"selling_price": 129.99,
"currency": "USD",
"stock_quantity": 18
}
],
"meta": {}
}Get Available Variant Values
Endpoint: GET /api/v1/operations/master-products/{id}/variants/available
Authentication: Required (Bearer token)
Returns, per attribute, which values are already used by existing variants and which values are still available (i.e., no variant exists for that value yet across any combination).
Response (200 OK):
{
"success": true,
"message": "Available variant values retrieved successfully",
"data": {
"Size": {
"used_values": ["US7", "US8", "US9"],
"available_values": ["US10", "US11"]
},
"Color": {
"used_values": ["Midnight Black", "Arctic White"],
"available_values": []
}
},
"meta": {}
}Bulk Update Variant Prices
Endpoint: POST /api/v1/operations/master-products/{id}/variants/bulk-update-prices
Authentication: Required (Bearer token)
Sets the selling price for every variant under this master product. Pass null to clear individual price overrides and cause all variants to fall back to the master's base_price.
Request Body:
{
"price": 114.99
}Response (200 OK):
{
"success": true,
"message": "Updated price to 114.99 for 10 variant(s)",
"data": null,
"meta": {
"updated_count": 10,
"price": 114.99
}
}Bulk Update Variant Stock
Endpoint: POST /api/v1/operations/master-products/{id}/variants/bulk-update-stock
Authentication: Required (Bearer token)
Sets the stock_quantity for every variant under this master product to the specified value.
Request Body:
{
"quantity": 50
}Response (200 OK):
{
"success": true,
"message": "Updated stock to 50 for 10 variant(s)",
"data": null,
"meta": {
"updated_count": 10,
"quantity": 50
}
}Delete All Variants
Endpoint: DELETE /api/v1/operations/master-products/{id}/variants
Authentication: Required (Bearer token)
Soft-deletes all variant products under this master. Variants with active inventory records are blocked - the domain will return a 422 error listing the count of blocking variants.
Response (200 OK):
{
"success": true,
"message": "Deleted 10 variant(s) successfully",
"data": null,
"meta": {
"deleted_count": 10
}
}Business Scenarios
Scenario 1: Launching a New Apparel Product with Auto-Generated Variants
Context: A merchandise team needs to list a new branded hoodie in five sizes and three colours - 15 SKUs total - for a product launch in two weeks.
Workflow:
- Create the master product in
draftstatus withvariant_attributesdefined - Generate all 15 variant combinations automatically
- Review the variant list and adjust prices for premium sizes if needed
- Update master status to
activeand setis_visibletotrueto publish
API Calls:
# 1. Create master product with variant configuration
POST /api/v1/operations/master-products
{
"name": "Origin Pullover Hoodie",
"category_id": "01hwcat000aaa111bbb222ccc3",
"supplier_id": "01hwsup000aaa111bbb222ddd4",
"brand": "Origin Apparel",
"base_price": 79.99,
"base_cost_price": 28.00,
"currency": "USD",
"base_weight": 0.55,
"variant_attributes": {
"attributes": [
{ "name": "Size", "values": ["XS", "S", "M", "L", "XL"] },
{ "name": "Color", "values": ["Slate Grey", "Navy Blue", "Forest Green"] }
]
},
"status": "draft",
"is_visible": false
}
# 2. Generate all 15 variants
POST /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants/generate
{
"auto_generate_sku": true,
"sku_prefix": "OPH",
"initial_stock": 0
}
# 3. Optional: raise price for XL variants individually
POST /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants
{
"variant_selection": { "Size": "XL", "Color": "Slate Grey" },
"selling_price": 84.99
}
# 4. Publish when ready
PUT /api/v1/operations/master-products/01hwxyz123abc456def789ghi0
{
"status": "active",
"is_visible": true
}Scenario 2: Receiving Initial Stock After a Purchase Order
Context: A purchase order has been received and the warehouse team needs to set opening stock levels across all variants of the hoodie launched in Scenario 1.
Workflow:
- Verify the master product and confirm all 15 variants exist
- Set uniform opening stock across all variants in one call
- Spot-check the variant list to confirm quantities
API Calls:
# 1. Confirm all variants exist
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants
# 2. Set opening stock of 30 per variant (450 units total)
POST /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants/bulk-update-stock
{
"quantity": 30
}
# 3. Verify
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variantsScenario 3: Running a Promotional Discount Across a Product Family
Context: The marketing team wants to mark down all variants of the Premium Running Shoe by 10% for a 48-hour flash sale, then restore original pricing.
Workflow:
- Retrieve the current base price from the master product
- Apply the promotional price to all variants via bulk update
- After 48 hours, clear variant price overrides so they fall back to the master base price
API Calls:
# 1. Check current master pricing
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0
# 2. Apply flash-sale price (10% off $129.99 = $116.99)
POST /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants/bulk-update-prices
{
"price": 116.99
}
# 3. After 48 hours: clear overrides (variants revert to base_price)
POST /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants/bulk-update-prices
{
"price": null
}Scenario 4: Discontinuing a Product Colour and Adding a New One
Context: "Arctic White" is being discontinued; "Coral Pink" is being added for the next season. Not all combinations for the new colour exist yet.
Workflow:
- Check which "Arctic White" variants still have available inventory
- Zero out stock for the outgoing colour before deletion
- Delete only the Arctic White variants - since these are managed individually, delete each via the Product endpoint rather than the bulk delete (which would remove all variants)
- Check which "Coral Pink" size combinations are still missing using the available-values endpoint
- Create the missing size-colour variants
API Calls:
# 1. Review existing Arctic White variants and their stock
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants
# 2. Zero stock for outgoing variants via inventory adjustment (see Inventory guide)
POST /api/v1/operations/inventory/adjust-stock
{
"product_id": "01hwvar111aaa222bbb333ccc5",
"warehouse_id": "01hwwhs000aaa111bbb222eee6",
"quantity": 0,
"reason": "Colour discontinued"
}
# 3. Delete outgoing variants individually via Product endpoint
DELETE /api/v1/operations/products/01hwvar111aaa222bbb333ccc5
# 4. Check which Coral Pink size combinations are missing
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants/available
# 5. Create each missing Coral Pink variant
POST /api/v1/operations/master-products/01hwxyz123abc456def789ghi0/variants
{
"variant_selection": { "Size": "US8", "Color": "Coral Pink" },
"sku": "PRR-US8-CORAL-PINK",
"selling_price": 129.99
}Targeted Variant Deletion
The DELETE /variants endpoint (plural, no ID) removes all variants. When discontinuing a single colour or size, delete individual variant products via DELETE /api/v1/operations/products/{id} instead to avoid touching unrelated variants.
Best Practices
1. Start in Draft, Publish When Ready
Always create master products in status: "draft" with is_visible: false. This prevents partial product data from surfacing in storefronts. Transition to active and flip is_visible to true only after all variants are created, priced, and stocked.
2. Define Variant Attributes Before Creating Products
variant_attributes should be fully defined at master product creation time. Changing the attribute matrix after variants exist requires deleting and regenerating all variants, which is disruptive to any downstream inventory records. Take time to confirm the full attribute set (sizes, colours, storage tiers, etc.) with merchandising before creation.
3. Use Bulk Operations for Initial Stock and Price Resets
bulk-update-stock and bulk-update-prices are designed for initial setup and uniform changes such as promotions or cost-of-goods adjustments. For day-to-day stock movements driven by purchases or sales, use the Inventory module's adjust-stock endpoint, which creates an immutable audit trail via StockMovements.
4. Leverage the Available Values Endpoint Before Manual Variant Creation
Before calling POST /variants manually, check GET /variants/available to see which attribute value combinations have not yet been created. This prevents duplicate-combination errors and gives a clear picture of which SKUs remain to be set up.
5. Keep Slug and Name Consistent
The slug is auto-generated from name at creation and enforced to be unique. If you later rename a master product, the slug will be updated automatically. Avoid providing custom slugs unless you have a specific URL scheme requirement - auto-generation is idempotent and collision-safe.
6. Use Tags for Cross-Cutting Catalog Features
Tags support filtering in the list endpoint and are the recommended way to build dynamic collections (e.g., "new-arrivals", "on-sale", "clearance") without hard-coding category assignments. Apply tags consistently across related master products so consumers can build accurate filtered queries.
Integration Points
With Product (Variants)
Each Product record created through this API is a variant that belongs to the master product. The product inherits base_price, base_cost_price, base_weight, base_dimensions, category_id, supplier_id, and brand from the master unless explicitly overridden at the variant level. Refer to the Product Management Guide for individual variant lifecycle operations (activate, deactivate, discontinue, attribute management).
With Inventory
Stock levels live on Inventory records that are linked to individual Product (variant) records, not to the master product directly. The master's getTotalStock() aggregate sums inventory across all its variants. After generating variants, use the Inventory Guide to set up per-warehouse stock, configure reorder thresholds, and track stock movements.
With Product Categories
Master products are assigned to a single ProductCategory. Categories are hierarchical (nested tree). Use the Category Management Guide to browse the category tree and find the correct category_id before creating a master product.
With Suppliers
The supplier_id on the master product links to the entity responsible for sourcing the product. Supplier data (lead times, performance ratings, contact information) is managed through the Supplier Management Guide. Variants inherit the supplier from the master unless overridden.
Troubleshooting
Cannot Generate Variants - "Master product does not have variant configuration"
Error: { "errors": { "variants": ["Cannot generate variants for master product without variant configuration"] } }
Cause: The master product was created without a variant_attributes definition, meaning it is configured as a Single Product.
Solution: Update the master product to add variant_attributes first. If no variants exist yet this is a straightforward update:
PUT /api/v1/operations/master-products/{id}
{
"variant_attributes": {
"attributes": [
{ "name": "Size", "values": ["S", "M", "L", "XL"] },
{ "name": "Color", "values": ["Black", "White"] }
]
}
}Cannot Delete Variants - "Cannot delete variants with active inventory"
Error: { "errors": { "variants": ["Cannot delete variants with active inventory. Found 3 variants with inventory."] } }
Cause: One or more variants have inventory records in the system. The domain blocks deletion to protect stock audit integrity.
Solution:
- Identify the variants with inventory:
GET /api/v1/operations/master-products/{id}/variants - Zero out or transfer their stock via the Inventory module:
POST /api/v1/operations/inventory/adjust-stock - Re-attempt the delete once all inventory counts are zero
Variant Creation Fails - "A variant with this combination already exists"
Error: { "errors": { "variant": ["A variant with this combination already exists"] } }
Cause: A variant with the exact same variant_selection (attribute name → value map) already exists on the master product.
Solution: Use GET /api/v1/operations/master-products/{id}/variants/available to see which combinations are still available before attempting to create a variant manually. If you believe the variant was accidentally deleted, check soft-deleted records or contact support to restore it.