GraphQL API

Access commercetools Composable Commerce via GraphQL.

The GraphQL API provides queries and mutations to the resources stored on commercetools Composable Commerce with the same API Clients that are used for the REST API.

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 console. 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.

Get started

You can learn how to create and structure GraphQL requests in our get started guide.

Interactive GraphQL console

To explore the GraphQL API, you can use the GraphQL Explorer in the Merchant Center.

Application of scopes

Access to resources is granted by the same scopes that are used on the REST 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}.

Representations

GraphQLRequest

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

query
String

String representation of the Source Text of the Document that is specified in the Language section of the GraphQL specification.

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:
200GraphQLResponseasapplication/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
}
}
}

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

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.

Query Attributes, Custom Objects, and Custom Fields

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

Retrieve Product Attributes

The contents of the value field reflect the data type that is used by the Product Attribute. For more information, see AttributeType. You must determine the data type yourself.

Example query and response for raw Product Attributes:

query {
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
variants {
...variantFields
}
}
}
}
}
fragment variantFields on ProductVariant {
sku
attributesRaw {
name
value
}
}
{
"data": {
"product": {
"masterData": {
"current": {
"variants": [
{
"sku": "M0E20000000E218",
"attributesRaw": [
{
"name": "productSupported",
"value": true
},
{
"name": "supportContact",
"value": {
"en": "english@example.com",
"de": "german@example.com"
}
}
]
}
]
}
}
}
}
}

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 query and response for raw Custom Fields:

{
product(id: "3ba12359-f03e-4fa1-9c7e-7fbdb5393ec5") {
masterData {
current {
variants {
prices {
...customFields
}
}
}
}
}
}
fragment customFields on ProductPrice {
custom {
customFieldsRaw {
name
value
}
}
}
{
"data": {
"product": {
"masterData": {
"current": {
"variants": [
{
"prices": [
{
"custom": {
"customFieldsRaw": [
{
"name": "kiloPrice",
"value": {
"type": "centPrecision",
"currencyCode": "EUR",
"centAmount": 95,
"fractionDigits": 2
}
}
]
}
}
]
}
]
}
}
}
}
}

Create Product Attributes, Custom Fields, and Custom Objects

To set values for Product 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\" }"

Check if resources exist

For use cases where you only want to check whether at least one result exists that matches your query, use the boolean exists field in your query. This will optimize the query and result in a shorter response time.

The API either returns true if there is at least one result matching the query condition, or false if there are none.

query {
# As the quotation marks are within quotation marks, they must be escaped
products(where: "productType(id=\"55e43a8a-b130-4ea3-9d90-4fd97bf90ab9\")") {
exists
}
}
{
"data": {
"products": {
"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:

{
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
children {
id
}
ancestors {
id
}
}
}
{
"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.

{
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
childCount
ancestorsRef {
id
}
}
}
{
"data": {
"category": {
"childCount": 3,
"ancestorsRef": [
{
"id": "1fbfdc4b-b6c7-4f06-9db4-cbd4179f2a17"
}
]
}
}
}

Custom Fields BETA

Reference Expansion for Custom Fields of CustomFieldReferenceType and for the CustomFieldSetType is supported in public beta.

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 {
category(id: "7bcd33e6-c1c7-4b96-8d70-9b9b18b19b70") {
custom {
customFieldsRaw(includeNames: ["categoryCustom"]) {
referencedResource {
... on CustomObject {
value
}
}
}
}
}
}
{
"data": {
"category": {
"custom": {
"customFieldsRaw": [
{
"referencedResource": {
"value": {
"extraCategoryData": "This is extra Category data"
}
}
}
]
}
}
}
}

Product Attributes BETA

Reference Expansion for Product Attributes is supported in public beta.

You can include referencedResource (for single references) and referencedResourceSet (for sets of references) under attributesRaw for allVariants or masterVariant:

{
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
}
}
}
}
}
}
}
}

Product Search Attributes BETA

Reference Expansion for Product Search Attributes are supported in public beta.

You can include referencedResource (for single references) and referencedResourceSet (for sets of references) under attributesRaw for masterVariant:

{
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 useful information in a single HTTP request using GraphQL. This is really helpful to avoid parsing unused fields, and remove 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 analyze by inspecting the x-graphql-query-complexity response header and its value.

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.

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
  • everything related to MyCart, MyOrder, MyPayment, MyProfile, MyShoppingList, MyBusinessUnit, MyQuote, MyQuoteRequest
  • NestedTypes on ProductType
  • referencedResource and referencedResourceSet