Catalog V1 to V3 Conversion Guide

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.

Major Changes

  1. Product to Variant Field Relocation: Several fields have moved from the product level to the variant level, including price and sale price. This change allows for more granular control per variant.
  2. Universal Variants: Every product now has at least one variant. Products without options are treated as 'single variant products'.
  3. Variant Management: The manageVariants field has been removed. All products now have variants:
    1. Products without options are considered single variant products
    2. Products with at least one option (equivalent to managedVariants: true in V1) may have multiple variants
  4. Discount Replacement: The discount field has been replaced by the sale price field at the variant level.
  5. Price Data Changes: priceData and convertedPriceData are no longer available. To obtain both:
    1. Make one call without a currency header to get priceData
    2. Make another call with a currency header to get convertedPriceData
  6. Options and Customizations: The new Customizations V3 API manages both options and modifiers:
    1. Customization V3 options type are equivalent to V1 options with managedVariants: true
    2. Customization V3 modifiers type are equivalent to V1 options with managedVariants: false
  7. Custom Text Fields: These have been moved to the Customizations modifier type

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.

Conversion Tables

*Fields marked with an asterisk signify little to no change in semantics or access.

Product Object Conversion

Product V1Product V3Notes
id*id
name*name
slug*slug
visible*visible
productTypeproductTypeEnum values in V3 are in UPPER_CASE
descriptiondescription (recommended) OR plainDescription (if integration with RICOS isn't possible)
skuvariantsInfo.variants[i].skuFor single variant product only. Each variant in V3 can have its own SKU
weightvariantsInfo.variants[i].physicalProperties.weightFor single variant product only. Each variant in V3 can have its own weight
weightRange.minValuephysicalProperties.shippingWeightRange.minValue
weightRange.maxValuephysicalProperties.shippingWeightRange.maxValue
stock.trackInventoryAvailable via Inventory Items APIEach variant in V3 can have its own inventory. Search Inventory Items and filter by productId and/or variantId.
stock.quantityAvailable via Inventory Items APIEach variant in V3 can have its own inventory. Search Inventory Items and filter by productId and/or variantId.
stock.inventoryStatusinventory.availabilityStatus
priceData.currencycurrencyNow a requested field
priceData.pricevariantsInfo.variants[i].price.basePrice.amount
priceData.discountedPricevariantsInfo.variants[i].price.salePrice.amount
priceData.formatted.pricevariantsInfo.variants[i].price.basePrice.formattedAmount
priceData.formatted.discountedPricevariantsInfo.variants[i].price.salePrice.formattedAmount
priceData.formatted.pricePerUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.description
priceData.pricePerUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.value
convertedPriceData.currencycurrencyNow a requested field
convertedPriceData.pricevariantsInfo.variants[i].price.basePrice.amountFor single variant product only. Each variant in V3 can have its own price
convertedPriceData.discountedPricevariantsInfo.variants[i].price.salePrice.amountFor single variant product only. Each variant in V3 can have its own sale price
convertedPriceData.formatted.pricevariantsInfo.variants[i].price.basePrice.formattedAmountFor single variant product only.
convertedPriceData.formatted.discountedPricevariantsInfo.variants[i].price.salePrice.formattedAmountFor single variant product only.
convertedPriceData.formatted.pricePerUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.descriptionFor single variant product only.
convertedPriceData.pricePerUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.valueFor single variant product only.
priceRange.minValuebasePriceRange.minValue.amount
priceRange.maxValuebasePriceRange.maxValue.amount
costAndProfitData.itemCostvariantsInfo.variants[i].revenueDetails.cost.amountFor single variant product only.
costAndProfitData.formattedItemCostvariantsInfo.variants[i].revenueDetails.cost.formattedAmountFor single variant product only.
costAndProfitData.profitvariantsInfo.variants[i].revenueDetails.profit.amountFor single variant product only.
costAndProfitData.formattedProfitvariantsInfo.variants[i].revenueDetails.profit.formattedAmountFor single variant product only.
costAndProfitData.profitMarginvariantsInfo.variants[i].revenueDetails.profitMarginFor single variant product only.
costRange.minValuecostRange.minValue.amount
costRange.maxValuecostRange.maxValue.amount
pricePerUnitData.totalQuantityvariantsInfo.variants[i].physicalProperties.pricePerUnit.settings.quantity
pricePerUnitData.totalMeasurementUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.settings.measurementUnit
pricePerUnitData.baseQuantityphysicalProperties.pricePerUnit.quantity
pricePerUnitData.baseMeasurementUnitphysicalProperties.pricePerUnit.measurementUnit
additionalInfoSections[i].titleinfoSections[i].title
additionalInfoSections[i].descriptioninfoSections[i].description (recommended) OR infoSections[i].plainDescription (if integration with RICOS isn't possible)
media.mainMediamedia.main
media.items[i]media.itemsInfo.items[i]
customTextFields[i].titlemodifiers[i].freeTextSettings.titleManage these fields with the Customizations API
customTextFields[i].maxLengthmodifiers[i].freeTextSettings.maxCharCountManage these fields with the Customizations API
customTextFields[i].mandatorymodifiers[i].mandatoryManage these fields with the Customizations API
manageVariants-
productOptions[i].optionTypeoptions[i].optionRenderType OR modifiers[i].modifierRenderType
productOptions[i].nameoptions[i].name OR modifiers[i].name
productOptions[i].choices[i].valueoptions[i].choicesSettings.choices[i] OR modifiers[i].choicesSettings.choices
productOptions[i].choices[i].descriptionoptions[i].choicesSettings.choices[i].name OR modifiers[i].choicesSettings.choices[i].name
productOptions[i].choices[i].mediaoptions[i].choicesSettings.choices[i].linkedMedia[i] OR modifiers[i].choicesSettings.choices[i].linkedMedia[i]See media table
productOptions[i].choices[i].inStockoptions[i].choicesSettings.choices[i].inStock
productOptions[i].choices[i].visibleoptions[i].choicesSettings.choices[i].visible
productPageUrl.baseurl.urlMust be a full URL
productPageUrl.pathurl.relativePath
numericIdWas used for cursor paging - V3 Query & Search APIs support cursor paging out of the box
inventoryItemIdAvailable via Inventory Items APIMoved to inventory service but it's no longer saved on Product V3. Search Inventory Items and filter by productId and/or variantId.
discount.typevariantsInfo.variants[i].price.salePrice.amountDiscounts now saved on each variant
discount.valuevariantsInfo.variants[i].price.salePrice.amountDiscounts now saved on each variant
collectionIds[i]directCategories[i].id
variants[i].idvariantsInfo.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.pricevariantsInfo.variants[i].price.basePrice.amount
variants[i].variant.convertedPriceData.discountedPricevariantsInfo.variants[i].price.salePrice.amount
variants[i].variant.convertedPriceData.formatted.pricevariantsInfo.variants[i].price.basePrice.formattedAmount
variants[i].variant.convertedPriceData.formatted.discountedPricevariantsInfo.variants[i].price.salePrice.formattedAmount
variants[i].variant.convertedPriceData.formatted.pricePerUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.description
variants[i].variant.convertedPriceData.pricePerUnitvariantsInfo.variants[i].physicalProperties.pricePerUnit.value
variants[i].variant.costAndProfitData.itemCostvariantsInfo.variants[i].revenueDetails.cost.amount
variants[i].variant.costAndProfitData.formattedItemCostvariantsInfo.variants[i].revenueDetails.cost.formattedAmount
variants[i].variant.costAndProfitData.profitvariantsInfo.variants[i].revenueDetails.profit.amount
variants[i].variant.costAndProfitData.formattedProfitvariantsInfo.variants[i].revenueDetails.profit.formattedAmount
variants[i].variant.costAndProfitData.profitMarginvariantsInfo.variants[i].revenueDetails.profitMargin
variants[i].variant.weightvariantsInfo.variants[i].physicalProperties.weight
variants[i].variant.skuvariantsInfo.variants[i].sku
variants[i].variant.visiblevariantsInfo.variants[i].visible
variants[i].stock.trackQuantityAvailable via Inventory Items API
variants[i].stock.quantityAvailable via Inventory Items API
variants[i].stock.inStockvariantsInfo.variants[i].inventoryStatus.inStock
lastUpdatedupdatedDate
createdDatecreatedDate
seoData.tags[i].type*seoData.tags[i].type
seoData.tags[i].propsseoData.tags[i].props
seoData.tags[i].metaseoData.tags[i].meta
seoData.tags[i].childrenseoData.tags[i].children
seoData.tags[i].customseoData.tags[i].custom
seoData.tags[i].disabledseoData.tags[i].disabled
seoData.settings.preventAutoRedirectseoData.settings.preventAutoRedirect
seoData.settings.keywords[i].termseoData.settings.keywords[i].term
seoData.settings.keywords[i].isMainseoData.settings.keywords[i].isMain
ribbonribbon.nameManage these fields with the Ribbons API
brandbrand.nameManage these fields with the Brands API
taxGroupIdtaxGroupId
digitalFile.idvariantsInfo.variants[i].digitalProperties.digitalFile.idEach variant in V3 can have its own digital file
digitalFile.fileNamevariantsInfo.variants[i].digitalProperties.digitalFile.fileNameEach variant in V3 can have its own digital file
digitalFile.fileTypevariantsInfo.variants[i].digitalProperties.digitalFile.fileTypeEach variant in V3 can have its own digital file

*Fields marked with an asterisk signify little to no change in semantics or access.

Media Conversion Table

Media V1Media V3
thumbnail.url-
thumbnail.width-
thumbnail.height-
thumbnail.format-
thumbnail.altText-
mediaType-
title and mediaType = IMAGEimage.fileName
title and mediaType = VIDEOvideo.filename
idimage.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].urlvideo.resolutions[i].url
video.files[i].widthvideo.resolutions[i].width
video.files[i].heightvideo.resolutions[i].height
video.files[i].formatvideo.resolutions[i].format
video.files[i].altText-
video.stillFrameMediaId-

Inventory Conversion Table

Inventory V1Inventory V3
product.variants[i].stock.trackQuantitytrackQuantity
product.variants[i].stock.quantitypreorderInfo.quantity
product.variants[i].stock.inStocktrackingMethod.inStock OR availabilityStatus depending on needs
Inventory V2Inventory Items V3Notes
id*id
productId*productId
trackQuantitytrackQuantityNow on the variant level
variants[i].variantIdvariantId
variants[i].inStocktrackingMethod.inStock
variants[i].quantitytrackingMethod.quantity
variants[i].availableForPreorderAvailabilityStatus = PREORDER
lastUpdatedupdatedDate
numericId-Was used for cursor paging - V3 Query & Search APIs support cursor paging out of the box
preorderInfo.enabledpreorderInfo.enabled
preorderInfo.messagepreorderInfo.message
preorderInfo.limitpreorderInfo.limit

Subscriptions Conversion Table

In V1 Subscriptions has its own APIs, where in V3 we don't have a dedicated API. Subscriptions exists directly in Product entity.

SubscriptionOption V1Product V3
idsubscriptionDetails.subscriptions[i].id
titlesubscriptionDetails.subscriptions[i].title
descriptionsubscriptionDetails.subscriptions[i].description
subscriptionSettings.frequencysubscriptionDetails.subscriptions[i].frequency
subscriptionSettings.intervalsubscriptionDetails.subscriptions[i].interval
subscriptionSettings.autoRenewalsubscriptionDetails.subscriptions[i].autoRenewal
subscriptionSettings.billingCyclessubscriptionDetails.subscriptions[i].billingCycles
discount.typesubscriptionDetails.subscriptions[i].discount.type
discount.valuesubscriptionDetails.subscriptions[i].discount.amountOff OR subscriptionDetails.subscriptions[i].discount.percentOff
SubscriptionOptionInProduct V1Product V3
idsubscriptionDetails.subscriptions[i].id
hiddensubscriptionDetails.subscriptions[i].visible
titlesubscriptionDetails.subscriptions[i].title
descriptionsubscriptionDetails.subscriptions[i].description
subscriptionSettings.frequencysubscriptionDetails.subscriptions[i].frequency
subscriptionSettings.intervalsubscriptionDetails.subscriptions[i].interval
subscriptionSettings.autoRenewalsubscriptionDetails.subscriptions[i].autoRenewal
subscriptionSettings.billingCyclessubscriptionDetails.subscriptions[i].billingCycles
discount.typesubscriptionDetails.subscriptions[i].discount.type
discount.valuesubscriptionDetails.subscriptions[i].discount.amountOff OR subscriptionDetails.subscriptions[i].discount.percentOff

Webhook Conversion Table

The following table shows Catalog V1 webhooks and their equivalents in Catalog V3 that are triggered at the same time:

Catalog V1Catalog V3
Product CreatedProduct Created
Product ChangedProduct Updated
Product DeletedProduct Deleted
Variants ChangedProduct Variant Updated
Collection CreatedCategory Created
Collection ChangedCategory Updated
Collection DeletedCategory Deleted

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 WebhooksCatalog V3 Webhooks
productId, collectionId, variants.variantIdAll webhook payloads - entityId
Product Changed - changedFieldsmodifiedFields
Product/Collection Created entity datacreatedEvent.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.

Did this help?