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. To obtain both:
priceData
convertedPriceData
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 | |
priceData.discountedPrice | variantsInfo.variants[i].price.salePrice.amount | |
priceData.formatted.price | variantsInfo.variants[i].price.basePrice.formattedAmount | |
priceData.formatted.discountedPrice | variantsInfo.variants[i].price.salePrice.formattedAmount | |
priceData.formatted.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.description | |
priceData.pricePerUnit | variantsInfo.variants[i].physicalProperties.pricePerUnit.value | |
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 | |
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 | - | |
productOptions[i].optionType | options[i].optionRenderType OR modifiers[i].modifierRenderType | |
productOptions[i].name | options[i].name OR modifiers[i].name | |
productOptions[i].choices[i].value | options[i].choicesSettings.choices[i] OR modifiers[i].choicesSettings.choices | |
productOptions[i].choices[i].description | options[i].choicesSettings.choices[i].name OR modifiers[i].choicesSettings.choices[i].name | |
productOptions[i].choices[i].media | options[i].choicesSettings.choices[i].linkedMedia[i] OR 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 | - | If currency header was not sent, all prices are returned in original currency, otherwise converted to requested currency |
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.tags[i].type * | seoData.tags[i].type | |
seoData.tags[i].props | seoData.tags[i].props | |
seoData.tags[i].meta | seoData.tags[i].meta | |
seoData.tags[i].children | seoData.tags[i].children | |
seoData.tags[i].custom | seoData.tags[i].custom | |
seoData.tags[i].disabled | seoData.tags[i].disabled | |
seoData.settings.preventAutoRedirect | seoData.settings.preventAutoRedirect | |
seoData.settings.keywords[i].term | seoData.settings.keywords[i].term | |
seoData.settings.keywords[i].isMain | seoData.settings.keywords[i].isMain | |
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 | image.id if mediaType = IMAGE OR video.id if mediaType = VIDEO |
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 V1 | Inventory V3 |
---|---|
product.variants[i].stock.trackQuantity | trackQuantity |
product.variants[i].stock.quantity | preorderInfo.quantity |
product.variants[i].stock.inStock | trackingMethod.inStock OR availabilityStatus depending on needs |
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:
We've updated the structure of the webhook/event payload.
The product ID is now provided both at the top level as entityId
and as product.id
within the payload itself.
The table below describes where to find the product ID or product entity in the new webhook payloads:
Catalog V1 Webhooks | Catalog V3 Webhooks |
---|---|
productId , collectionId , variants.variantId | All webhook payloads - entityId |
Product Changed - changedFields | modifiedFields |
Product/Collection Created entity data | createdEvent.entityAsJson |
For more detailed information on specific field changes and how to access data in the new API structure, please refer to our API documentation.