This guide aims to assist developers in migrating from the Stores Catalog V1 API to the V3 API. It outlines key changes in the product object structure and provides detailed conversion tables for various components.
manageVariants
field has been removed. All products now have variants:
managedVariants: true
in V1) may have multiple variantspriceData
and convertedPriceData
are no longer available.managedVariants: true
managedVariants: false
Some fields previously accessible via the Catalog V1 Product object are now available through other Catalog V3 APIs. On the other hand, some fields that required separate API calls in V1 are now directly available in the Products V3 API.
*Fields marked with an asterisk signify little to no change in semantics or access.
Product V1 | Product V3 | Notes |
---|---|---|
id * | id | |
name * | name | |
slug * | slug | |
visible * | visible | |
productType | productType | Enum values in V3 are in UPPER_CASE |
description | description (recommended) OR plainDescription (if integration with RICOS isn't possible) | |
sku | variantsInfo.variants[i].sku | For single variant product only. Each variant in V3 can have its own SKU |
weight | variantsInfo.variants[i].physicalProperties.weight | For single variant product only. Each variant in V3 can have its own weight |
weightRange.minValue | physicalProperties.shippingWeightRange.minValue | |
weightRange.maxValue | physicalProperties.shippingWeightRange.maxValue | |
stock.trackInventory | Available via Inventory Items API | Each variant in V3 can have its own inventory. Search Inventory Items and filter by productId and/or variantId . |
stock.quantity | Available via Inventory Items API | Each variant in V3 can have its own inventory. Search Inventory Items and filter by productId and/or variantId . |
stock.inventoryStatus | inventory.availabilityStatus | |
priceData.currency | currency | Now a requested field |
priceData.price | variantsInfo.variants[i].price.basePrice.amount | See point (5) in Major Changes section above |
priceData.discountedPrice | variantsInfo.variants[i].price.salePrice.amount | See point (5) in Major Changes section above |
priceData.formatted.price | variantsInfo.variants[i].price.basePrice.formattedAmount | See point (5) in Major Changes section above |
priceData.formatted.discountedPrice | variantsInfo.variants[i].price.salePrice.formattedAmount | See point (5) in Major Changes section above |
priceData.formatted.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.description | See point (5) in Major Changes section above |
priceData.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.value | See point (5) in Major Changes section above |
convertedPriceData.currency | currency | Now a requested field |
convertedPriceData.price | variantsInfo.variants[i].price.basePrice.amount | For single variant product only. Each variant in V3 can have its own price |
convertedPriceData.discountedPrice | variantsInfo.variants[i].price.salePrice.amount | For single variant product only. Each variant in V3 can have its own sale price |
convertedPriceData.formatted.price | variantsInfo.variants[i].price.basePrice.formattedAmount | For single variant product only. |
convertedPriceData.formatted.discountedPrice | variantsInfo.variants[i].price.salePrice.formattedAmount | For single variant product only. |
convertedPriceData.formatted.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.description | For single variant product only. |
convertedPriceData.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.value | For single variant product only. |
priceRange.minValue | basePriceRange.minValue.amount | |
priceRange.maxValue | basePriceRange.maxValue.amount | |
costAndProfitData.itemCost | variantsInfo.variants[i].revenueDetails.cost.amount | For single variant product only. |
costAndProfitData.formattedItemCost | variantsInfo.variants[i].revenueDetails.cost.formattedAmount | For single variant product only. |
costAndProfitData.profit | variantsInfo.variants[i].revenueDetails.profit.amount | For single variant product only. |
costAndProfitData.formattedProfit | variantsInfo.variants[i].revenueDetails.profit.formattedAmount | For single variant product only. |
costAndProfitData.profitMargin | variantsInfo.variants[i].revenueDetails.profitMargin | For single variant product only. |
costRange.minValue | costRange.minValue.amount | |
costRange.maxValue | costRange.maxValue.amount | |
pricePerUnitData.totalQuantity | variantsInfo.variants[i].physicalProperties.pricePerUnit.settings.quantity | |
pricePerUnitData.totalMeasurementUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.settings.measurementUnit | |
pricePerUnitData.baseQuantity | physicalProperties.pricePerUnit.quantity | |
pricePerUnitData.baseMeasurementUnit | physicalProperties.pricePerUnit.measurementUnit | |
additionalInfoSections[i].title | infoSections[i].title | |
additionalInfoSections[i].description | infoSections[i].description (recommended) OR infoSections[i].plainDescription (if integration with RICOS isn't possible) | |
media.mainMedia | media.main | See media table |
media.items[i] | media.itemsInfo.items[i] | |
customTextFields[i].title | modifiers[i].freeTextSettings.title | Manage these fields with the Customizations API |
customTextFields[i].maxLength | modifiers[i].freeTextSettings.maxCharCount | Manage these fields with the Customizations API |
customTextFields[i].mandatory | modifiers[i].mandatory | Manage these fields with the Customizations API |
manageVariants | - | See point (5) in Major Changes section above |
productOptions[i].optionType and manageVariants = true | options[i].optionRenderType | |
productOptions[i].optionType and manageVariants = false | modifiers[i].modifierRenderType | |
productOptions[i].name and manageVariants = true | options[i].name | |
productOptions[i].name and manageVariants = false | modifiers[i].name | |
productOptions[i].choices[i].value and manageVariants = true | options[i].choicesSettings.choices[i] | |
productOptions[i].choices[i].value and manageVariants = false | modifiers[i].choicesSettings.choices | |
productOptions[i].choices[i].description and manageVariants = true | options[i].choicesSettings.choices[i].name | |
productOptions[i].choices[i].description and manageVariants = false | modifiers[i].choicesSettings.choices[i].name | |
productOptions[i].choices[i].media and manageVariants = true | options[i].choicesSettings.choices[i].linkedMedia[i] | See media table |
productOptions[i].choices[i].media and manageVariants = false | modifiers[i].choicesSettings.choices[i].linkedMedia[i] | See media table |
productOptions[i].choices[i].inStock | options[i].choicesSettings.choices[i].inStock | |
productOptions[i].choices[i].visible | options[i].choicesSettings.choices[i].visible | |
productPageUrl.base | url.url | Must be a full URL |
productPageUrl.path | url.relativePath | |
numericId | Was used for cursor paging - V3 Query & Search APIs support cursor paging out of the box | |
inventoryItemId | Available via Inventory Items API | Moved to inventory service but it's no longer saved on Product V3. Search Inventory Items and filter by productId and/or variantId . |
discount.type | variantsInfo.variants[i].price.salePrice.amount | Discounts now saved on each variant |
discount.value | variantsInfo.variants[i].price.salePrice.amount | Discounts now saved on each variant |
collectionIds[i] | directCategories[i].id | |
variants[i].id | variantsInfo.variants[i].id | |
variants[i].choices[key] | variantsInfo.variants[i].choices[i].optionChoiceNames.optionName | |
variants[i].choices[value] | variantsInfo.variants[i].choices[i].optionChoiceNames.choiceName | |
variants[i].variant.priceData | - | See point (5) in Major Changes section above |
variants[i].variant.convertedPriceData.price | variantsInfo.variants[i].price.basePrice.amount | |
variants[i].variant.convertedPriceData.discountedPrice | variantsInfo.variants[i].price.salePrice.amount | |
variants[i].variant.convertedPriceData.formatted.price | variantsInfo.variants[i].price.basePrice.formattedAmount | |
variants[i].variant.convertedPriceData.formatted.discountedPrice | variantsInfo.variants[i].price.salePrice.formattedAmount | |
variants[i].variant.convertedPriceData.formatted.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.description | |
variants[i].variant.convertedPriceData.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.value | |
variants[i].variant.costAndProfitData.itemCost | variantsInfo.variants[i].revenueDetails.cost.amount | |
variants[i].variant.costAndProfitData.formattedItemCost | variantsInfo.variants[i].revenueDetails.cost.formattedAmount | |
variants[i].variant.costAndProfitData.profit | variantsInfo.variants[i].revenueDetails.profit.amount | |
variants[i].variant.costAndProfitData.formattedProfit | variantsInfo.variants[i].revenueDetails.profit.formattedAmount | |
variants[i].variant.costAndProfitData.profitMargin | variantsInfo.variants[i].revenueDetails.profitMargin | |
variants[i].variant.weight | variantsInfo.variants[i].physicalProperties.weight | |
variants[i].variant.sku | variantsInfo.variants[i].sku | |
variants[i].variant.visible | variantsInfo.variants[i].visible | |
variants[i].stock.trackQuantity | Available via Inventory Items API | |
variants[i].stock.quantity | Available via Inventory Items API | |
variants[i].stock.inStock | variantsInfo.variants[i].inventoryStatus.inStock | |
lastUpdated | updatedDate | |
createdDate | createdDate | |
seoData * | seoData | |
ribbon | ribbon.name | Manage these fields with the Ribbons API |
brand | brand.name | Manage these fields with the Brands API |
taxGroupId | taxGroupId | |
digitalFile.id | variantsInfo.variants[i].digitalProperties.digitalFile.id | Each variant in V3 can have its own digital file |
digitalFile.fileName | variantsInfo.variants[i].digitalProperties.digitalFile.fileName | Each variant in V3 can have its own digital file |
digitalFile.fileType | variantsInfo.variants[i].digitalProperties.digitalFile.fileType | Each variant in V3 can have its own digital file |
*Fields marked with an asterisk signify little to no change in semantics or access.
Media V1 | Media V3 |
---|---|
thumbnail.url | - |
thumbnail.width | - |
thumbnail.height | - |
thumbnail.format | - |
thumbnail.altText | - |
mediaType | - |
title and mediaType = IMAGE | image.fileName |
title and mediaType = VIDEO | video.filename |
id and mediaType = IMAGE | image.id |
id and mediaType = VIDEO | video.id |
image.url * | image.url |
image.width * | image.width |
image.height * | image.height |
image.format | - |
image.altText * | image.altText |
video.files[i].url | video.resolutions[i].url |
video.files[i].width | video.resolutions[i].width |
video.files[i].height | video.resolutions[i].height |
video.files[i].format | video.resolutions[i].format |
video.files[i].altText | - |
video.stillFrameMediaId | - |
Inventory V2 | Inventory Items V3 | Notes |
---|---|---|
id * | id | |
productId * | productId | |
trackQuantity | trackQuantity | Now on the variant level |
variants[i].variantId | variantId | |
variants[i].inStock | trackingMethod.inStock | |
variants[i].quantity | trackingMethod.quantity | |
variants[i].availableForPreorder | AvailabilityStatus = PREORDER | |
lastUpdated | updatedDate | |
numericId | - | Was used for cursor paging - V3 Query & Search APIs support cursor paging out of the box |
preorderInfo.enabled | preorderInfo.enabled | |
preorderInfo.message | preorderInfo.message | |
preorderInfo.limit | preorderInfo.limit |
In V1 Subscriptions has its own APIs, where in V3 we don't have a dedicated API. Subscriptions exists directly in Product entity.
SubscriptionOption V1 | Product V3 |
---|---|
id | subscriptionDetails.subscriptions[i].id |
title | subscriptionDetails.subscriptions[i].title |
description | subscriptionDetails.subscriptions[i].description |
subscriptionSettings.frequency | subscriptionDetails.subscriptions[i].frequency |
subscriptionSettings.interval | subscriptionDetails.subscriptions[i].interval |
subscriptionSettings.autoRenewal | subscriptionDetails.subscriptions[i].autoRenewal |
subscriptionSettings.billingCycles | subscriptionDetails.subscriptions[i].billingCycles |
discount.type | subscriptionDetails.subscriptions[i].discount.type |
discount.value | subscriptionDetails.subscriptions[i].discount.amountOff OR subscriptionDetails.subscriptions[i].discount.percentOff |
SubscriptionOptionInProduct V1 | Product V3 |
---|---|
id | subscriptionDetails.subscriptions[i].id |
hidden | subscriptionDetails.subscriptions[i].visible |
title | subscriptionDetails.subscriptions[i].title |
description | subscriptionDetails.subscriptions[i].description |
subscriptionSettings.frequency | subscriptionDetails.subscriptions[i].frequency |
subscriptionSettings.interval | subscriptionDetails.subscriptions[i].interval |
subscriptionSettings.autoRenewal | subscriptionDetails.subscriptions[i].autoRenewal |
subscriptionSettings.billingCycles | subscriptionDetails.subscriptions[i].billingCycles |
discount.type | subscriptionDetails.subscriptions[i].discount.type |
discount.value | subscriptionDetails.subscriptions[i].discount.amountOff OR subscriptionDetails.subscriptions[i].discount.percentOff |
The following table shows Catalog V1 webhooks and their equivalents in Catalog V3 that are triggered at the same time:
Catalog V1 | Catalog V3 |
---|---|
Product Created | Product Created |
Product Changed | Product Updated |
Product Deleted | Product Deleted |
Product Variants Changed | - |
We've updated the structure of the webhook/event payload. The table below describes where to find the entity ID or entity object in the new webhook payloads:
Catalog V1 Webhooks | Catalog V3 Webhooks |
---|---|
productId , collectionId , variants.variantId | All webhook payloads - metadata.entityId |
Product/Collection Created entity data | All webhook payloads - handler.event.entity |
For more detailed information on specific field changes and how to access data in the new API structure, please refer to our API documentation.