Themes built on the Twig templating engine are now deprecated and require migration to Vitrin to ensure continued support and compatibility with Zid.
product_class.| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer JWT for scope-based authentication. |
X-Manager-Token | Yes | Encrypted manager token. |
Store-Id | Yes | Store UUID. |
Role | Yes | Must be set to Manager. |
Content-Type | Yes | Must be application/json. |
| Product Type | product_class Value | Use Case | Additional Step Required |
|---|---|---|---|
| Standard Product | Not required | Regular physical or digital product. | No |
| Grouped Product | grouped_product | Sell multiple existing products together as one product. | No |
| Voucher Product | voucher | Gift cards, license keys, or digital redemption products. | May require voucher setup after creation. |
| Downloadable Product | downloadable | Digital file products such as e-books or documents. | Files are managed separately after product creation. |
| Crowdfunding Project | crowdfunding_project | Fundraising product with goal tracking. | No |
| Donation Item | donation_item | Donation campaign with unit-based tracking. | No |
| Customizable Product | Not required | Product with custom input fields or predefined options. | No |
| Dynamic Bundle | dynamic_bundle | Bundle where customers select items from configured groups. | Yes. Selection groups must be added separately. |
| Field | Type | Required | Description |
|---|---|---|---|
name | object/string | Yes | Product name. Supports an i18n object such as { "ar": "...", "en": "..." } or a plain string. |
description | object/string | No | Product description. Supports an i18n object or a plain string. |
short_description | object/string | No | Short product description. |
product_class | string | Conditional | Defines the product type. Not required for standard or customizable products. |
sku | string | No | Product SKU. |
barcode | string | No | Product barcode. |
price | number | Yes | Product price. Some product classes have specific price rules. |
sale_price | number | No | Discounted product price. Not supported by some product classes. |
cost | number | No | Product cost. |
quantity | integer | Conditional | Product quantity. Some product classes calculate or manage quantity automatically. |
is_infinite | boolean | No | Whether the product has unlimited quantity. Not supported by some product classes. |
is_taxable | boolean | No | Whether the product is taxable. |
requires_shipping | boolean | No | Whether the product requires shipping. |
weight | object | Conditional | Product weight. Required when shipping is enabled. |
is_draft | boolean | No | Whether the product is saved as draft. |
is_published | boolean | No | Whether the product is published. |
keywords | array | No | Product keywords. |
seo | object | No | SEO title and description. |
badge | object | No | Product badge details. |
meta | object | Conditional | Product-type-specific metadata. |
stocks | array | Conditional | Product stock by inventory location. |
group_products | array | Conditional | Required for grouped products. |
custom_user_input_fields | array | No | Customer free-input fields. |
custom_option_fields | array | No | Customer predefined option fields. |
Note: Categories cannot be added during product creation. To assign a product to one or more categories, use the category assignment endpoints after the product is created.
product_class value.{
"name": {
"ar": "منتج عادي",
"en": "Standard Product"
},
"description": {
"ar": "منتج عادي عام",
"en": "A regular general product"
},
"sku": "STANDARD-001",
"barcode": "1234567890128",
"price": 99.99,
"sale_price": 79.99,
"quantity": 100,
"is_taxable": true,
"requires_shipping": true,
"weight": {
"value": 2.5,
"unit": "kg"
},
"is_draft": false,
"is_published": true,
"keywords": [
"product",
"standard"
]
}{
"id": "product-uuid",
"name": {
"ar": "منتج عادي",
"en": "Standard Product"
},
"description": {
"ar": "منتج عادي عام",
"en": "A regular general product"
},
"sku": "STANDARD-001",
"barcode": "1234567890128",
"product_class": null,
"price": 99.99,
"sale_price": 79.99,
"quantity": 100,
"is_infinite": false,
"is_taxable": true,
"requires_shipping": true,
"is_draft": false,
"is_published": true,
"weight": {
"value": 2.5,
"unit": "kg"
},
"meta": {},
"variants": [],
"custom_user_input_fields": [],
"custom_option_fields": [],
"created_at": "2026-06-10T10:00:00Z",
"updated_at": "2026-06-10T10:00:00Z"
}"product_class": "grouped_product"group_products array to define which products are included and how many units of each product are part of the group.{
"name": {
"ar": "منتج مجمع",
"en": "Grouped Product"
},
"description": {
"ar": "منتج يحتوي على عدة منتجات مرتبطة",
"en": "A product that includes multiple related products"
},
"product_class": "grouped_product",
"sku": "GROUPED-001",
"price": 299.99,
"is_draft": false,
"is_published": true,
"requires_shipping": true,
"stocks": [
{
"location": "location-uuid-here",
"available_quantity": 50,
"is_infinite": false
}
],
"group_products": [
{
"item_id": "product-uuid-1",
"item_quantity": 2
},
{
"item_id": "product-uuid-2",
"item_quantity": 1
},
{
"item_id": "product-uuid-3",
"item_quantity": 3
}
],
"weight": {
"value": 5,
"unit": "kg"
}
}{
"id": "product-uuid",
"name": {
"ar": "منتج مجمع",
"en": "Grouped Product"
},
"product_class": "grouped_product",
"sku": "GROUPED-001",
"price": 299.99,
"requires_shipping": true,
"is_draft": false,
"is_published": true,
"group_products": [
{
"item_id": "product-uuid-1",
"item_quantity": 2
},
{
"item_id": "product-uuid-2",
"item_quantity": 1
},
{
"item_id": "product-uuid-3",
"item_quantity": 3
}
],
"stocks": [
{
"location": "location-uuid-here",
"available_quantity": 50,
"is_infinite": false
}
]
}group_products cannot be empty for published grouped products."product_class": "voucher"{
"name": {
"ar": "بطاقة هدية",
"en": "Gift Card"
},
"description": {
"ar": "بطاقة هدية رقمية بقيمة 100 ريال",
"en": "Digital gift card worth 100 SAR"
},
"product_class": "voucher",
"sku": "VOUCHER-001",
"price": 100,
"is_taxable": false,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {}
}{
"id": "product-uuid",
"name": {
"ar": "بطاقة هدية",
"en": "Gift Card"
},
"description": {
"ar": "بطاقة هدية رقمية بقيمة 100 ريال",
"en": "Digital gift card worth 100 SAR"
},
"product_class": "voucher",
"sku": "VOUCHER-001",
"price": 100,
"is_taxable": false,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {}
}requires_shipping to false.sale_price.meta field can be used for extension data."product_class": "downloadable"{
"name": {
"ar": "كتاب إلكتروني",
"en": "E-Book"
},
"description": {
"ar": "كتاب الدليل الشامل",
"en": "Complete Guide E-Book"
},
"product_class": "downloadable",
"sku": "EBOOK-001",
"price": 29.99,
"is_taxable": false,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {
"download_limit": 5,
"expiration_period": 30
}
}{
"id": "product-uuid",
"name": {
"ar": "كتاب إلكتروني",
"en": "E-Book"
},
"product_class": "downloadable",
"sku": "EBOOK-001",
"price": 29.99,
"is_taxable": false,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {
"download_limit": 5,
"expiration_period": 30
}
}| Field | Type | Required | Description |
|---|---|---|---|
download_limit | integer | No | Maximum number of downloads allowed. |
expiration_period | integer | No | Number of days before the download link expires. |
is_infinite to true."product_class": "crowdfunding_project"meta object to define the funding goal and progress display settings.{
"name": {
"ar": "تمويل مشروع البئر",
"en": "Well Drilling Project"
},
"description": {
"ar": "تمويل حفر بئر مياه نظيفة في قرية نائية",
"en": "Fundraising for drilling a clean water well"
},
"product_class": "crowdfunding_project",
"sku": "CROWDFUND-001",
"price": 1,
"is_taxable": true,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {
"project_goal_amount": 5000,
"project_external_collected_amount": 1000,
"show_progress_bar": true,
"show_progress_percentage": true,
"show_collected_amount": true,
"is_open_donation": false
}
}{
"id": "product-uuid",
"name": {
"ar": "تمويل مشروع البئر",
"en": "Well Drilling Project"
},
"product_class": "crowdfunding_project",
"sku": "CROWDFUND-001",
"price": 1,
"is_taxable": true,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {
"project_goal_amount": 5000,
"project_external_collected_amount": 1000,
"show_progress_bar": true,
"show_progress_percentage": true,
"show_collected_amount": true,
"is_open_donation": false
}
}| Field | Type | Required | Description |
|---|---|---|---|
project_goal_amount | integer | Yes | Total amount required to complete the project. |
project_external_collected_amount | integer | No | Amount already collected outside Zid. |
show_progress_bar | boolean | No | Shows or hides the progress bar. |
show_progress_percentage | boolean | No | Shows or hides the progress percentage. |
show_collected_amount | boolean | No | Shows or hides the collected amount. |
is_open_donation | boolean | No | Allows donations without a fixed goal. When enabled, the goal amount is hidden. |
1.sale_price."product_class": "donation_item"meta object to define total units, externally purchased units, and progress display settings.{
"name": {
"ar": "وجبة غداء للفقراء",
"en": "Lunch Meal for the Poor"
},
"description": {
"ar": "وجبة غداء صحية متكاملة",
"en": "Complete healthy meal"
},
"product_class": "donation_item",
"sku": "DONATION-001",
"price": 25,
"is_taxable": true,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {
"total_units": 200,
"external_purchased_units": 50,
"show_progress_bar": true,
"show_progress_percentage": true,
"show_purchased_units": true,
"is_open_donation": false
}
}{
"id": "product-uuid",
"name": {
"ar": "وجبة غداء للفقراء",
"en": "Lunch Meal for the Poor"
},
"product_class": "donation_item",
"sku": "DONATION-001",
"price": 25,
"is_taxable": true,
"requires_shipping": false,
"is_draft": false,
"is_published": true,
"meta": {
"total_units": 200,
"external_purchased_units": 50,
"show_progress_bar": true,
"show_progress_percentage": true,
"show_purchased_units": true,
"is_open_donation": false
}
}| Field | Type | Required | Description |
|---|---|---|---|
total_units | integer | Yes | Total number of donation units available. |
external_purchased_units | integer | No | Units already purchased outside Zid. |
show_progress_bar | boolean | No | Shows or hides the progress bar. |
show_progress_percentage | boolean | No | Shows or hides the progress percentage. |
show_purchased_units | boolean | No | Shows or hides the number of purchased units. |
is_open_donation | boolean | No | Allows donations without a fixed unit goal. |
total_units.sale_price.custom_user_input_fieldscustom_option_fieldscustom_user_input_fields for free input fields such as text, number, URL, file, image, date, or time.custom_option_fields for predefined options such as dropdowns or checkboxes.product_class value.{
"name": {
"ar": "كعكة الزفاف المخصصة",
"en": "Custom Wedding Cake"
},
"description": {
"ar": "كعكة زفاف قابلة للتخصيص مع اسم العروسين",
"en": "Customizable wedding cake with couple names"
},
"sku": "CAKE-001",
"price": 299.99,
"is_draft": false,
"is_published": true,
"requires_shipping": true,
"custom_user_input_fields": [
{
"type": "TEXT",
"label": {
"ar": "اسم العريس",
"en": "Groom Name"
},
"hint": {
"ar": "أدخل اسم العريس",
"en": "Enter groom's name"
},
"is_required": true,
"price": 0,
"display_order": 1,
"is_published": true
},
{
"type": "TEXT",
"label": {
"ar": "اسم العروس",
"en": "Bride Name"
},
"hint": {
"ar": "أدخل اسم العروس",
"en": "Enter bride's name"
},
"is_required": true,
"price": 0,
"display_order": 2,
"is_published": true
},
{
"type": "NUMBER",
"label": {
"ar": "عدد الأشخاص",
"en": "Number of Guests"
},
"hint": {
"ar": "أدخل عدد الأشخاص",
"en": "Enter number of guests"
},
"is_required": true,
"price": 50,
"display_order": 3,
"is_published": true
}
],
"custom_option_fields": [
{
"type": "select",
"label": {
"ar": "نكهة الكعكة",
"en": "Cake Flavor"
},
"hint": {
"ar": "اختر نكهة الكعكة",
"en": "Choose cake flavor"
},
"is_required": true,
"can_choose_multiple_options": false,
"display_order": 1,
"is_published": true,
"choices": [
{
"id": "flavor-1",
"ar": "فانيليا كلاسيكية",
"en": "Classic Vanilla",
"price": 0
},
{
"id": "flavor-2",
"ar": "شوكولاتة داكنة",
"en": "Dark Chocolate",
"price": 25
},
{
"id": "flavor-3",
"ar": "فراولة",
"en": "Strawberry",
"price": 20
}
]
},
{
"type": "select",
"label": {
"ar": "نوع الحشوة",
"en": "Filling Type"
},
"hint": {
"ar": "اختر نوع الحشوة",
"en": "Choose filling type"
},
"is_required": true,
"can_choose_multiple_options": false,
"display_order": 2,
"is_published": true,
"choices": [
{
"id": "filling-1",
"ar": "كريمة",
"en": "Cream",
"price": 0
},
{
"id": "filling-2",
"ar": "فاكهة",
"en": "Fruit",
"price": 15
}
]
}
]
}{
"id": "product-uuid",
"name": {
"ar": "كعكة الزفاف المخصصة",
"en": "Custom Wedding Cake"
},
"sku": "CAKE-001",
"product_class": null,
"price": 299.99,
"is_draft": false,
"is_published": true,
"requires_shipping": true,
"custom_user_input_fields": [
{
"id": "custom-field-uuid-1",
"type": "TEXT",
"label": {
"ar": "اسم العريس",
"en": "Groom Name"
},
"hint": {
"ar": "أدخل اسم العريس",
"en": "Enter groom's name"
},
"is_required": true,
"price": 0,
"display_order": 1,
"is_published": true
}
],
"custom_option_fields": [
{
"id": "option-field-uuid-1",
"label": {
"ar": "نكهة الكعكة",
"en": "Cake Flavor"
},
"hint": {
"ar": "اختر نكهة الكعكة",
"en": "Choose cake flavor"
},
"is_required": true,
"can_choose_multiple_options": false,
"display_order": 1,
"is_published": true,
"choices": [
{
"id": "flavor-1",
"ar": "فانيليا كلاسيكية",
"en": "Classic Vanilla",
"price": 0
}
]
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Field type. Must be uppercase. |
label | object/string | Yes | Field label. Accepts an i18n object or plain string. |
hint | object/string | No | Helper text shown to the customer. |
is_required | boolean | No | Whether the customer must complete the field. |
price | number | No | Additional price added when the field is used. Defaults to 0. |
display_order | integer | No | Display order of the field. |
is_published | boolean | No | Whether the field is visible to customers. |
custom_user_input_fields[].type values:| Type |
|---|
TEXT |
NUMBER |
URL |
FILE |
IMAGE |
DATE |
TIME |
| Field | Type | Required | Description |
|---|---|---|---|
type | string | No | Ignored by the API. The option type is derived from can_choose_multiple_options. |
label | object/string | Yes | Field label. Accepts an i18n object or plain string. |
hint | object/string | No | Helper text shown to the customer. |
is_required | boolean | No | Whether the customer must select an option. |
can_choose_multiple_options | boolean | No | Determines whether the field behaves as a dropdown or checkbox group. |
display_order | integer | No | Display order of the field. |
is_published | boolean | No | Whether the field is visible to customers. |
choices | array | Yes | List of predefined choices. |
| Field | Type | Required | Description |
|---|---|---|---|
id | string | No | Choice identifier. If omitted, it is generated automatically. |
ar | string | Conditional | Arabic choice label. |
en | string | Conditional | English choice label. |
price | number | No | Additional price for the choice. Defaults to 0. |
custom_user_input_fields are used for free input fields.custom_option_fields are used for predefined choices.custom_user_input_fields[].type must be uppercase.text will be rejected.custom_option_fields[].type is ignored because the field type is derived from can_choose_multiple_options.can_choose_multiple_options is false, the option field behaves like a dropdown.can_choose_multiple_options is true, the option field behaves like a checkbox field.choices[].id is optional. If omitted, it is generated automatically.choices[].price defaults to 0 if it is not provided.label is required for both field types.label accepts either an i18n object or a plain string.id to update the field.is_deleted: true."product_class": "dynamic_bundle"POST /v1/products/PATCH /v1/products/{product_id}/selection-groups/bulk-patch/POST /v1/products/PATCH /v1/products/{product_id}/selection-groups/bulk-patch/PATCH /v1/products/{id}/{
"name": {
"ar": "حزمة البناء المخصصة",
"en": "Custom Build Bundle"
},
"description": {
"ar": "اختر المكونات الخاصة بك لإنشاء حزمة فريدة",
"en": "Choose your components to create a unique bundle"
},
"product_class": "dynamic_bundle",
"sku": "BUNDLE-001",
"price": 0,
"is_draft": false,
"is_published": false,
"requires_shipping": true,
"meta": {
"location_id": "dd125776-70d1-4819-934c-a29b8ebd18ca"
}
}{
"id": "product-uuid",
"name": {
"ar": "حزمة البناء المخصصة",
"en": "Custom Build Bundle"
},
"description": {
"ar": "اختر المكونات الخاصة بك لإنشاء حزمة فريدة",
"en": "Choose your components to create a unique bundle"
},
"product_class": "dynamic_bundle",
"sku": "BUNDLE-001",
"price": 0,
"is_draft": false,
"is_published": false,
"requires_shipping": true,
"meta": {
"location_id": "dd125776-70d1-4819-934c-a29b8ebd18ca"
},
"selection_groups": []
}price: 0 is commonly used because the final price is calculated from the selected bundle items.meta.location_id should match the inventory location where all bundle items have stock.is_draft: true if you want to create the product first and add selection groups later.location_id.{
"location_id": "dd125776-70d1-4819-934c-a29b8ebd18ca",
"selection_groups": [
{
"name": {
"ar": "اختر اللون",
"en": "Choose Color"
},
"required_selection_count": 1,
"allow_duplicate_items": false,
"items": [
{
"item_id": "standalone-product-uuid"
},
{
"item_id": "parent-product-uuid",
"variant_ids": [
"variant-child-uuid-1",
"variant-child-uuid-2"
]
}
]
}
]
}{
"id": "product-uuid",
"product_class": "dynamic_bundle",
"selection_groups": [
{
"selection_group_id": "selection-group-uuid",
"name": {
"ar": "اختر اللون",
"en": "Choose Color"
},
"required_selection_count": 1,
"allow_duplicate_items": false,
"items": [
{
"item_id": "standalone-product-uuid",
"variant_ids": null
},
{
"item_id": "parent-product-uuid",
"variant_ids": [
"variant-child-uuid-1",
"variant-child-uuid-2"
]
}
]
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
location_id | string | Yes | Inventory location UUID. All bundle items must have stock in this location. |
selection_groups | array | Yes | List of selection groups to add, update, or delete. |
selection_groups[].selection_group_id | string | No | Existing selection group UUID. Include only when updating or deleting an existing group. |
selection_groups[].name | object/string | Yes | Selection group name. Accepts an i18n object or a plain string. |
selection_groups[].required_selection_count | integer | Yes | Number of items the customer must select from this group. Must be less than or equal to the number of items in the group. |
selection_groups[].allow_duplicate_items | boolean | No | Determines whether duplicate items are allowed. Defaults to false. |
selection_groups[].items | array | Yes | List of products available for selection in the group. |
selection_groups[].items[].item_id | string | Yes | Product UUID of the item added to the selection group. |
selection_groups[].items[].variant_ids | array/null | Conditional | Required when item_id belongs to a parent product with options or variants. Omit or set to null for standalone products. |
selection_groups[].is_deleted | boolean | No | Set to true to delete an existing selection group. Use only with selection_group_id. |
item_id.{
"item_id": "1be029e1-b627-48db-88ab-1c6595428915"
}variant_ids entirely or set it to null.variant_ids is required.{
"item_id": "parent-product-uuid",
"variant_ids": [
"variant-uuid-1",
"variant-uuid-2"
]
}variant_ids, the API returns an error because at least one child variant must be selected.{
"location_id": "dd125776-70d1-4819-934c-a29b8ebd18ca",
"selection_groups": [
{
"name": {
"ar": "اختر اللون",
"en": "Choose Color"
},
"required_selection_count": 1,
"allow_duplicate_items": false,
"items": [
{
"item_id": "standalone-product-uuid"
},
{
"item_id": "parent-product-uuid",
"variant_ids": [
"variant-child-uuid-1",
"variant-child-uuid-2"
]
}
]
},
{
"name": {
"ar": "اختر المقاس",
"en": "Choose Size"
},
"required_selection_count": 1,
"allow_duplicate_items": false,
"items": [
{
"item_id": "another-product-uuid"
}
]
}
]
}{
"is_draft": false,
"is_published": true
}{
"name": {
"ar": "منتج شامل",
"en": "Comprehensive Product"
},
"description": {
"ar": "منتج يوضح جميع الميزات المتاحة",
"en": "Product showcasing all available features"
},
"short_description": {
"ar": "منتج شامل مع جميع الميزات",
"en": "Comprehensive product with all features"
},
"sku": "FULL-001",
"barcode": "1234567890128",
"price": 199.99,
"sale_price": 149.99,
"cost": 80,
"quantity": 100,
"is_infinite": false,
"is_draft": false,
"is_published": true,
"is_taxable": true,
"requires_shipping": true,
"weight": {
"value": 1.5,
"unit": "kg"
},
"keywords": [
"product",
"complete",
"featured"
],
"display_order": 1,
"seo": {
"title": {
"ar": "منتج شامل - متجر متقدم",
"en": "Comprehensive Product - Advanced Store"
},
"description": {
"ar": "اكتشف منتجنا الشامل بميزات متقدمة",
"en": "Discover our comprehensive product with advanced features"
}
},
"purchase_restrictions": {
"min_quantity_per_cart": 1,
"max_quantity_per_cart": 5,
"availability_period_start": "2024-01-01T00:00:00Z",
"availability_period_end": "2024-12-31T23:59:59Z",
"sale_price_period_start": "2024-01-01T00:00:00Z",
"sale_price_period_end": "2024-03-31T23:59:59Z"
},
"badge": {
"body": {
"ar": "خصم {discount_percent}",
"en": "Discount {discount_percent}"
}
}
}{
"message": "The given data was invalid.",
"errors": {
"price": [
"The price field is required."
]
}
}{
"message": "Unauthenticated."
}{
"message": "This action is unauthorized."
}| Error | Cause | How to Fix |
|---|---|---|
Bundle Product must contain at least 1 selection group | The Dynamic Bundle product was published or updated before adding selection groups. | Add selection groups using the bulk patch endpoint before publishing the product. |
No location found with the given ID=None | location_id is missing from the request body. | Add location_id at the top level of the request body. |
For products with options, at least one variant must be selected | The selected item_id belongs to a parent product with variants. | Add variant_ids with at least one child variant UUID. |
A selection group must have at least 1 item | The items array is empty. | Add at least one item to the selection group. |
required_selection_count must be less than or equal to items count | The required selection count is greater than the number of available items. | Reduce required_selection_count or add more items to the group. |
Location ID must be specified for dynamic bundle product | meta.location_id is missing from the product or location_id is missing from the bulk patch request. | Add the location ID in both the product metadata and the selection group request. |
All items in a dynamic bundle must have quantity in the same location | One or more items do not have stock in the selected location. | Make sure every item has stock in the specified location_id. |
You can't add more than 10 selection groups | The request includes more than 10 selection groups. | Keep the number of selection groups to 10 or fewer. |
Product [uuid] has no stock | The selected item does not have stock in the bundle location. | Add stock for the product in the selected location. |
{
"message": "For products with options, at least one variant must be selected",
"errors": {
"selection_groups.0.items.1.variant_ids": [
"For products with options, at least one variant must be selected"
]
}
}| Method | Endpoint | Purpose |
|---|---|---|
POST | /v1/products/ | Create a product. |
PATCH | /v1/products/{id}/ | Update product fields or publish a product. |
PATCH | /v1/products/{product_id}/selection-groups/bulk-patch/ | Add, update, or delete Dynamic Bundle selection groups. |
GET | /v1/products/{id}/ | Retrieve product details. |
GET | /v1/products/ | List products. |
product_class value for the product type.product_class for standard products unless required by your implementation.variant_ids.location_id.is_draft: true when you need to create a product first and complete its configuration later.