GraphQL API

The Composable Commerce GraphQL API provides queries and mutations to the resources stored on Composable Commerce with the same API Clients that are used by HTTP APIs.

This page explains how to:

This page does not document the standard types and fields that the GraphQL API provides. You can retrieve this information either from the GraphQL schema via the introspection system or by using the Documentation Explorer in the GraphQL Explorer. For more information about the types and fields that are currently in public beta, see the Public beta functionalities section.
The introspection system also lets you discover features that are currently in early access and are intended for customers taking part in the early evaluation phase for upcoming features. Be aware that those features are not covered by our SLAs and can either change or be removed without public notice. The GraphQL schema that is publicly available on GitHub contains all the officially released API features which are covered by our SLAs.
Learn more about how to use GraphQL with Composable Commerce in our self-paced GraphQL module.

The GraphQL API is versionless, meaning new types and fields may be introduced at any time without notice. As a result, dynamic schema stitching is discouraged, as it can lead to naming conflicts and unexpected behavior.

Interactive GraphQL console

To experiment with the GraphQL API, and to view the full types and fields definitions, use the GraphQL Explorer in the Merchant Center.

Scopes

Access to resources is granted by the same scopes that are used on the HTTP API endpoints. This page does not explain about scopes in detail, but you can follow these guidelines to find the most suitable scope for a specific use case:
Use caseGraphQL serviceScope
query for a particular resourceQuery.{resourceType}view_{resourceType}s:{projectKey}
query for resources of a certain typeQuery.{resourceType}sview_{resourceType}s:{projectKey}
create a resource of a certain typeMutation.create{resourceType}manage_{resourceType}s:{projectKey}
update a particular resourceMutation.update{resourceType}manage_{resourceType}s:{projectKey}
delete a particular resourceMutation.delete{resourceType}manage_{resourceType}s:{projectKey}
For example, manage_products:{projectKey} is required for updating a Product with the Mutation.updateProduct service. The view_products:{projectKey} scope would not be sufficient for this.
The view_published_products:{projectKey} scope can be used by the Query.products service to retrieve data in masterData.current, but not in masterData.staged. The same applies for the Query.productProjectionSearch service that only returns data with this scope when the staged parameter is set to false in such queries.
Store-specific scopes are required to query or mutate Store-specific resources. For example, the service Query.inStore requires view_{resourceType}s:{projectKey}:{storeKey}.

Store-scoped queries and mutations

You can scope GraphQL operations to one or more Stores. The list of Store-scoped API methods shows which operations support Store scoping.

Query for resources in Stores

Use the top-level fields inStore and inStores to query resources belonging only to specified Stores.
Query for Carts in a specific Store with key 'luxury-brand'graphql
query {
  inStore(key: "luxury-brand") {
    carts {
      results { id }
      total
    }
  }
}
Query for Carts in multiple Storesgraphql
query {
  inStores(keys: ["luxury-brand", "budget-brand"]) {
    carts {
      total
    }
  }
}

Authorization:

  • You can use regular project-wide scopes (for example manage_orders:project-key).
  • Or use store-based scopes (for example manage_orders:project-key:luxury-brand).
  • For inStores, at least one of the provided Store keys must be covered by your scopes; otherwise an insufficient_scope error is returned.

Mutations on resources in Stores

Mutations on Carts, Orders, and Customers have an optional storeKey argument. When present, the mutation is executed in the context of that Store and fails if the targeted resource does not belong to it.
Create a Cart in the Store with key 'luxury-brand'graphql
mutation {
  createCart(draft: { currency: "USD" }, storeKey: "luxury-brand") {
    id
  }
}
Update a Cart only if it is in the Store with key 'luxury-brand'graphql
mutation {
  updateCart(
    id: "123e4567-e89b-12d3-a456-426655440000"
    version: 1
    actions: [{ addLineItem: { sku: "..." } }]
    storeKey: "luxury-brand"
  ) {
    id
  }
}

Scopes:

  • Either project-wide (for example manage_orders:project-key) or store-based (for example manage_orders:project-key:luxury-brand).

Representations

GraphQLRequest

The query, operation name, and variables that are sent to the GraphQL API.

query​
String​
operationName​
String​
Name of the operation, if you defined several operations in query.
variables​

JSON object that contains key-value pairs in which the keys are variable names and the values are variable values.

Example: json
{
  "query": "query getProductByKey($productKey: String!) {  product(key: $productKey) { id version }}",
  "operationName": "getProductByKey",
  "variables": {
    "productKey": "a-product-key"
  }
}

GraphQLVariablesMap

The variables that the GraphQL query uses.

//​
Any string parameter matching this regular expression​

JSON object that contains key-value pairs in which the keys are variable names and the values are variable values.

Example: json
{
  "productKey": "a-product-key"
}

GraphQLResponse

error is present in the response only if the GraphQL query was unsuccessful.
data​
Any​

JSON object that contains the results of a GraphQL query.

errors​
Array of GraphQLError​

Errors that the GraphQL query returns.

Example: json
{
  "data": {
    "product": {
      "id": "35d33405-2d39-4528-b195-fa3ab6beb927",
      "version": 2
    }
  }
}

Query GraphQL

GraphQL uses HTTP POST requests to both query and mutate data.

POST
https://api.{region}.commercetools.com/{projectKey}/graphql

Execute a GraphQL request.

OAuth 2.0 Scopes:
view_products:{projectKey}
Path parameters:
region
​
String
​
Region in which the Project is hosted.
projectKey
​
String
​
key of the Project.
Request Body:GraphQLRequestasapplication/json
Response:
200

GraphQLResponse

as
application/json
Request Example:cURL
curl https://api.{region}.commercetools.com/{projectKey}/graphql -i \
--header "Authorization: Bearer ${BEARER_TOKEN}" \
--header 'Content-Type: application/json' \
--data-binary @- << DATA 
{
  "query" : "query getProductByKey($productKey: String!) {  product(key: $productKey) { id version }}",
  "operationName" : "getProductByKey",
  "variables" : {
    "productKey" : "a-product-key"
  }
}
DATA
200 Response Example: GraphQLResponsejson
{
  "data": {
    "product": {
      "id": "35d33405-2d39-4528-b195-fa3ab6beb927",
      "version": 2
    }
  }
}

Using an SDK

The following code demonstrates how to query the GraphQL API using Composable Commerce SDKs.

This code assumes you have set up your SDK as described in the get started guide of your respective SDK. You may need to modify some code if your environment differs.

Query GraphQL using an SDK
async function graphQLCall() {
  const q = `
    query getProductByKey($productKey: String!) {
      product(key: $productKey) {
        id
        version
      }
    }
  `;

  return await apiRoot
    .graphql()
    .post({
      body: {
        query: q,
        operationName: 'getProductByKey',
        variables: {
          productKey: 'a-product-key',
        },
      },
    })
    .execute();
}

graphQLCall()
  .then(({ body }) => {
    console.log(body.data);
  })
  .catch(console.error);

Errors

If a GraphQL request is unsuccessful, the GraphQLResponse returns an array of GraphQLError.

GraphQLError

Contains an error message, the location of the code that caused the error, and other information to help you correct the error.

message​
String​

Detailed description of the error explaining the root cause of the problem and suggesting how to correct the error.

locations​
Array of GraphQLErrorLocation​

Location within your query where the error occurred.

path​
Array of Any​
Query fields listed in order from the root of the query response up to the field in which the error occurred. path is displayed in the response only if an error is associated with a particular field in the query result.
extensions​

Dictionary with additional information where applicable.

Example: json
{
  "message": "Object 35d33405-2d39-4528-b195-fa3ab6beb927 has a different version than expected. Expected: 1 - Actual: 2.",
  "path": [
    "deleteProduct"
  ],
  "locations": [
    {
      "line": 2,
      "column": 3
    }
  ],
  "extensions": {
    "code": "ConcurrentModification",
    "currentVersion": 2
  }
}

GraphQLErrorLocation

Represents the location within your query where the error occurred.

line​
Int​

Line number of the query where the error occurred.

column​
Int​
Position in line where the error occurred.

GraphQLErrorObject

Represents a single error.

code​
String​
One of the error codes that is listed on the Errors page.
//​
Any string parameter matching this regular expression​

Error-specific additional fields.

Structure GraphQL requests

The structure of GraphQL calls vary based on whether you want to query, create, update, or delete resources.

Query existing resources

Querying existing resources within your Project uses query. A name can be included to describe the call.
Query existing resourcesgraphql
query ReturnCustomers{}

Add an endpoint

In this example, customers targets all Customers. To target a single Customer, use customer.
Query Customersgraphql
query ReturnCustomers{
  customers{

  }
}
Query a single Customergraphql
query ReturnASingleCustomer {
  customer() {

  }
}

Add query parameters

When querying an endpoint such as customers (where all Customers are targeted) these query parameters can be added based on your requirements.
ParameterActionExample use
whereOnly returns resources that match the Query Predicate.
Quotation marks within quotation marks must be escaped.
where: "firstName=\"John\""
sortChanges the order of the returned resources.sort: "lastName asc"
limitThe maximum number of results to return. The default value is 20.limit: 5
offsetUsed for skipping results. The default value is 0.offset: 1
When querying an endpoint like customer (where a single Customer is targeted) you must enter a unique identifier for the resource (usually its id or key).
Query parameters must be enclosed in () next to the endpoint:
Query Customers with parametersgraphql
query ReturnCustomers {
  # Return up to five Customers named "John", ordered by their surname (ascending), and not including the first result
  customers(where: "firstName=\"John\"", sort: "lastName asc", limit: 5, offset: 1) {

  }
}
Query a single Customer by idgraphql
query ReturnASingleCustomer {
  # Return a Customer based on their id
  customer(id: "{customerID}") {

  }
}

Choose what to return

When querying an endpoint such as customers (where all Customers are targeted) you can return the following:
  • offset is the same value you selected in the parameters.
  • count is the number of resources returned based on the limit parameter.
  • total is the total number of resources in your Project.
  • exists returns a boolean value to indicate whether a queried resource exists.
  • results is the object where you include the values (such as id or version) you want to be returned.
When querying an endpoint like customer (where a single Customer is targeted), you only choose the values of the resource to return.
Complete query for Customers with parameters and values to returngraphql
query ReturnCustomers {
  # Return up to five Customers named "John", ordered by their surname (ascending), and not including the first result
  customers(
    where: "firstName=\"John\""
    sort: "lastName asc"
    limit: 5
    offset: 1
  ) {
    # Display the offset, count, and total
    offset
    count
    total
    results {
      # Return the Customer's ID, version, email, and name.
      id
      version
      email
      firstName
      lastName
    }
  }
}
Complete query for a single Customer by id and values to returngraphql
query ReturnASingleCustomer {
  # Return a Customer based on their id
  customer(id: "{customerID}") {
    id
    version
    email
    firstName
    lastName
  }
}

Create and update resources

When creating or updating resources within your Project, use mutation. A name can be included to describe the call.
Create a new resourcegraphql
mutation CreateDiscountCode{}
Update an existing resourcegraphql
mutation DeactivateDiscountCode{}

Add an action

Instead of requiring an endpoint, the mutation requires an action. The chosen action determines whether you are creating a new resource or updating an existing one.

When creating a new resource

Like with the HTTP API, you must post a draft to create a new resource.

You must also include the values you want GraphQL to return once the resource has been created.

Complete query for creating a new resourcegraphql
mutation CreateDiscountCode {
  # The action for creating a Discount Code
  createDiscountCode(
    # The DiscountCodeDraft and its required fields
    draft: {
      code: "SAVE25"
      isActive: true
      cartDiscounts: { typeId: "cart-discount", id: "{cartDiscountID}" }
    }
  ) {
    # The values to return
    code
    isActive
  }
}

When updating an existing resource

Like with the HTTP API, you must post an array of update actions to modify the data of existing resources.

You must also include the values you want GraphQL to return once the resource has been updated.

Complete query for updating an existing resourcegraphql
mutation DeactivateDiscountCode {
  # The action to update an existing resource
  updateDiscountCode(
    version: 1
    id: "{discountCodeID}"
    ## Include update actions and their required parameters
    actions: [{ changeIsActive: { isActive: false } }]
  ) {
    # The values to return
    code
    isActive
  }
}

Delete resources

When deleting resources within your Project, use mutation. You can include a name to describe the call.
Delete an existing resourcegraphql
mutation DeleteDiscountCode {
  # The action to delete an existing resource
  deleteDiscountCode(version: 1, id: "{discountCodeID}") {
    # The values to return
    id
    code
  }
}

Check if resources exist

HTTP APIs provide "Check if resource exists" endpoints that use the HEAD method and return a 200 or 404 status code to indicate whether a resource exists, based on an identifier or query predicate. In GraphQL, the equivalent functionality is provided by the exists field.
The GraphQL API either returns true if there is at least one result matching the query condition, or false if there are none.
Check if a resource exists by id, key, or query predicategraphql
# Quotation marks within quotation marks must be escaped.
query checkIfResourceExistsById {
  customers(where: "id=\"ba5f454f-dab5-4f95-802f-f1c285be7167\"") {
    exists
  }
}

query checkIfResourceExistsByKey {
  customers(where: "key=\"a-customer-key\"") {
    exists
  }
}

query checkIfResourceExistsByQueryPredicate {
  customers(where: "firstName=\"John\" and lastName=\"Smith\"") {
    exists
  }
}
Example response for checking if a resource existsjson
{
  "data": {
    "customers": {
      "exists": true
    }
  }
}

Reference Expansion

The GraphQL API supports Reference Expansion, just like the HTTP API.

By convention, the GraphQL API offers two fields for each expandable reference:

  • <fieldName>Ref - Fetches the Reference or KeyReference to the resource only (lower query complexity).
  • <fieldName> - Fetches the expanded resource that is referenced (higher query complexity).
    Returns null if the referenced resource is not found.
Expanding a reference in the GraphQL API impacts the performance of the request, and adds to the complexity score. If you don't need the expanded reference for your use case, you should use the <fieldName>Ref to get a better performance on your query.

For example, to retrieve the number of child Categories for a specific Category and the identifiers for its ancestors:

Query for child Categories and ancestors of a Categorygraphql
{
  category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
    children {
      id
    }
    ancestors {
      id
    }
  }
}
Example response for children and ancestorsjson
{
  "data": {
    "category": {
      "children": [
        {
          "id": "7900ab4b-c01c-4e73-8f10-557b84de55f5"
        },
        {
          "id": "93aa3372-310f-4fa7-8ab2-986036382e4f"
        },
        {
          "id": "0938dbd3-766e-48c2-b86b-31a3a3d820da"
        }
      ],
      "ancestors": [
        {
          "id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
        }
      ]
    }
  }
}
The total number of child Categories is the size of the children array. The identifiers for ancestors are listed in the ancestors field.
However, it is possible to reduce the complexity of the previous example. If you only need the number of child Categories, use the childCount field. Also, if you only need the identifiers for the ancestors, it is better to use the ancestorsRef field.
Query for child count and ancestors reference of a Categorygraphql
{
  category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
    childCount
    ancestorsRef {
      id
    }
  }
}
Example response for child count and ancestors referencejson
{
  "data": {
    "category": {
      "childCount": 3,
      "ancestorsRef": [
        {
          "id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
        }
      ]
    }
  }
}

Custom Fields

Reference Expansion for Custom Fields of CustomFieldReferenceType and for the CustomFieldSetType is supported.
If, for example, a Category has a Custom Field that holds a Reference to a Custom Object, the following query expands the referenced Custom Object and retrieves the value of the referenced Custom Object in the same query.
Query for a Custom Field that references a Custom Objectgraphql
query {
  category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
    custom {
      customFieldsRaw(includeNames: ["categoryCustom"]) {
        referencedResource {
          ... on CustomObject {
            value
          }
        }
      }
    }
  }
}
Expanded Custom Object value in a Custom Fieldjson
{
  "data": {
    "category": {
      "custom": {
        "customFieldsRaw": [
          {
            "referencedResource": {
              "value": {
                "extraCategoryData": "This is extra Category data"
              }
            }
          }
        ]
      }
    }
  }
}

Custom Objects BETA

If you have stored References to other resources in values of Custom Objects, you can expand them by using referencedResources(expand: [String!]): [ReferencedResource!].
Given an example Custom Object that contains a Reference to a Review resource:
Example Custom Object with Reference to a Review resourcejson
{
  "id": "687e312c-600a-4544-af21-ca1f6313bfde",
  "version": 5,
  ...
  "container": "myContainer",
  "key": "myKey",
  "value": {
      "reviewRating": {
          "typeId": "review",
          "id": "d77f00e0-1cd5-0bfa-b566-bcd105d86edd"
      }
  }
}

The following query represents how to expand the referenced Review contained in the payload of your Custom Object.

Query for expanded text field of a referenced Review resourcegraphql
query {
  customObject(container: "myContainer", key: "myKey") {
    referencedResources(expand: ["reviewRating"]) {
      path
      objs {
        ... on Review {
          text
        }
      }
    }
  }
}
Expanded 'text' field on a referenced Reviewjson
{
  "data": {
    "customObject": {
      "referencedResources": [
        {
          "path": "reviewRating",
          "objs": [
            {
              "text": "some review text"
            }
          ]
        }
      ]
    }
  }
}

If your Custom Object contains a list of References, like the following example containing an array of References to Review resources:

Example Custom Object with an array of References to Review resourcesjson
{
  "id": "687e312c-600a-4544-af21-ca1f6313bfde",
  "version": 7,
  ...
  "container": "containerForReferences",
  "key": "listOfReferences",
  "value": {
      "reviewReferences": [
          {
              "id": "6e46a6fc-bdee-4159-a07d-ce7b8f6f130f",
              "typeId": "review"
          },
          {
              "id": "e8f32564-7963-4c8a-906e-cdc675aba9e8",
              "typeId": "review"
          },
          {
              "id": "9902febb-6208-4322-9d7a-d622ec3e4f4f",
              "typeId": "review"
          }
      ]
  }
}
you can request for reference expansion of the references contained in the array. For example, you can use the following query to get the text field from the expanded Review resources:
Query for expanded 'text' field of all referenced Review resourcesgraphql
{
  customObject(container: "containerForReferences", key: "listOfReferences") {
    key
    referencedResources(expand: "reviewReferences[*]") {
      path
      objs {
        ... on Review {
          text
        }
      }
    }
  }
}
Expanded 'text' field on all referenced Reviewsjson
{
  "data": {
    "customObject": {
      "key": "listOfReferences",
      "referencedResources": [
        {
          "path": "reviewReferences[*]",
          "objs": [
            {
              "text": "Some review text"
            },
            {
              "text": "Another review text"
            },
            {
              "text": "Would buy again"
            }
          ]
        }
      ]
    }
  }
}
In the previous example we asked for expanding the objects for all references in the array by using the asterisk operator expand: "reviewReferences[*]". The expansion path syntax allows you to expand only specific elements of the array also.
For Custom Objects, the expansion path cannot contain reference fields that are nested inside the referenced resource. If, for example, you want to expand the parent of a referenced Category, the expansion path expand: "category.parent" does not work.

Instead, you specify only the top level reference in the expansion path, and query for any nested references in the fragment part of the GraphQL query, like in the following example:

Query for the name of the expanded parent category of a referenced categorygraphql
query {
  customObject(container: "custom-object-container", key: "custom-object-key") {
    referencedResources(expand: ["category"]) {
      path
      objs {
        ... on Category {
          parent {
            name(locale: "en")
          }
        }
      }
    }
  }
}
Expanded 'name' field on expanded 'parent' field of referenced Categoryjson
{
  "data": {
    "customObject": {
      "referencedResources": [
        {
          "path": "category",
          "objs": [
            {
              "parent": {
                "name": "some category name"
              }
            }
          ]
        }
      ]
    }
  }
}

If your Custom Object value contains references of different resource types, like in the following example:

Custom Object with references of different resource typesjson
{
    ...
    "container": "custom-object-container",
    "key": "custom-object-key",
    "value": [
        {
            "category": {
                "id": "ba5704a1-77b5-4be4-bfb1-24f6a2630d82",
                "typeId": "category"
            }
        },
        {
            "review": {
                "id": "6e46a6fc-bdee-4159-a07d-ce7b8f6f130f",
                "typeId": "review"
            }
        }
    ]
}

you can request expanding both references in the same query by providing both expansion paths:

Query for the name of the expanded parent category of a referenced categorygraphql
query {
  customObject(container: "custom-object-container", key: "custom-object-key") {
    referencedResources(expand: ["category", "review"]) {
      path
      objs {
        ... on Category {
          parent {
            name(locale: "en")
          }
        }
        ... on Review {
          text
        }
      }
    }
  }
}
Expanded fields on both expansion pathsjson
{
  "data": {
    "customObject": {
      "referencedResources": [
        {
          "path": "category",
          "objs": [
            {
              "parent": {
                "name": "root category"
              }
            }
          ]
        },
        {
          "path": "review",
          "objs": [
            {
              "text": "awesome test review"
            }
          ]
        }
      ]
    }
  }
}

Variant Attributes

You can include referencedResource (for single references) and referencedResourceSet (for sets of references) under attributesRaw for allVariants or masterVariant:
Query for Product Variant Attributesgraphql
{
  product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
    masterData {
      current {
        allVariants {
          attributesRaw {
            referencedResource {
              ## If a referenced Product exists, return its name, SKUs, and key
              ... on Product {
                masterData {
                  current {
                    slug(locale: "en")
                  }
                }
                skus
                key
              }
              ## If a referenced ProductType exists, return the Attributes names and ProductType name
              ... on ProductTypeDefinition {
                attributeDefinitions {
                  results {
                    name
                  }
                }
                name
              }
            }
            referencedResourceSet {
              ## If a set of referenced Products exists, return their names, SKUs, and keys
              ... on Product {
                masterData {
                  current {
                    slug(locale: "en")
                  }
                }
                skus
                key
              }
              ## If a set of referenced ProductTypes exists, return their Attribute names and ProductType names
              ... on ProductTypeDefinition {
                attributeDefinitions {
                  results {
                    name
                  }
                }
                name
              }
            }
          }
        }
      }
    }
  }
}

Nested Attributes BETA

When using nested attributes you can use attributesRaw field on RawProductAttribute type to gain access to referencedResource and referencedResourceSet, and therefore expand any references contained within the nested attribute.

You can include multiple levels of nested attributes, but doing so increases the total cost of the query.

{
  product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
    masterData {
      current {
        allVariants {
          attributesRaw {
            name
            attributesRaw {
              name
              referencedResource {
                ## If a referenced Product exists, under a nested reference, return its name, SKUs, and key
                ... on Product {
                  masterData {
                    current {
                      slug(locale: "en")
                    }
                  }
                  skus
                  key
                }
              }
            }
          }
        }
      }
    }
  }
}

Product Search Attributes

You can include referencedResource (for single references) and referencedResourceSet (for sets of references) under attributesRaw for masterVariant.
Additionally, when using nested attributes you can use attributesRaw field on RawProductAttribute type to gain access to referencedResource and referencedResourceSet, and therefore expand any references contained within the nested attribute.
Query for Product Search Attributesgraphql
{
  productProjectionSearch(staged: true) {
    results {
      masterVariant {
        attributesRaw(
          includeNames: "{includedAttributes}"
          excludeNames: "{excludedAttributes}"
        ) {
          name
          value
          referencedResource {
            id
            ... on Product {
              skus
            }
          }
          referencedResourceSet {
            id
            ... on Product {
              skus
            }
          }
        }
      }
    }
  }
}

Query complexity

You can fetch a lot of information in a single HTTP request using GraphQL. This is helpful to avoid parsing unused fields, and the unnecessary network overhead by reducing the number of requests. At the same time, it is important to remember that a single query can potentially generate a lot of database operations. Hence, you cannot assume that the response time for a query increases linear with the number of fields in the query.

The GraphQL schema defines a "cost" per field, which you can display using following options:

  • Inspecting the x-graphql-query-complexity response header and its value.
  • Using the GraphQL Explorer query profiler to measure the impact.
    GraphQL Explorer query profiler

QueryComplexityLimitExceeded

To prevent complex queries from having a negative impact on the overall performance, we block queries equal to or higher than the complexity limit of 20 000. In such cases, queries return a QueryComplexityLimitExceeded error code with the HTTP status code 400.
code​
String​
"QueryComplexityLimitExceeded"
message​
String​
//​
Any string parameter matching this regular expression​

Error-specific additional fields.

Advanced queries

Query Attributes, Custom Objects, and Custom Fields

Attributes, Custom Objects, and Custom Fields contain Project-specific dynamic data that can be accessed by using raw GraphQL fields.

Retrieve Variant Attributes

The contents of the value field reflect the data type that is used by the Attribute. For more information, see AttributeType. You must determine the data type yourself.
Example GraphQL request to retrieve Variant Attributesgraphql
query {
  product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
    masterData {
      current {
        variants {
          ...variantFields
        }
      }
    }
  }
}

fragment variantFields on ProductVariant {
  sku
  attributesRaw {
    name
    value
  }
}
Returned Product Variant Attributesjson
{
  "data": {
    "product": {
      "masterData": {
        "current": {
          "variants": [
            {
              "sku": "M0E20000000E218",
              "attributesRaw": [
                {
                  "name": "productSupported",
                  "value": true
                },
                {
                  "name": "supportContact",
                  "value": {
                    "en": "english@example.com",
                    "de": "german@example.com"
                  }
                }
              ]
            }
          ]
        }
      }
    }
  }
}

Retrieve values of enum Attributes in a ProductType

The results field contains an array of objects containing name and type of all Attributes in your Project. If results[*].type.name is enum or lenum, an additional values field is present, which contains the possible values of the enum Attributes.
Example GraphQL request to retrieve values of enum Attributesgraphql
{
  productType(key: "product-type-key") {
    attributeDefinitions {
      results {
        name
        type {
          name
          ...enumValues
          ...localizedEnumValues
        }
      }
    }
  }
}

fragment enumValues on EnumAttributeDefinitionType {
  values {
    results {
      key
      label
    }
  }
}

fragment localizedEnumValues on LocalizableEnumAttributeDefinitionType {
  values {
    results {
      key
      labelAllLocales {
        locale
        value
      }
    }
  }
}
Returned Product Type Attribute valuesjson
{
  "data": {
    "productType": {
      "attributeDefinitions": {
        "results": [
          {
            "name": "creationDate",
            "type": {
              "name": "datetime"
            }
          },
          {
            "name": "articleNumberManufacturer",
            "type": {
              "name": "text"
            }
          },
          {
            "name": "madeInItaly",
            "type": {
              "name": "enum",
              "values": {
                "results": [
                  {
                    "key": "yes",
                    "label": "yes"
                  },
                  {
                    "key": "no",
                    "label": "no"
                  }
                ]
              }
            }
          },
          {
            "name": "color",
            "type": {
              "name": "lenum",
              "values": {
                "results": [
                  {
                    "key": "black",
                    "labelAllLocales": [
                      {
                        "locale": "en",
                        "value": "black"
                      },
                      {
                        "locale": "de",
                        "value": "schwarz"
                      }
                    ]
                  },
                  {
                    "key": "white",
                    "labelAllLocales": [
                      {
                        "locale": "de",
                        "value": "weiss"
                      },
                      {
                        "locale": "en",
                        "value": "white"
                      }
                    ]
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
}

Retrieve Custom Fields

The contents of the value field reflect the data type that is used by the Custom Field. For more information, see FieldType. You must determine the data type yourself.
Example GraphQL request to retrieve Custom Fieldsgraphql
{
  product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
    masterData {
      current {
        variants {
          prices {
            ...customFields
          }
        }
      }
    }
  }
}

fragment customFields on ProductPrice {
  custom {
    customFieldsRaw {
      name
      value
    }
  }
}
Returned Product Custom Fieldsjson
{
  "data": {
    "product": {
      "masterData": {
        "current": {
          "variants": [
            {
              "prices": [
                {
                  "custom": {
                    "customFieldsRaw": [
                      {
                        "name": "kiloPrice",
                        "value": {
                          "type": "centPrecision",
                          "currencyCode": "EUR",
                          "centAmount": 95,
                          "fractionDigits": 2
                        }
                      }
                    ]
                  }
                }
              ]
            }
          ]
        }
      }
    }
  }
}

Create Attributes, Custom Fields, and Custom Objects

To set values for Attributes, Custom Objects, and Custom Fields, you must use their corresponding input object types. For each of these, the value field should be a string containing escaped JSON.
Examples for the value field on ProductAttributeInput:
"{\"type\": \"centPrecision\", \"currencyCode\": \"USD\", \"centAmount\": 1000, \"fractionDigits\": 2}"
"\"yellow\""
Examples for the value field on CustomFieldInput:
"[\"This is a string\", \"This is another string\"]"
"{\"id\": \"b911b62d-353a-4388-93ee-8d488d9af962\", \"typeId\": \"product\"}"
Example for the value field on CustomObjectDraft:
"{ \"stringField\": \"myVal\", \"numberField\": 123, \"boolField\": false, \"nestedObject\": { \"nestedObjectKey\": \"anotherValue\" }, \"dateField\": \"2018-10-12T14:00:00.000Z\" }"

Use Search queries

You can implement storefront search applications using the GraphQL API.

Example

Example query with complex expression, postFilter, sorting, pagination, and facetsgraphql
query ProductSearchExample {
  productsSearch(
    query: {
      and: [
        { exact: { field: "variants.prices.currencyCode", value: "USD" } }
        { exists: { field: "variants.prices.centAmount" } }
        { exists: { field: "name", language: "en" } }
        {
          fullText: {
            field: "description"
            value: "Sample Product"
            language: "en"
          }
        }
        { range: { long: { field: "variants.prices.centAmount", lte: 15 } } }
        {
          range: {
            datetime: { field: "createdAt", gte: "2024-01-01T00:00:00" }
          }
        }
        {
          or: [
            { exact: { field: "name", value: "Club Mate", language: "en" } }
            { exact: { field: "name", value: "Spezi", language: "en" } }
            { exact: { field: "name", value: "Cola", language: "en" } }
          ]
        }
      ]
    }
    postFilter: {
      and: [
        { exact: { field: "variants.prices.currencyCode", value: "USD" } }
        { exists: { field: "variants.prices.centAmount" } }
      ]
    }
    sort: [{ field: "name", order: asc, language: "en" }]
    limit: 10
    offset: 0
    markMatchingVariants: true
    facets: [{ distinct: { name: "productKeys", field: "key", limit: 10 } }]
  ) {
    total
    offset
    limit
    results {
      id
      product {
        id
      }
    }
    facets {
      name
    }
  }
}
The query argument follows the SearchQuery documentation.
In contrast to productProjectionsSearch where the product fields are directly selectable on the results, there is a dedicated product sub field in results.

Fetch all Product Variants

The productsSearch query provides the following query fields to fetch the Master Variant or the additional Product Variants of a Product Projection separately or all together.
  • masterData - Fetches the selected (current, staged) master data.
  • variants - Fetches only the additional Product Variants.
  • allVariants - Fetches all Product Variants including the Master Variant.
All options for fetching Product Variantsgraphql
query Products {
  productsSearch(
    query: {
      fullText: { field: "description", value: "pants", language: "en" }
    }
  ) {
    total
    results {
      product {
        key
        masterData {
          current {
            name(locale: "en")
            variants {
              sku
            }
            allVariants {
              sku
            }
          }
        }
      }
    }
  }
}
The productsSearch query also supports markMatchingVariants, see the explanations in Product Projections Search.

Search based on text and locale

Example GraphQL request to search using text and localegraphql
query {
  productProjectionSearch(staged: true, locale: "en-US", text: "bed") {
    total

    # Uncomment to return the ID and English name of each result.
    #  results{
    #   id
    #    name(locale:"en-US")
    #  }
  }
}
Returned Product Projection Search requestjson
{
  "data": {
    "productProjectionSearch": {
      "total": 17
    }
  }
}

Search based on text, locale, and filtering

Example GraphQL request to search using text, locale, and filteringgraphql
query {
  productProjectionSearch(
    queryFilters: [{ string: "published:true" }]
    staged: true
    locale: "en-US"
    text: "bed"
  ) {
    # Return the total number of results.
    total

    # Uncomment to return the ID and English name of each result.
    #  results{
    #   id
    #    name(locale:"en-US")
    #  }
  }
}
Returned Product Projection Search requestjson
{
  "data": {
    "productProjectionSearch": {
      "total": 17
    }
  }
}

Search using filters

Example GraphQL request to search using filtersgraphql
query {
  productProjectionSearch(
    staged: true
    filters: [
      {
        model: {
          value: { path: "variants.price.centAmount", values: ["1599"] }
        }
      }
    ]
  ) {
    total
    results {
      id
      version
    }
  }
}
Returned Product Projection Search requestjson
{
  "data": {
    "productProjectionSearch": {
      "total": 3,
      "results": [
        {
          "id": "394f20b4-0b21-45f7-81cc-43a4e45ba775",
          "version": 1
        },
        {
          "id": "ecc60e5f-ddd7-4137-8b84-fcaa17426549",
          "version": 3
        },
        {
          "id": "df65a374-e281-41a1-a370-c4d2591cae39",
          "version": 1
        }
      ]
    }
  }
}

Retrieve facet calculation

Example GraphQL request to retrieve facet calculationgraphql
query {
  productProjectionSearch(
    facets: [
      {
        model: {
          range: {
            path: "variants.price.centAmount"
            ranges: [{ from: "1000", to: "3000" }]
            countProducts: false
          }
        }
      }
    ]
  ) {
    facets {
      facet
      value {
        type
        ... on RangeFacetResult {
          dataType
          ranges {
            type
            ... on RangeCountDouble {
              from
              fromStr
              to
              toStr
              count
              productCount
              totalCount
              total
              min
              max
              mean
            }
          }
        }
      }
    }
  }
}
Returned Product Projection Search requestjson
{
  "data": {
    "productProjectionSearch": {
      "facets": [
        {
          "facet": "variants.price.centAmount",
          "value": {
            "type": "range",
            "dataType": "number",
            "ranges": [
              {
                "type": "double",
                "from": 1000,
                "fromStr": "1000.0",
                "to": 3000,
                "toStr": "3000.0",
                "count": 35,
                "productCount": null,
                "totalCount": 35,
                "total": 62065,
                "min": 1099,
                "max": 2999,
                "mean": 1773.2857142857142
              }
            ]
          }
        }
      ]
    }
  }
}

Differentiate between highPrecision and centPrecision money

Example GraphQL request to query for highPrecision and centPrecision moneygraphql
{
  productProjectionSearch(staged: false, locale: "en", text: "blue") {
    count
    results {
      id
      masterVariant {
        sku
        prices {
          ...productPrice
        }
      }
    }
  }
}

fragment productPrice on ProductPriceSearch {
  value {
    ...money
    __typename
  }
  discounted {
    value {
      ...money
      __typename
    }
    __typename
  }
}

fragment money on BaseMoney {
  type
  currencyCode
  centAmount
  fractionDigits
  ... on HighPrecisionMoney {
    preciseAmount
  }
}
Returned Product Projection Search requestjson
{
  "data": {
    "productProjectionSearch": {
      "results": [
        {
          "id": "500797c7-e719-4d72-8c69-92fdee39d451",
          "masterVariant": {
            "sku": "M0E20000000E582",
            "prices": [
              {
                "value": {
                  "type": "highPrecision",
                  "currencyCode": "USD",
                  "centAmount": 24875,
                  "fractionDigits": 11,
                  "preciseAmount": 24875123456789,
                  "__typename": "HighPrecisionMoney"
                },
                "discounted": null
              },
              {
                "value": {
                  "type": "centPrecision",
                  "currencyCode": "EUR",
                  "centAmount": 16311,
                  "fractionDigits": 2,
                  "__typename": "Money"
                },
                "discounted": null
              }
            ]
          }
        }
      ]
    }
  }
}

Fetch all Product Variants

The productProjectionSearch query provides the following query fields to fetch the Master Variant or the additional Product Variants of a Product Projection separately or all together.
  • masterVariant - Fetches the Master Variant only.
  • variants - Fetches only the Product Variants in addition to the Master Variant.
  • allVariants - Fetches all Product Variants including the Master Variant.
All options for fetching Product Variantsgraphql
query {
  productProjectionSearch {
    results {
      masterVariant {
        key
      }
      variants {
        id
      }
      allVariants {
        sku
      }
    }
  }
}

Fetch only matching Product Variants

In the productProjectionSearch query, you can control whether or not the response contains only the Product Variants that match the search query. To accomplish this, set markMatchingVariants: true, and set the onlyMatching flag in the variants or allVariants field to true.

The flag behaves as follows:

  • onlyMatching: true - Returns only the matching Product Variants.
  • onlyMatching: false - Returns only the non-matching Product Variants.
  • no flag - Returns all Product Variants.
If you use the onlyMatching flag without setting markMatchingVariants to true, the results will be empty even though matching Product Variants may exist.
Example for onlyMatching: truegraphql
query {
  productProjectionSearch(
    markMatchingVariants: true
    queryFilters: {
      model: { value: { path: "variants.price.centAmount", values: ["1299"] } }
    }
  ) {
    results {
      key
      allVariants(onlyMatching: true) {
        sku
      }
    }
    count
  }
}

Use Search Term Suggestions

You can use the functionality of the Search Term Suggestions API with a productProjectionsSuggest query.
Example query for suggested search terms for English input 'swiss'graphql
query {
  productProjectionsSuggest(
    searchKeywords: { searchKeyword: "swiss", locale: "en" }
  ) {
    searchKeywords {
      suggestions {
        text
      }
    }
  }
}
Example response for predefined search keywords for English: 'swiss'json
{
  "data": {
    "productProjectionsSuggest": {
      "searchKeywords": [
        {
          "suggestions": [
            {
              "text": "Swiss Army Knife"
            }
          ]
        }
      ]
    }
  }
}

Public beta functionalities BETA

Find below a list of functionality that is currently in beta.
  • createdBy and lastModifiedBy on Versioned
  • MultiBuyLineItemsTarget and MultiBuyCustomLineItemsTarget on CartDiscount
  • stores on CartDiscount
  • NestedTypes on ProductType
  • attributesRaw on RawProductAttribute,
  • productsSearch query,
  • everything related to MyCart, MyOrder, MyPayment, MyProfile, MyShoppingList, MyBusinessUnit, MyQuote, MyQuoteRequest