> Note: > We're no longer publishing API release notes. Instead, you can find the latest updates on Shopify APIs in our [developer changelog](https://shopify.dev/changelog). You can filter updates by area. For example, you can filter API updates by the API name and version, such as GraphQL Admin API changes in version 2025-04.
The API version release date and the date that the version is no longer supported
Release date Date version is no longer supported
January 1, 2025 January 1, 2026
## Highlights Here are some highlights of version 2025-01 of Shopify's APIs: - **Automatic discounts**: The `minimumRequirement` field for both the [`DiscountAutomaticBasic`](/docs/api/admin-graphql/2025-01/objects/DiscountAutomaticBasic) and [`DiscountAutomaticFreeShipping`](/docs/api/admin-graphql/2025-01/objects/DiscountAutomaticFreeShipping) objects is now nullable, making minimum purchase conditions optional for automatic discounts. - **Bulk query operations**: The [`BulkOperationUserError`](/docs/api/admin-graphql/2025-01/objects/BulkOperationUserError) object has been updated with a new `UserError` GraphQL object type, which includes an additional `code` field. - **Fulfillment holds**: You can now place multiple holds on a fulfillment order. Each hold captures a specific issue independently, allowing you to release holds individually while maintaining other active holds. For detailed information on the changes, and how to upgrade to the 2025-01 version of the GraphQL Admin API, consult the [developer changelog](/changelog/apply-multiple-holds-to-a-single-fulfillment-order). - **Fulfillment services**: The default value for the `permitsSkuSharing` field on the [`fulfillmentServiceCreate`](/docs/api/admin-graphql/2025-01/objects/FulfillmentService) mutation is now set to `true`, allowing fulfillment services to stock inventory across multiple locations. - **JSON body support**: We now provide native support of a HTTP request body as a `JSON_body` for function external calls. Use this field when the `body` is in JSON format to reduce function instruction consumption and to ensure the `body` is formatted in logs. Don't use the `JSON_body` field together with the `body` field in the [`HttpResponse`](/docs/api/functions/reference/cart-checkout-validation/graphql/common-objects/httpresponse) object. If both are provided, then the `HttpResponse`'s `body` field takes precedence. If the `JSON_body` field is specified and no `Content-Type` header is included, then the header will automatically be set to `application/json`. - **Metafield admin access**: The `admin` field on the [`MetafieldAccessInput`](/docs/api/admin-graphql/2025-01/input-objects/MetafieldAccessInput#field-admin) and [`MetafieldAccessUpdateInput`](/docs/api/admin-graphql/2025-01/input-objects/MetafieldAccessUpdateInput#field-admin) objects is now optional. In API version 2024-10 and prior, this field was required. - **Metafield storefront visibility**: Several related objects, mutations, queries, and fields have been removed. Use the `access` field on the [`MetafieldDefinition`](/docs/api/admin-graphql/2025-01/objects/MetafieldDefinition) object instead. - **Multi-location shop feature**: The deprecated `multiLocation` field has been removed from the [`ShopFeatures`](/docs/api/admin-graphql/2025-01/objects/ShopFeatures) object. Use the [`locationsCount`](/docs/api/admin-graphql/2025-01/queries/locationsCount) query to determine the number of shop locations. - **New metafieldsDelete mutation**: We've replaced the [`metafieldDelete`](/docs/api/admin-graphql/2024-10/mutations/metafieldDelete) mutation with the [`metafieldsDelete`](/docs/api/admin-graphql/2025-01/mutations/metafieldsDelete) mutation. This change provides a fundamental update in how you delete metafields. By using `metafieldsDelete`, you need to adjust your code to accommodate for a new identifier format. - **Product handle uniqueness validation**: The `handle` field on the [`ProductInput`](/docs/api/admin-graphql/2025-01/input-objects/ProductInput) input object is now validated for uniqueness, preventing collisions when creating or updating product handles. ## Breaking changes These changes require special attention. If your app uses these API resources, and you don’t adjust your usage of the resources according to the following instructions, then your app might break when you update to this API version. ### Automatic discounts We've changed the [`minimumRequirement`](/docs/api/admin-graphql/2025-01/objects/DiscountAutomaticBasic#field-minimumrequirement) field for both the [`DiscountAutomaticBasic`](/docs/api/admin-graphql/2025-01/objects/DiscountAutomaticBasic) object and [`DiscountAutomaticFreeShipping`](/docs/api/admin-graphql/2025-01/objects/DiscountAutomaticFreeShipping) object to be nullable. Previously, merchants were required to specify minimum purchase conditions on product, order, and free shipping automatic discounts. We're now making these conditions optional, so the [`minimumRequirement`](/docs/api/admin-graphql/2025-01/objects/DiscountAutomaticFreeShipping#field-minimumrequirement) field can return a `null` value. ### Bulk query operations In the Admin API, we have improved the [`BulkOperationUserError`](/docs/api/admin-graphql/2025-01/objects/BulkOperationUserError) object by introducing a new [`code`](/docs/api/admin-graphql/2025-01/objects/BulkOperationUserError#field-code) field for the `userErrors` returned by the [`bulkOperationRunQuery`](/docs/api/admin-graphql/2025-01/mutations/bulkOperationRunQuery#field-bulkoperationrunquerypayload-usererrors) mutation. The new `code` field allows for improved error handling while retaining all the previous fields. We have also made the [`BulkOperationUserError`](/docs/api/admin-graphql/2025-01/objects/BulkOperationUserError) type public, enabling developers to access this updated error information. ### Customer payloads in webhook topics We've changed how a customer is represented in webhooks: - Removed the `tags` field. Use the [`CUSTOMER_TAGS_ADDED`](/docs/api/admin-graphql/2025-01/enums/WebhookSubscriptionTopic#value-customertagsadded) and [`CUSTOMER_TAGS_REMOVED`](/docs/api/admin-graphql/2025-01/enums/WebhookSubscriptionTopic#value-customertagsremoved) webhook topics instead. - Removed the `email_marketing_consent` field. Use the [`CUSTOMERS_EMAIL_MARKETING_CONSENT_UPDATE`](/docs/api/admin-graphql/2025-01/enums/WebhookSubscriptionTopic#value-customersemailmarketingconsentupdate) webhook topic instead. - Removed the `sms_marketing_consent` field. Use the [`CUSTOMERS_MARKETING_CONSENT_UPDATE`](/docs/api/admin-graphql/2025-01/enums/WebhookSubscriptionTopic#value-customersmarketingconsentupdate) webhook topic instead. - Removed the `last_order_id`, `last_order_name`, `total_spent`, and `orders_count` fields. Use the [`CUSTOMERS_PURCHASING_SUMMARY`](/docs/api/admin-graphql/2025-01/enums/WebhookSubscriptionTopic#value-customerspurchasingsummary) webhook topic instead. The following [webhook topics](/docs/api/admin-graphql/2025-01/enums/WebhookSubscriptionTopic) contain a customer payload: - `CHECKOUTS_CREATE` - `CHECKOUTS_UPDATE` - `CUSTOMERS_CREATE` - `CUSTOMERS_DELETE` - `CUSTOMERS_DISABLE` - `CUSTOMERS_ENABLE` - `CUSTOMERS_UPDATE` - `DRAFT_ORDERS_CREATE` - `DRAFT_ORDERS_UPDATE` - `ORDERS_CANCELLED` - `ORDERS_CREATE` - `ORDERS_FULFILLED` - `ORDERS_PAID` - `ORDERS_PARTIALLY_FULFILLED` - `ORDERS_UPDATED` ### Customer payment methods We've hidden the [`customerPaymentMethodRemoteCreditCardCreate`](/docs/api/admin-graphql/2025-01/mutations/customerPaymentMethodRemoteCreditCardCreate) mutation, as it has been deprecated for more than three years. You can use the [`customerPaymentMethodRemoteCreate`](/docs/api/admin-graphql/2025-01/mutations/customerPaymentMethodRemoteCreate) mutation instead to manage customer payment methods. Learn more about [payment processing](/docs/apps/build/payments/processing). **Developer action required** - The [`stripePaymentMethodId`](/docs/api/admin-graphql/2025-01/mutations/customerpaymentmethodremotecreditcardcreate#argument-stripepaymentmethodid) argument is now required. Update your code to accommodate this change. - Transition away from using the [`customerPaymentMethodRemoteCreditCardCreate`](/docs/api/admin-graphql/2025-01/mutations/customerpaymentmethodremotecreditcardcreate) mutation by January 2026. We'll fully remove this mutation after January 2026, following its complete deprecation in the 2025-01 API version. This mutation was primarily intended for creating payment methods using credit cards stored by Stripe. If the customer IDs you request are invalid, then the method returns a user error. ### Fulfillment hold access We've introduced validation for fulfillment hold access in node queries. This change only affects apps which fetch fulfillment holds using a [`node` or `nodes` GraphQL query](/docs/api/admin-graphql/2025-01/objects/FulfillmentHold#interface-node). If your app doesn't currently have sufficient access scopes as defined below then you need to request the correct access scopes before migrating to the 2025-01 API version. When using a `node` or `nodes` query to fetch holds, if your app doesn't have sufficient access, then a `null` value is returned for any fulfillment holds that you don't have access to. Refer to the API access scopes section of the [`FulfillmentOrder`](/docs/api/admin-graphql/2025-01/objects/FulfillmentOrder) object for more information about access scopes. **Developer action required** Apps using the `node` or `nodes` GraphQL queries to fetch fulfillment holds will only retrieve those associated with fulfillment orders for which they have access: | Access scope | What you can access | |-----------------------------------------------------|-----------------------------------------------------------------| | `read_merchant_managed_fulfillment_orders` | Holds on fulfillment orders assigned to a merchant-managed location | | `read_assigned_fulfillment_orders` | Holds on fulfillment orders assigned to locations owned by your app | | `read_third_party_fulfillment_orders` | Holds on fulfillment orders assigned to a third-party location | | `read_marketplace_fulfillment_orders` | Holds on fulfillment orders that belong to one of your marketplace's orders | For more information, refer to the [changelog](/changelog/update-to-fulfillmenthold-heldbyapp-field-from-fulfillmenthold-heldby-field). ### Fulfillment hold field replacement We've added the new [`heldByApp`](/docs/api/admin-graphql/2025-01/objects/FulfillmentHold#field-heldbyapp) object field on the [FulfillmentHold](/docs/api/admin-graphql/2025-01/objects/FulfillmentHold#top) object, replacing the [`heldBy`](/docs/api/admin-graphql/2024-10/objects/FulfillmentHold#field-heldby) string field. **Developer action required** The [`heldByApp`](/docs/api/admin-graphql/2025-01/objects/FulfillmentHold#field-heldbyapp) field provides access to all attributes of the [`App`](/docs/api/admin-graphql/2025-01/objects/App) object, in contrast to the deprecated `heldBy` field, which only indicated the app's title. If you currently query `fulfillmentHold.heldBy`, then transition to querying `fulfillmentHold.heldByApp.title`. ### Fulfillment holds You can now place multiple holds on a fulfillment order. Each hold captures a specific issue independently, allowing you to release holds individually while maintaining other active holds. For detailed information on the changes, and how to upgrade to the 2025-01 version of the GraphQL Admin API, consult the [developer changelog](/changelog/apply-multiple-holds-to-a-single-fulfillment-order). ### Fulfillment services The default value of the [`permitsSkuSharing`](/docs/api/admin-graphql/2025-01/objects/FulfillmentService#field-permitsskusharing) field on the [`fulfillmentServiceCreate` mutation](/docs/api/admin-graphql/2025-01/objects/FulfillmentService#top) is now `true`. If `permitsSkuSharing` is `true`, then a fulfillment service can stock inventory at multiple fulfillment services or merchant-managed locations. ### Gift card visibility We've changed the `paymentMethods` field within the [`Input`](/docs/api/functions/reference/payment-customization/graphql/input) object of the [`PaymentCustomizationApi`](/docs/api/functions/reference/payment-customization/graphql). This feature enhances the flexibility of payment processing by enabling merchants to configure the visibility of gift cards based on specific conditions. > Note: > The [`PaymentCustomizationPaymentMethodPlacement`](/docs/api/functions/reference/payment-customization/graphql/common-objects/paymentcustomizationpaymentmethodplacement) enum contains the `PAYMENT_METHOD` values. ### Localized fields You can now use [localized fields](/docs/apps/build/markets/add-locally-required-order-data) in Checkout UI extensions and Shopify Functions to implement custom validation for tax fields in checkout. You can apply checkout error targets to custom tax fields for precise error messages. We've added the [`HasLocalizedFields`](/docs/api/admin-graphql/2025-01/interfaces/HasLocalizedFields) interface. We've also renamed the `localizationExtensions` field to `localizedFields` on the following types: - [`DraftOrderInput`](/docs/api/admin-graphql/2025-01/input-objects/DraftOrderInput#field-localizedfields) - [`input` argument on `OrderUpdate`](/docs/api/admin-graphql/2025-01/mutations/orderUpdate#argument-input) ### Metafield admin access The `admin` field on the [`MetafieldAccessInput`](/docs/api/admin-graphql/2025-01/input-objects/MetafieldAccessInput#field-admin) and [`MetafieldAccessUpdateInput`](/docs/api/admin-graphql/2025-01/input-objects/MetafieldAccessUpdateInput#field-admin) objects is now optional. In API version 2024-10 and prior, this field was required. The `admin` field governs access to metafields. If you don't explicitly set the field, then the behavior works the same as if the field was omitted. Learn more about [metafield access controls](/docs/apps/build/custom-data/permissions). ### Metafield and metaobject permissions We're simplifying how metafield and metaobject permissions work to improve API response times. We've removed private and public permissions for [app-reserved metafields and metaobjects](/docs/apps/build/custom-data/ownership#reserved-prefixes) from all mutations: - Removed `PRIVATE`, `PUBLIC_READ`, and `PUBLIC_READ_WRITE` values from app-reserved [metafield](/docs/api/admin-graphql/2025-01/enums/MetafieldAdminAccessInput) and [metaobject](/docs/api/admin-graphql/2025-01/enums/MetaobjectAdminAccessInput) enums. - Removed the `LEGACY_LIQUID_ONLY` value from app-reserved [metafield](/docs/api/admin-graphql/2025-01/enums/MetafieldAdminAccess) and [metaobject](/docs/api/admin-graphql/2025-01/enums/MetaobjectAdminAccess) enums. For more information on upcoming changes to metafields and metaobjects, refer to the [developer changelog](/changelog/simplifying-how-metafield-and-metaobject-permissions-work). ### Metafield definition capabilities We're sharing a consistent configuration pattern for capabilities between metafield and metaobject definitions, to unify and simplify how you enable optional features across custom data. To implement metafield definition capabilities, we've made the following changes:
Additions to metafield definition capabilities
Name Type/field Change
useAsCollectionCondition Field Removed. Use the capabilities.smartCollectionCondition field instead. For more information, refer to the developer changelog.
capabilities Field Added to standardMetafieldDefinitionEnable mutation
capabilities Field Added to standardMetafieldDefinitionsEnable mutation
INVALID_CAPABILITY Error code Added to the MetafieldDefinitionCreateUserErrorCode and MetafieldDefinitionUpdateUserErrorCode enums.
TYPE_NOT_ALLOWED_FOR_CONDITIONS Error code Added to the MetafieldDefinitionCreateUserErrorCode and MetafieldDefinitionUpdateUserErrorCode enums.
### Metafield storefront visibility We've removed several `MetafieldStorefrontVisibility` related objects, mutations, queries, and fields:
Removals of MetafieldStorefrontVisibility-related types
Name Type Change
MetafieldStorefrontVisibility Object Removed. Use the access field on the MetafieldDefinition object instead.
metafieldStorefrontVisibilityCreate Mutation Removed. Use the metafieldDefinitionUpdate mutation instead.
metafieldStorefrontVisibilityDelete Mutation Removed. Use the metafieldDefinitionUpdate mutation instead.
metafieldStorefrontVisibilities Query Removed. Use the access field on the MetafieldDefinition object instead.
metafieldStorefrontVisibility Query Removed. Use the access field on the MetafieldDefinition object instead.
visibleToStorefrontApi Field on MetafieldDefinition object Removed. Use the access field on the MetafieldDefinition object instead.
visibleToStorefrontApi Field on MetafieldDefinitionInput input object Removed. Use the access field on the MetafieldDefinitionInput input object instead.
visibleToStorefrontApi Field on MetafieldDefinitionUpdateInput input object Removed. Use the access field on the MetafieldDefinitionUpdateInput input object instead.
### Metafields remove private We've removed the [`PrivateMetafield`](/docs/api/admin-graphql/2024-10/objects/PrivateMetafield) from the public GraphQL Admin API, changing how `metafields` are implemented and used across stores. **Developer action required** - The [`PrivateMetafield`](/docs/api/admin-graphql/2024-10/queries/privateMetafield) was removed from the public GraphQL Admin API. Use [`app-data` metafields](/docs/apps/build/custom-data/metafields/use-app-data-metafields) instead. - If the `metafield` is needed per resource, refer to the migration guide for using [`app-reserved` namespaces](/docs/apps/build/custom-data/ownership#reserved-prefixes). ### Multi-location shop feature We've removed the deprecated [`multiLocation`](/docs/api/admin-graphql/2024-10/objects/ShopFeatures#field-multilocation) field from the `ShopFeatures` object. Use the [`locationsCount`](/docs/api/admin-graphql/2025-01/queries/locationsCount) query instead to determine the number of shop locations. ### Payments bank account remove fields We've cleaned up the GraphQL Admin API `ShopifyPaymentsBankAccount` object and removed the following fields that weren't being used by third-party apps: - [`accountNumber`](/docs/api/admin-graphql/2024-10/objects/shopifypaymentsbankaccount#field-accountnumber) - [`routingNumber`](/docs/api/admin-graphql/2024-10/objects/shopifypaymentsbankaccount#field-routingnumber) ### Payment extensions [Payments extensions](/docs/apps/build/payments/offsite/use-the-cli?framework=remix#create-a-payments-extension) that support vaulting have been improved to enable the processing of Three-Domain Secure (3DS) challenges for verifications. - A new mutation, [`VerificationSessionRedirect`](/docs/api/payments-apps/2025-01/mutations/verificationSessionRedirect), is introduced. - New arguments have been added to the existing [`VerificationSessionResolve`](/docs/api/payments-apps/2025-01/mutations/verificationSessionResolve) and [`VerificationSessionReject`](/docs/api/payments-apps/2025-01/mutations/verificationSessionReject) mutations. **Developer action required** For payments extensions that support vaulting, we strongly recommend that you update to the 2025-01 version as soon as possible. You also need to consider the following actions: - If 3DS is required for a verification, you must use the `VerificationSessionRedirect` mutation. - When resolving or rejecting a verification that required 3DS, pass the `authentication` argument to either the `VerificationSessionResolve` or `VerificationSessionReject` mutation. - We're also deprecating the following `VerificationSessionStateReason`: `REQUIRED_3DS_CHALLENGE`. Use the new `VerificationSessionRedirect` mutation instead. ### Price lists We've removed the following values on the [`PriceListUserErrorCode`](/docs/api/admin-graphql/2025-01/enums/PriceListUserErrorCode) enum that aren't currently returned by the GraphQL Admin API: - `CONTEXT_RULE_COUNTRIES_LIMIT` - `CONTEXT_RULE_COUNTRY_TAKEN` - `CONTEXT_RULE_LIMIT_REACHED` - `CONTEXT_RULE_MARKET_NOT_FOUND` - `CONTEXT_RULE_MARKET_TAKEN` - `COUNTRY_CURRENCY_MISMATCH` - `CURRENCY_COUNTRY_MISMATCH` - `MARKET_CURRENCY_MISMATCH` ### Product handle uniqueness validation The [`handle`](/docs/api/admin-graphql/2025-01/input-objects/ProductInput#field-handle) field on the `ProductInput` input object is now validated for uniqueness. This enhancement ensures that there are no collisions when creating or updating product handles. The change doesn't affect existing behavior when a `handle` isn't provided as input. ### Product image deprecate We have changed the REST Admin API for the [product image resource](/docs/api/admin-rest/2024-10/resources/product-image) so that it returns a [`media image id`](/docs/api/storefront/2025-01/objects/MediaImage#field-id) instead of a product image GID. This is designed to make it easier to migrate to GraphQL from REST when interfacing with product images that were created before the introduction of a unified media ID. **Developer action required** Use `medias.id` instead of `medias.legacy_id`/`product_images.id` for the admin_graphql_api_id. Previously, the `admin_graphql_api_id` returned a product image ID: `"gid://shopify/ProductImage/43701248884792"` Now, the `admin_graphql_api_id` returns a media image ID: `"gid://shopify/MediaImage/12379812379123"` This change will only affect clients using the latest 2025-01 API version. Older versions will continue to return the `ProductImage GID`, ensuring backward compatibility. It's strongly recommended that you upgrade to using GraphQL, as REST is nearing deprecation. ### Reverse fulfillment orders The [`order`](/docs/api/admin-graphql/2025-01/objects/ReverseFulfillmentOrder#field-order) field on the `ReverseFulfillmentOrder` object is now nullable. An order can be nullable if the app meets any of the following conditions: - The app doesn't have the [`read_all_orders`](/docs/api/usage/access-scopes#orders-permissions) access scope. - The order is older than 60 days. - The order no longer exists. In API versions prior to 2025-01, the `order` field returns a GraphQL error when the order isn't available. ### Shop fields We've removed the following unused fields on the `Shop` object: - [`collectionSavedSearches`](/docs/api/admin-graphql/2024-10/objects/Shop#connection-collectionsavedsearches). Use [`QueryRoot.collectionSavedSearches`](/docs/api/admin-graphql/2025-01/queries/collectionSavedSearches) instead. - [`draftOrderSavedSearches`](/docs/api/admin-graphql/2024-10/objects/Shop#connection-draftordersavedsearches). Use [`QueryRoot.draftOrderSavedSearches`](/docs/api/admin-graphql/2025-01/queries/draftOrderSavedSearches) instead. - [`marketingEvents`](/docs/api/admin-graphql/2024-10/objects/Shop#connection-marketingevents). Use [`QueryRoot.marketingEvents`](/docs/api/admin-graphql/2025-01/queries/marketingEvents) instead. - [`orderSavedSearches`](/docs/api/admin-graphql/2024-10/objects/Shop#connection-ordersavedsearches). Use [`QueryRoot.orderSavedSearches`](/docs/api/admin-graphql/2025-01/queries/orderSavedSearches) instead. - [`productByHandle`](/docs/api/admin-graphql/2024-10/objects/Shop#field-productbyhandle). Use [`QueryRoot.productByHandle`](/docs/api/admin-graphql/2025-01/queries/productByHandle) instead. - [`productSavedSearches`](/docs/api/admin-graphql/2024-10/objects/Shop#connection-productsavedsearches). Use [`QueryRoot.productSavedSearches`](/docs/api/admin-graphql/2025-01/queries/productSavedSearches) instead. - [`uploadedImagesByIds`](/docs/api/admin-graphql/2024-10/objects/Shop#connection-uploadedimagesbyids). Use the [`files`](/docs/api/admin-graphql/2025-01/queries/files) query instead. ### Script tag display scopes We've reduced the available options for where a script is included when you create or update script tags. This change is related to the upcoming deprecation of script tags for the Thank you and Order status pages on August 28, 2025. [Learn more](/docs/apps/build/online-store/blocking-script-tags) about upcoming changes, key dates, and actions that you're required to take related to the deprecation of script tags. The only valid value for the [`displayScope`](/docs/api/admin-graphql/2025-01/input-objects/ScriptTagInput#field-displayscope) field on the `ScriptTagInput` input object is now `ONLINE_STORE`. The `displayScope` field remains optional. When you omit this field from the [`scriptTagCreate`](/docs/api/admin-graphql/2025-01/mutations/scriptTagCreate) mutation, the value defaults to `ONLINE_STORE`. Review the following next steps based on how you currently use script tags:
Script tag display scope usage and recommended alternatives
If you use... ...Then use this instead
UI customizations Upgrade to Checkout Extensibility
Analytics and conversion tracking Upgrade to web pixels
Online store Update the displayScope value to ONLINE_STORE
## GraphQL Admin API changes Version 2025-01 of the GraphQL Admin API introduces the following changes:

We've added the customizations fields, merchandiseThumbnail.fit and merchandiseThumbnail.badge.background, to the CheckoutBrandingInput input object. You can now adjust the aspect ratio and image fit for product thumbnails, as well as the quantity badge background colors to align with your brand.

We've added the OrderCreateUpsertCustomerAttributesInput input object that contains the input fields for creating a new customer object or for identifying an existing customer to update and associate with the order. We also added the toUpsert input field to the orderCreate mutation, at order.customer.toUpsert. You can now create a new customer or update an existing customer when you create an order.

We've changed the minimumRequirement field for both the DiscountAutomaticBasic object and DiscountAutomaticFreeShipping object to be nullable. Previously, merchants were required to specify minimum purchase conditions on product, order, and free shipping automatic discounts. We're now making these conditions optional, so the minimumRequirement field can return a null value.

We've improved the BulkOperationUserError object by introducing a new code field for the userErrors returned by the bulkOperationRunQuery mutation. The new code field allows for improved error handling while retaining all the previous fields. We have also made the BulkOperationUserError type public, enabling developers to access this updated error information.

We've added two new fields to represent product bundles, allowing you to accurately nest component products under the parent product in a grouped view.

  • The [components](/docs/api/admin-graphql/2025-01/objects/AbandonedCheckoutLineItem#field-components) field has been added to the AbandonedCheckoutLineItem object. Use this field to define the component products within a product bundle, ensuring a grouped view in Abandoned Checkout Emails.

  • The group field has been added to the [LineItem] object. Use this field to indicate that line item products are a part of a product bundle, ensuring a grouped view in Orders Detail Pages.

In addition, these fields can help you display product bundles in a grouped view in transactional emails, such as order confirmations and shipping updates. Learn how you can implement a grouped view by following this tutorial.

We've added the customizations fields, merchandiseThumbnail.fit and merchandiseThumbnail.badge.background, to the CheckoutBrandingInput input object. You can now adjust the aspect ratio and image fit for product thumbnails, as well as the quantity badge background colors to align with your brand.

We've added the BusinessEntity object, which represents the formal and legal structure under which a merchant operates their business.

You can use the businessEntities query to retrieve information about business entities that are enabled on a merchant's shop.

The MISSING_OPTIONS_VALUE error code value has been added to the CombinedListingUpdateUserErrorCode enum. This error code is returned when the optionsAndValues field is empty.

We've added the taxExemptions and taxRegistrationId fields on the CompanyLocationTaxSettings object. As a result, we've deprecated these fields from the root of the CompanyLocation object.

Additionally, we've introduced a companyLocationTaxSettingsUpdate mutation for updating tax_exempt, taxExemptions, and taxRegistrationId for a company location. You should use this mutation in place of the following deprecated fields:

You can now use the metafieldDefinitionCreate and metafieldDefinitionUpdate mutations to create and edit conditional metafield definitions.

Conditional metafield definitions are definitions with constraints, which allow metafield definitions to be applied to a subset of resources. For example, each category metafield comes with a set of constraints that determine what product categories the metafield applies to. Currently, Shopify supports only product category constraints on product metafield definitions.

To implement conditional metafield definitions, the following types and fields have been added:

New types and fields for managing conditional metafield definitions
Name Type Change
MetafieldDefinitionConstraintsInput Input object Added
MetafieldDefinitionConstraintsUpdatesInput Input object Added
constraints Field Added to MetafieldDefinitionInput input object
constraintsUpdates Field Added to MetafieldDefinitionUpdateInput input object
deleteConflictingConstrainedMetafields deleteConflictingConstrainedMetafields Field Added to ProductUpdateInput input object
linkedMetafieldValue Field Added to VariantOptionValueInput input object
INVALID_CONSTRAINTS Error code Added to MetafieldDefinitionCreateUserErrorCode enum
INVALID_CONSTRAINTS Error code Added to MetafieldDefinitionUpdateUserErrorCode enum

We've added custom ID and upsert support to enhance data management across platforms. Use the custom ID support to assign unique identifiers to resources and look up the resource by the custom ID. This simplifies the synchronization process and reduces data inconsistencies. Concurrently, you can use the upsert to either create or update a resource based on a matching key, reducing the number of API calls required.

  • For custom IDs: You can create and manage custom IDs for any data type that has metafield support. Refer to metafieldDefinitionCreate and identifier.customId for details about defining the metafield definition id and the key, namespace, and value input fields used in creating a metafield ID.
  • For upserts - We've made two APIs available that allow upserting by a matching key. For products, use productSet and for customers use customerSet. You cannot yet use a custom ID as a matching key for upserting.

We've changed how a customer is represented in webhooks:

The following webhook topics contain a customer payload:

  • CHECKOUTS_CREATE
  • CHECKOUTS_UPDATE
  • CUSTOMERS_CREATE
  • CUSTOMERS_DELETE
  • CUSTOMERS_DISABLE
  • CUSTOMERS_ENABLE
  • CUSTOMERS_UPDATE
  • DRAFT_ORDERS_CREATE
  • DRAFT_ORDERS_UPDATE
  • ORDERS_CANCELLED
  • ORDERS_CREATE
  • ORDERS_FULFILLED
  • ORDERS_PAID
  • ORDERS_PARTIALLY_FULFILLED
  • ORDERS_UPDATED

We've hidden the customerPaymentMethodRemoteCreditCardCreate mutation, as it has been deprecated for more than three years. You can use the customerPaymentMethodRemoteCreate mutation instead to manage customer payment methods.

Learn more about payment processing.

Developer action required

We've added a subscriptionContracts connection to the Order object. This connection lets you query subscription contracts associated with a specific order, making it easier to manage customer subscriptions.

We've added the DeliveryPromiseSetting object, which stores information about when customers can expect to receive their orders. With this addition you can do the following:

We’ve also added the delivery_promise_settings/update webhook topic so that your app can be notified when a delivery promise setting is updated.

We've added the following new fields and error messages for managing discounts:

New fields and error messages for managing discounts
Name Type Change
appliesOnOneTimeSubscription Field Added to DiscountAutomaticAppInput input object
appliesOnOneTimePurchase Field Added to DiscountAutomaticApp input object
appliesOnOneTimePurchase Field Added to DiscountCodeApp object
appliesOnOneTimePurchase Field Added to DiscountCodeAppInput input object
appliesOnSubscription Field Added to DiscountCodeAppInput input object
appliesOnSubscription Field Added to DiscountCodeApp object
APPLIES_ON_ONE_TIME_PURCHASE_AND_SUBSCRIPTION_BOTH_FALSE Error code Added to DiscountErrorCode enum
MULTIPLE_RECURRING_CYCLE_LIMIT_FOR_NON_SUBSCRIPTION_ITEMS_CONSTRAINTS Error code Added to DiscountErrorCode enum
recurringCycleLimit Field Added to DiscountCodeAppInput input object
RECURRING_CYCLE_LIMIT_NOT_A_VALID_INTEGER Error code Added to PriceRuleErrorCode enum
RECURRING_CYCLE_LIMIT_NOT_A_VALID_INTEGER Error code Added to DiscountErrorCode enum

We've added a new code filter parameter to the discountNodes query, allowing you to filter discounts by their associated discount codes.

We've added the priceOverride field on the DraftOrderLineItemInput input object. This latest enhancement enables you to use the field to customize pricing at the draft order level. You can specify a price override for the line item, which will replace the product variant's catalog price for that draft order. This functionality allows for greater flexibility in managing pricing directly at the draft order level:

  • Use the priceOverride field to customize pricing at the draft order level.
  • Specify a price override for the line item, which will replace the product variant's catalog price for that draft order.

You need to handle currency conversion and understand the restrictions concerning bundles. Price overrides cannot be applied to bundles or their components. If a line item is included in a bundle, any price override will be removed.

We've added new error codes to the SubmissionErrorCode enum. These enhancements provide clearer feedback when issues occur during the cart submission process. The new error codes enhance the detail and clarity of error responses when cart submission fails.

We've added the variantId field to the CalculateExchangeLineItemInput input object. You can use this field to set the ID of the product variant to be added to the order as part of an exchange.

We've introduced validation for fulfillment hold access in node queries. This change only affects apps which fetch fulfillment holds using a node or nodes GraphQL query. If your app doesn't currently have sufficient access scopes as defined below then you need to request the correct access scopes before migrating to the 2025-01 API version.

When using a node or nodes query to fetch holds, if your app doesn't have sufficient access, then a null value is returned for any fulfillment holds that you don't have access to. Refer to the API access scopes section of the FulfillmentOrder object for more information about access scopes.

Developer action required

Apps using the node or nodes GraphQL queries to fetch fulfillment holds will only retrieve those associated with fulfillment orders for which they have access:

Access scope What you can access
read_merchant_managed_fulfillment_orders Holds on fulfillment orders assigned to a merchant-managed location
read_assigned_fulfillment_orders Holds on fulfillment orders assigned to locations owned by your app
read_third_party_fulfillment_orders Holds on fulfillment orders assigned to a third-party location
read_marketplace_fulfillment_orders Holds on fulfillment orders that belong to one of your marketplace's orders

We've added the new heldByApp object field on the FulfillmentHold object, replacing the heldBy string field.

Developer action required

The heldByApp object field provides access to all attributes of the App object, in contrast to the deprecated heldBy field, which only indicated the app's title.

If you currently query fulfillmentHold.heldBy, you should transition to querying fulfillmentHold.heldByApp.title.

For more information, refer to the changelog.

You can now place multiple holds on a fulfillment order. Each hold captures a specific issue independently, allowing you to release holds individually while maintaining other active holds. For detailed information on the changes, and how to upgrade to the 2025-01 version of the GraphQL Admin API, consult the developer changelog.

The default value of the permitsSkuSharing field on the fulfillmentServiceCreate mutation is now true. If permitsSkuSharing is true, then a fulfillment service can stock inventory at multiple fulfillment services or merchant-managed locations.

We've added the SHIPPING_CREDENTIAL_MX extension key to the LocalizationExtensionKey enum. Use this extension key to retrieve the shipping credentials for cross-border shipments to Mexico.

You can now use localized fields in Checkout UI extensions and Shopify Functions to implement custom validation for tax fields in checkout. You can apply checkout error targets to custom tax fields for precise error messages.

We've added the HasLocalizedFields interface. We've also renamed the localizationExtensions field to localizedFields on the following types:

We've added the location_id filter to the locations query. The location ID allows you to specify the location where the physical good resides. If no ID is specified, then the primary location is used.

We’ve added the manualPaymentGateway field to the OrderTransaction object. The manualPaymentGateway field indicates whether the transaction is processed by a manual payment gateway.

For more information about manual payments, refer to Manual payment methods.

The admin field on the MetafieldAccessInput and MetafieldAccessUpdateInput objects is now optional. In API version 2024-10 and prior, this field was required.

The admin field governs access to metafields. If the field isn't explicitly set, then the behavior works the same as if the field was omitted.

Learn more about metafield access controls.

Metafields input query variables are now subject to additional validation across all Function APIs. Previously, if these metafields didn't contain properly formatted data, we treated them as empty. This could lead to situations where it was difficult to determine why a function wasn't receiving the expected input data.

Now, an invalid metafield will result in an InvalidVariableValueError when attempting to run the function. For more information, refer to the list of errors.

-->

We've removed the PrivateMetafield from the public GraphQL Admin API, changing how metafields are implemented and used across stores.

Developer action required

We're simplifying how metafield and metaobject permissions work to improve API response times.

We've removed private and public permissions for app-reserved metafields and metaobjects from all mutations:

  • Removed PRIVATE, PUBLIC_READ, and PUBLIC_READ_WRITE values from app-reserved metafield and metaobject enums.

  • Removed the LEGACY_LIQUID_ONLY value from app-reserved metafield and metaobject enums.

For more information on upcoming changes to metafields and metaobjects, refer to the developer changelog.

We're sharing a consistent configuration pattern for capabilities between metafield and metaobject definitions, to unify and simplify how you work with custom data.

Additions to metafield definition capabilities
Name Type/field Change
useAsCollectionCondition Field Removed. Use the capabilities.smartCollectionCondition field instead. For more information, refer to the developer changelog.
capabilities Field Added to standardMetafieldDefinitionEnable mutation
capabilities Field Added to standardMetafieldDefinitionsEnable mutation
INVALID_CAPABILITY Error code Added to the MetafieldDefinitionCreateUserErrorCode and MetafieldDefinitionUpdateUserErrorCode enums.
TYPE_NOT_ALLOWED_FOR_CONDITIONS Error code Added to the MetafieldDefinitionCreateUserErrorCode and MetafieldDefinitionUpdateUserErrorCode enums.

You can now use the MetafieldCapabilityUniqueValues object and MetafieldCapabilityUniqueValuesInput input object to retrieve metafield definitions that enforce uniqueness. You can use this capability to ensure that each metafield has a unique value across all resources. Currently, you can only enforce uniqueness on metafield definitions that don’t yet have associated metafields.

You can enforce uniqueness for the following data types:

  • single_line_text_field
  • number_integer
  • url
  • id

We've removed the metafieldDelete mutation and replaced it with the metafieldsDelete mutation. The former mutation relies on the Metafield group identifier (gid), while the latter takes an array of MetafieldIdentifier fields composed of key, namespace, and ownerId.

We've removed several MetafieldStorefrontVisibility-related objects, mutations, queries, and fields:

Removals of MetafieldStorefrontVisibility-related types
Name Type Change
MetafieldStorefrontVisibility Object Removed. Use the access field on the MetafieldDefinition object instead.
metafieldStorefrontVisibilityCreate Mutation Removed. Use the metafieldDefinitionUpdate mutation instead.
metafieldStorefrontVisibilityDelete Mutation Removed. Use the metafieldDefinitionUpdate mutation instead.
metafieldStorefrontVisibilities Query Removed. Use the access field on the MetafieldDefinition object instead.
metafieldStorefrontVisibility Query Removed. Use the access field on the MetafieldDefinition object instead.
visibleToStorefrontApi Field on MetafieldDefinition object Removed. Use the access field on the MetafieldDefinition object instead.
visibleToStorefrontApi Field on MetafieldDefinitionInput input object Removed. Use the access field on the MetafieldDefinitionInput input object instead.
visibleToStorefrontApi Field on MetafieldDefinitionUpdateInput input object Removed. Use the access field on the MetafieldDefinitionUpdateInput input object instead.

We've removed the deprecated multiLocation field from the ShopFeatures object. Use the locationsCount query instead to determine the number of shop locations.

We've added the sales_line_item_group_id field to the orders/create webhook. This field allows you to determine if a specific line_item is part of a product bundle. When a line_item belongs to a product bundle, it will have an associated sales_line_item_group_id.

You can now use the pickupAddress field in both the SubscriptionDeliveryMethodPickupOption and SubscriptionPickupOption objects to query for a customer pickup address.

We've removed the following values on the PriceListUserErrorCode enum that aren't currently returned by the GraphQL Admin API:

  • CONTEXT_RULE_COUNTRIES_LIMIT
  • CONTEXT_RULE_COUNTRY_TAKEN
  • CONTEXT_RULE_LIMIT_REACHED
  • CONTEXT_RULE_MARKET_NOT_FOUND
  • CONTEXT_RULE_MARKET_TAKEN
  • COUNTRY_CURRENCY_MISMATCH
  • CURRENCY_COUNTRY_MISMATCH
  • MARKET_CURRENCY_MISMATCH

The handle field on the ProductInput input object is now validated for uniqueness.

This enhancement ensures that there are no collisions when creating or updating product handles. The change doesn't affect existing behavior when a handle isn't provided as input.

We've moved the following product metadata queries from the Shop type to QueryRoot and added pagination support:

Product metadata query changes
Name Type Change
productTags Query Moved to QueryRoot with pagination support
productTypes Query Moved to QueryRoot with pagination support
productVendors Query Moved to QueryRoot with pagination support

Previously, these fields were available on the Shop type with a limit of 250 results. The new implementation removes this limitation and supports pagination through standard cursor-based connections.

The order field on the ReverseFulfillmentOrder object is now nullable. An order can be nullable if the app meets any of the following conditions:

  • The app doesn't have the read_all_orders access scope.
  • The order is older than 60 days.
  • The order no longer exists.

In API versions prior to 2025-01, the order field returns a GraphQL error when the order isn't available.

We've added the PAYMENT_METHOD_VERIFICATION_FAILED and THREE_D_SECURE_FLOW_IN_VERIFICATION_NOT_IMPLEMENTED values to the CustomerPaymentMethodRevocationReason enum to provide more granular information about payment method revocations. This enhancement helps apps handle scenarios where a customer's payment method needs to be revoked.

We've removed the following fields from the ShopifyPaymentsBankAccount object that weren't being used by third-party apps:

We've reduced the available options for where a script is included when you create or update script tags. This change is related to the upcoming deprecation of script tags for the Thank you and Order status pages on August 28, 2025. Learn more about upcoming changes, key dates, and actions that you're required to take related to the deprecation of script tags.

The only valid value for the displayScope field on the ScriptTagInput input object is now ONLINE_STORE.

The displayScope field remains optional. When you omit this field from the scriptTagCreate mutation, the value defaults to ONLINE_STORE.

Script tag display scope usage and recommended alternatives
If you use... ...Then use this instead
UI customizations Upgrade to Checkout Extensibility
Analytics and conversion tracking Upgrade to web pixels
Online store Update the displayScope value to ONLINE_STORE

We've added the accountOpenerName field to the ShopifyPaymentsAccount object. You can use the field to query the name of the person that opened the Shopify Payments account.

You can use a limit of up to 2000 variants when running a query on a single product, such as product or productByHandle. This enhanced limit doesn't apply if you make multiple queries in one request, or are accessing the variants any other way except through the ProductVariantConnection.

The StringConnection connection now includes a nodes field, which provides a list of strings within the connection. The nodes field contains a list of nodes contained in StringEdge. This StringEdge contains one String and a cursor. The StringConnection and its associated Edge are cacheable, for improved performance. This addition makes it easier for developers to access the individual elements in a string connection seamlessly.

We’ve introduced the concatenatedOriginContract field to the SubscriptionLine object. The concatenatedOriginContract field provides information about the originating contract of the subscription line, and specifically whether it was created by concatenating multiple contracts. The concatenatedOriginContract field returns an instance of SubscriptionContract, which can be null if no concatenation is present.

We've moved the following product metadata queries from the Shop type to QueryRoot and added pagination support:

Product metadata query changes
Name Type Change
productTags Query Moved to QueryRoot with pagination support
productTypes Query Moved to QueryRoot with pagination support
productVendors Query Moved to QueryRoot with pagination support

We’ve introduced the concatenatedOriginContract field to the SubscriptionLine object. The concatenatedOriginContract field provides information about the originating contract of the subscription line, and specifically whether it was created by concatenating multiple contracts. The concatenatedOriginContract field returns an instance of SubscriptionContract, which can be null if no concatenation is present.

## Shopify Function APIs changes Version 2025-01 of the Shopify Function APIs introduces the following changes:

We've added the header field to the HttpResponse object. This field allows you to query for a specific HTTP header and add a specific header field to the function's external calls response.

The header field is available across all Shopify Function APIs.

The new header field includes a required name argument. This argument lets you specify a case-insensitive header name to retrieve its value. With this header field, you can access individual HTTP headers on demand. This provides more granular control compared to the previously available headers field, which returned all headers as a list. The header field returns an instance of the HttpResponseHeader type.

We now provide native support of a HTTP request body as a JSON_body for function external calls. Use this field when the body is in JSON format to reduce function instruction consumption and to ensure the body is formatted in logs. Don't use the JSON_body field together with the body field in the HttpResponse object. If both are provided, then the HttpResponse's body field takes precedence. If the JSON_body field is specified and no Content-Type header is included, then the header will automatically be set to application/json.

We've added the paymentDetails field on the verificationSessionResolve mutation. This field allows payment providers to send payment details as arguments to a card input field, such as billingAddress and cardHolderName.

## Payments Apps API changes Version 2025-01 of the Payments Apps API introduces the following changes:

We've added a localizedFields attribute to the Cart object for function inputs. This attribute returns the localized fields available for the cart. Values are only returned for server-side validations using the purchase.validation.run extension target.

Payments extensions that support vaulting have been improved to enable the processing of Three-Domain Secure (3DS) challenges for verifications.

Developer action required

For payments extensions that support vaulting, we strongly recommend that you update to the 2025-01 version as soon as possible. You also need to consider the following actions:

  • If 3DS is required for a verification, you must use the VerificationSessionRedirect mutation.
  • When resolving or rejecting a verification that required 3DS, pass the authentication argument to either the VerificationSessionResolve or VerificationSessionReject mutation.
  • We're also deprecating the following VerificationSessionStateReason: REQUIRED_3DS_CHALLENGE. Use the new VerificationSessionRedirect mutation instead.

We have changed the product image resource so that it returns a media ID instead of a product image GID. This is designed to make it easier to migrate to GraphQL from REST when interfacing with product images that were created before the introduction of a unified media ID.

Developer action required

Use medias.id instead of medias.legacy_id/product_images.id for the admin_graphql_api_id.

  • Previously, the admin_graphql_api_id returned a product image ID: "gid://shopify/ProductImage/43701248884792"

  • Now, the admin_graphql_api_id returns a media image ID: "gid://shopify/MediaImage/12379812379123"

This change will only affect clients using the latest 2025-01 API version. Older versions will continue to return the ProductImage GID, ensuring backward compatibility. It's strongly recommended that you upgrade to using GraphQL, as REST is nearing deprecation.

We've added the paymentDetails field on the verificationSessionResolve mutation. This field allows payment providers to send payment details as arguments to its paymentDetails.card input field.

## Storefront API changes Version 2025-01 of the Storefront API introduces the following changes:

We've added an addresses field to the CartDelivery object. This field returns a list of addresses that customers can select for their cart delivery, providing more flexible shipping options.

We've deprecated the following tax and duty fields on the Cart object's cost field: - totalDutyAmount - totalDutyAmountEstimated - totalTaxAmount - totalTaxAmountEstimated

Tax and duties are now calculated at checkout within the complete context of the customer's information, ensuring greater accuracy.

The StringConnection connection now includes a nodes field, which provides a list of strings within the connection. The nodes field contains a list of nodes contained in StringEdge. This StringEdge contains one String and a cursor. The StringConnection and its associated Edge are cacheable, for improved performance. This addition makes it easier for developers to access the individual elements in a string connection.

## REST Admin API changes Version 2025-01 of the REST Admin API introduces the following changes:

We've added business entity identifiers on the Order resource, as well as on webhook payloads. These identifiers represents the formal and legal structure under which a merchant operates their business.