Skip to content

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:

Strategyvariant_attributesHow Variants Are CreatedTypical Use Case
Single Productnull (omitted)One product created manually at the product levelA unique item with no sizing or colour options
Predefined VariantsProvided on creationCreated one at a time via POST /variants with an explicit variant_selectionA clothing line where only selected size-colour pairs are stocked
Generated VariantsProvided on creationAll combinations auto-generated via POST /variants/generateElectronics 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

FieldTypeDescriptionRequired
namestring (max 255)Human-readable product nameYes
slugstringURL-safe identifier; auto-generated from name if omittedNo
descriptionstringLong-form product descriptionNo
short_descriptionstringBrief summary for catalog listingsNo
category_idULID stringProduct category identifierNo
supplier_idULID stringSupplier identifierNo
brandstringBrand nameNo
modelstringModel or part numberNo
base_pricefloatDefault selling price inherited by variants (in currency)No
base_cost_pricefloatDefault cost price inherited by variantsNo
currencystring (ISO 4217)3-letter currency code (e.g., USD, EUR); defaults to USDNo
base_weightfloatDefault weight in kg inherited by variantsNo
base_dimensionsobjectDefault dimensions {length, width, height, unit} - unit: cm, in, m, mmNo
variant_attributesobjectVariant configuration with attributes array; each entry has name and valuesNo
imagesarrayArray of image URLs or identifiersNo
tagsarrayString tags for categorization and filteringNo
statusstringOne of: draft, active, inactive, archived; defaults to draftNo
is_visiblebooleanWhether visible in storefront; defaults to falseNo
is_featuredbooleanWhether to surface in featured collections; defaults to falseNo
sort_orderintegerManual ordering weight; defaults to 0No
requires_shippingbooleanWhether physical shipment is required; defaults to trueNo
is_taxablebooleanWhether tax applies; defaults to trueNo
tax_classstringTax class identifierNo
meta_titlestringSEO page titleNo
meta_descriptionstringSEO meta descriptionNo
meta_keywordsstringSEO keywordsNo

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:

ParameterTypeDescription
searchstringFull-text search across name and slug
statusstringFilter by status (draft, active, inactive, archived)
category_idULID stringFilter by category
supplier_idULID stringFilter by supplier
brandstringFilter by brand name
has_variantsbooleanFilter to only masters with (true) or without (false) variant configuration
is_visiblebooleanFilter by storefront visibility
is_featuredbooleanFilter to featured products only
min_pricefloatMinimum base price
max_pricefloatMaximum base price
tagsarrayFilter by tags (any match)
sort_bystringSort field: name, base_price, status, created_at, sort_order (default: created_at)
sort_directionstringasc or desc (default: desc)
pageintegerPage number (default: 1)
per_pageintegerResults per page, max 100 (default: 15)

Example Request:

bash
GET /api/v1/operations/master-products?status=active&has_variants=true&sort_by=name&sort_direction=asc&per_page=25

Response (200 OK):

json
{
  "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):

json
{
  "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:

json
{
  "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):

json
{
  "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):

json
{
  "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:

bash
GET /api/v1/operations/master-products/01hwxyz123abc456def789ghi0?include=variants,category,supplier

Response (200 OK):

json
{
  "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:

json
{
  "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):

json
{
  "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):

json
{
  "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:

json
{
  "auto_generate_sku": true,
  "sku_prefix": "PRR",
  "initial_stock": 0
}
FieldTypeDescriptionDefault
auto_generate_skubooleanGenerate SKUs from master slug + attribute valuestrue
sku_prefixstringOptional prefix prepended to generated SKUs""
initial_stockintegerStarting stock quantity per variant0

Response (201 Created):

json
{
  "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:

json
{
  "variant_selection": {
    "Size": "US10",
    "Color": "Arctic White"
  },
  "selling_price": 124.99,
  "sku": "PRR-US10-ARCTIC-WHITE"
}

Response (201 Created):

json
{
  "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):

json
{
  "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):

json
{
  "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:

json
{
  "price": 114.99
}

Response (200 OK):

json
{
  "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:

json
{
  "quantity": 50
}

Response (200 OK):

json
{
  "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):

json
{
  "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:

  1. Create the master product in draft status with variant_attributes defined
  2. Generate all 15 variant combinations automatically
  3. Review the variant list and adjust prices for premium sizes if needed
  4. Update master status to active and set is_visible to true to publish

API Calls:

bash
# 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:

  1. Verify the master product and confirm all 15 variants exist
  2. Set uniform opening stock across all variants in one call
  3. Spot-check the variant list to confirm quantities

API Calls:

bash
# 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/variants

Scenario 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:

  1. Retrieve the current base price from the master product
  2. Apply the promotional price to all variants via bulk update
  3. After 48 hours, clear variant price overrides so they fall back to the master base price

API Calls:

bash
# 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:

  1. Check which "Arctic White" variants still have available inventory
  2. Zero out stock for the outgoing colour before deletion
  3. 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)
  4. Check which "Coral Pink" size combinations are still missing using the available-values endpoint
  5. Create the missing size-colour variants

API Calls:

bash
# 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:

bash
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:

  1. Identify the variants with inventory: GET /api/v1/operations/master-products/{id}/variants
  2. Zero out or transfer their stock via the Inventory module: POST /api/v1/operations/inventory/adjust-stock
  3. 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.

Documentation for SynthesQ CRM/ERP Platform