Articles in this section

Migrate your Shopify Products and Variants REST APIs to GraphQL

Shopify is deprecating the Product and Product variant REST APIs and recommends migrating to supported GraphQL APIs by February 1, 2025. Celigo has been granted a special extension, allowing support for this transition until April 1, 2025. However, we strongly recommend migrating to the new GraphQL APIs as early as possible to ensure a smooth and seamless transition. For more details about this Shopify update, refer to the deprecation timelines for the new GraphQL product APIs.

This article explains how to find deprecating endpoints/relative URLs in your existing flows and replace them. 

Product and Product variant deprecating endpoints

The following table lists the deprecating endpoints and their relative URLs.

Product endpoints 

Relative URLs 

Variant endpoints 

Relative URLs 

Creates a new product

/products.json

Creates a new product variant

/products/:_productId/variants.json

Updates a product

/products/:_productId.json

Modify an existing product variant

/variants/:_variantId.json

Create or Update product

/products/:_productId.json 

 /products.json

Create or Update product

/products/:_productId/variants/:_variantId.json

/products/:_productId/variants.json

Deletes a product

/products/:_productId.json

Remove a product variant from the database

/products/:_productId/variants/:_variantId.json

Retrieves a list of products

/products.json

Retrieves a list of product variants

/products/:_productId/variants.json

Retrieves a single product

/products/:_productId.json

Retrieves a single product variant

/variants/:_variantId.json

Retrieves a list of meta fields that belong to a product

/products/:_productId/metafields.json

Retrieves a list of meta fields that belong to a product variant

/products/:_productId/variants/:_variantId/metafields.json

Important information

  • For some of the listed GraphQL export queries, the ID (key field) value is defined in handlebars format as mentioned below:

    • gid://shopify/ProductVariant/{{provide_your_productVariant_ID}} 

    • gid://shopify/Product/{{provide_your_product_ID}} 

      Replace {{provide_your_product_ID}} with AFE handlebars to extract the value from the source application dynamically, such as  {{{data.0.ID}}} in AFE1.0 or {{{record.ID}}} in AFE2.0. 

  • Use the following terminology in GraphQL operations:

    • Exports: Referred to as Queries.

    • Imports: Referred to as Mutations (Create, Modify, or Delete).

  • Refer to the respective resources that are listed in the Predefined GraphQL queries section for missing property fields in the GraphQL queries which are built based on the REST API response and mapper.

  • Download and install the Shopify - Acumatica sample template for your reference which is attached at the end of this article.

Changes to make in Celigo integrator.io

Note

  • Before you update the flow, ensure to clone the flow as a backup or for reference.

  • Ensure your Shopify connection is configured with the (2024-10) API version or higher.

  1. Sign in to your Celigo integrator.io account.

  2. Navigate to Resources > Connections.

  3. Search for an existing Shopify connection. From the Actions overflow menu, select Used by. A list of all items that use this connection appears.

  4. Select your browser’s option to open the export or import in a new tab.

Sample export

  1. Navigate and expand the What would you like to export? section.

  2. In the Resource * setting, If you see Products: Product or Products: Product Variant [Deprecating], switch to HTTP view and update the following settings:

    1. HTTP method *: Select POST (don't update if POST has already been selected).

    2. Relative URI:  Enter/graphql.jsonfor all identified endpoints. (If you are using a universal HTTP connector, update all the identified relative URLs). While making this change in the export HTTP form, you may encounter these errors: Delta exports must use {{{lastExportDateTime}}} in either the relative URI or HTTP request bodyorThe paging method selected must use {{export.http.paging.{0}}} in either the relative URI or HTTP request body.To resolve this, update the Export type to ALLor remove the Paging method from Does this API use Paging?

    3. HTTP request body: Enter the GraphQL query listed Predefined GraphQL queries (exports), based on your requirements and the endpoint's functionality. For example, if the endpoint is Retrieves a list of products, add the following GraphQL query. 

    6a.png
    Newmap.png
  3. Expand Configure export type and update the following settings if you want to export all the data:

    1. Export type *: Select All - always export all data.

    2. Click Preview.

  4. Expand Non-standard API response patterns and update the following settings:

    1. Path to records in HTTP Response body: Update the resource path per the API response to get the correct Parsed output.

      For example, enter data.products.nodes to Retrieve the list of products (You can identify the path in the HTTP response in the following image.)  

      3.png
    2. Path to error field in HTTP response body : Enter errors[0].message. This field helps to return a successful HTTP status code and display errors if any.

      jj.png
  5. Click Save and close.

Sample import

  1. Navigate and expand the How would you like the records imported? section.

  2. In the Resource * setting, If you seeProducts: Product or Products: Product Variant [Deprecating], switch to HTTP view, and update the following settings:

    1. HTTP method *: SelectPOST(don't update if POST has already been selected).

    2. Relative URI:  Enter/graphql.jsonfor all identified endpoints.

    3. HTTP request body: Enter the GraphQL query listed in Predefined GraphQL queries (imports), based on your requirements and the endpoint's functionality. For example, if you want to create or update a product or product variant, you can achieve it with the following single GraphQL query.

      Mutations.png
      Import2.png
  3. Expand Non-standard API response patterns and update the following setting:

    1. Path to error field in HTTP response body: Enter errors[0].message. This field helps to return a successful HTTP status code and display errors if any.

      jj.png
  4. Click Save and close.

  5. Click Import mapping and switch to Mapper 2.0. (We provided a sample mapping that suits to create or update operations with the attached (at the end of this article) Acumatica-Shopify template.

    • For the Input object, if the ID field is present, the operation will update the existing record. If it is not present, the operation will create a new record after you run the flow.

    • In the mapping, you can also add more fields based on your requirements. For detailed information, see Shopify productset info.

      Mapper.png
  6. Click Save and Run the flow.

Limitations

  • GraphQL does not support identifying existing records or ignoring missing records for import endpoints.

  • Pagination functionality is not supported in the provided GraphQL queries.

Sample configuration videos (Acumatica - Shopify template)

The following video demonstrates the sample export configuration:

The following video demonstrates the sample import configuration:

Predefined GraphQL queries

Export queries

The following queries can be used to retrieve a product or product variant.

Retrieves a list of products: Add resourcePath as data.products.nodes.

{"query": "{ products(first: 10) { nodes { id title vendor handle tags status bodyHtml createdAt description productType updatedAt publishedAt templateSuffix variants(first: 10) { edges { node { id title price position taxable barcode sku createdAt displayName updatedAt inventoryPolicy inventoryQuantity presentmentPrices(first: 10) { nodes { price { amount currencyCode } compareAtPrice { amount currencyCode } } } image { id } product { id title } } } } options { id name position values } } }}"}

Retrieves a single product: Add resourcePath as data.product.

{"query": "{ product(id: \"gid://shopify/Product/{{Provide_your_productID}}\") { id title vendor handle tags status bodyHtml createdAt description productType updatedAt publishedAt templateSuffix variants(first: 10) { edges { node { id title price position taxable barcode sku createdAt displayName updatedAt inventoryPolicy presentmentPrices(first: 10) { nodes { price { amount currencyCode } compareAtPrice { amount currencyCode } } } image { id } product { id title } } } } options { id name position values } }}"}

Retrieves a list of meta fields that belong to a product: Add resourcePath as data.product.

{"query": "{ product(id: \"gid://shopify/Product/{{provide_your_product_ID}}\") { description metafields(first: 10) { nodes { createdAt description id key namespace ownerType type updatedAt value compareDigest jsonValue } } }}"}

Retrieves a list of product variants: Add resourcePath as data.productVariants.nodes.

{"query": "{ productVariants(first: 10, query: \"product_id:{{provide_your_product_id}}\") { nodes { createdAt compareAtPrice displayName id inventoryPolicy inventoryQuantity position price sku taxCode storefrontId taxable title updatedAt product { createdAt description id publishedAt status title tags updatedAt } inventoryItem { updatedAt sku id } image { id } presentmentPrices(first: 10) { edges { node { price { amount currencyCode } compareAtPrice { currencyCode } } } } } }}"}

Retrieves a single product variant: Add resourcePath as data.productVariant.

{"query": "{ productVariant(id: \"gid://shopify/ProductVariant/{{provide_your_productVariant_ID}}\") { id title availableForSale displayName barcode compareAtPrice createdAt inventoryPolicy inventoryQuantity position price sku taxCode taxable title updatedAt product { createdAt description id publishedAt status title tags updatedAt } inventoryItem { updatedAt sku id } image { id } presentmentPrices(first: 10) { edges { node { price { amount currencyCode } compareAtPrice { currencyCode } } } } }}"}

Retrieves a list of meta fields that belong to a product variant: Add resourcePath as data.productVariant.

{"query": "{ productVariant(id: \"gid://shopify/ProductVariant/{{provide_your_productVariant_id}}\") { metafields(first: 10) { nodes { createdAt compareDigest description id jsonValue key namespace ownerType type updatedAt value } } id createdAt displayName inventoryQuantity price sku title updatedAt }}"}

Import queries

The following Product queries can be used to create, update, or delete a product or product variant .

ProductSet: Create or update operation (the following query can be used to create or update a product or product variant in a single request).

{
"query": "mutation createEntireProduct($input: ProductSetInput!, $synchronous: Boolean!) { productSet(synchronous: $synchronous, input: $input) { product { id title description variants(first: 100) { nodes { id sku price compareAtPrice taxable taxCode barcode inventoryItem { id tracked } } } } productSetOperation { id product { id } status userErrors { field message } } userErrors { field message } } }",
 "variables": {{{jsonSerialize record}}}
}

 Deletes a product: 

{
  "query": "mutation productDelete($input: ProductDeleteInput!) { productDelete(input: $input) { deletedProductId userErrors { field message } }}",
   "variables": {{{jsonSerialize record}}}
}

Remove a product variant from the database: 

{
  "query": "mutation ProductVariantsDelete($productId: ID!, $variantsIds: [ID!]!) { productVariantsBulkDelete(productId: $productId, variantsIds: $variantsIds) { product { id title } userErrors { field message } }}",
   "variables": {{{jsonSerialize record}}}
}

Additional queries

The following Product queries can be used to create, update, or delete a product or product variant.

 Creates a new product:  

{
  "query": "mutation ProductCreate($input: ProductInput!) { productCreate(input: $input) { product { id description createdAt publishedAt status descriptionPlainSummary isGiftCard productType publicationCount tags title totalInventory totalVariants tracksInventory storefrontId updatedAt vendor variants(first: 10) { edges { node { createdAt displayName id inventoryPolicy price sku storefrontId taxCode title updatedAt presentmentPrices(first: 10) { nodes { price { amount currencyCode } compareAtPrice { currencyCode } } } image { id } } } } } userErrors { field message } }}",
   "variables": {{{jsonSerialize record}}}
}

 Updates a product:  

{
  "query": "mutation ProductUpdate($input: ProductInput!) { productUpdate(input: $input) { product { id description createdAt publishedAt status descriptionPlainSummary isGiftCard productType publicationCount tags title totalInventory totalVariants tracksInventory storefrontId updatedAt vendor variants(first: 10) { edges { node { createdAt displayName id inventoryQuantity inventoryPolicy price sku storefrontId taxCode title updatedAt presentmentPrices(first: 10) { nodes { price { amount currencyCode } compareAtPrice { currencyCode } } } image { id } } } } } userErrors { field message } }}",
   "variables": {{{jsonSerialize record}}}
}

To update a subset of variants, you can use any one of the following bulk variant mutations

Creates a new product variant: 

{
  "query": "mutation ProductVariantsCreate( $productId: ID! $variants: [ProductVariantsBulkInput!]!) { productVariantsBulkCreate(productId: $productId, variants: $variants) { product { createdAt description id legacyResourceId productType status tags title totalInventory vendor updatedAt } productVariants { createdAt displayName id inventoryItem { unitCost { amount } tracked } inventoryPolicy inventoryQuantity sku price product { id } title } userErrors { field message } }}",
  "variables": {{{jsonSerialize record}}}
}

Modify an existing product variant:  

{
  "query": "mutation productVariantsBulkUpdate($productId: ID!, $variants: [ProductVariantsBulkInput!]!) { productVariantsBulkUpdate(productId: $productId, variants: $variants) { productVariants { displayName defaultCursor createdAt id inventoryPolicy inventoryQuantity legacyResourceId price position requiresComponents sellableOnlineQuantity sellingPlanGroupCount sku taxCode title taxable updatedAt } product { createdAt description id legacyResourceId productType status tags title totalInventory vendor updatedAt } userErrors { field message } }}",
 "variables": {{{jsonSerialize record}}}
}
Was this article helpful?
1 out of 2 found this helpful

Comments

4 comments
Date Votes
  • Thanks for the article!

    What would happen to custom flows that will continue using deprecated REST endpoints after April 1? For example GET Products (retrieve a list of products).

    0
  • Hi Andrew, 

    We would highly recommend you to take immediate action and migrate to GraphQL APIs. We have added a bunch of references above, but please feel free to raise a support ticket if you need additional help.

    Best,

     

    0
  • This is a bit more complex then I understand. 

    0
  • Hey Pete, if you need help with switching to Shopify graphQL - feel free to contact andreyt@entechsolutions.com

    0

Please sign in to leave a comment.