Support
Manage your catalogManage catalog items

How to manage catalog items

View as Markdown

Create and manage SKUs and SKU groups through the Catalog GraphQL subgraph — the store-scoped endpoint for catalog operations.

Overview

The Catalog subgraph manages SKUs and SKU groups (there's no Product type). A SKU is a single purchasable variant. A SKU group is a collection of related SKUs (for example, a shirt available in multiple sizes). All catalog operations go through one GraphQL endpoint: POST /v2/commerce/stores/{storeId}/catalog-subgraph. Send the same store ID in the {storeId} path and the x-store-id header. The header is required. If they differ, the subgraph uses the header — the path does not override it.

API host

Examples use https://api.godaddy.com. Use a Personal Access Token issued for the API host you call.

Catalog scopes use commerce.product:* naming for historical reasons. Request commerce.product:read to query data and commerce.product:write for mutations. Read RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset on every catalog-subgraph response. On HTTP 429, wait for RateLimit-Reset or Retry-After. See Handle rate limits.

The following article describes how to manage catalog items. Go to Catalog GraphQL reference for more information about the Catalog subgraph.

Prerequisites

The following prerequisites are required before you can manage catalog items:

  • a GoDaddy account with an active commerce store
  • a Personal Access Token (PAT) with commerce.product:read (queries) or commerce.product:write (mutations)
  • your storeId

    Find your store ID

    Sign in to your GoDaddy account and go to About the Commerce API to retrieve your storeId.

List SKU groups

skuGroups returns a paginated list of SKU groups for your store. Use first and after to page through results.

The following procedure retrieves the first page of SKU groups.

  1. Query SKU groups for your store:

    curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/catalog-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: ${STORE_ID}" \
      -H "Content-Type: application/json" \
      -d '{"query": "{ skuGroups(first: 10) { edges { node { id label type status } } pageInfo { hasNextPage endCursor } } }"}'
  2. Review the response including SKU group IDs and the pagination cursor:

    {
      "data": {
        "skuGroups": {
          "edges": [
            {
              "node": {
                "id": "<SKU_GROUP_UUID>",
                "label": "<SKU_GROUP_DISPLAY_LABEL>",
                "type": "<SKU_GROUP_TYPE>",
                "status": "<LIFECYCLE_STATUS>"
              }
            }
          ],
          "pageInfo": {
            "hasNextPage": true,
            "endCursor": "<PAGINATION_CURSOR>"
          }
        }
      }
    }

    Fetch the next page

    To fetch the next page, pass the endCursor value as the after argument: skuGroups(first: 10, after: "<PAGINATION_CURSOR>").

Get a SKU group

skuGroup(id) retrieves a single SKU group and its associated SKUs.

  • Retrieve a SKU group by its id:

    SKU_GROUP_ID="<SKU_GROUP_UUID>"
    
    curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/catalog-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: ${STORE_ID}" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "query GetSkuGroup($id: String!) { skuGroup(id: $id) { id label type status skus { edges { node { id label code status } } } } }",
        "variables": { "id": "<SKU_GROUP_UUID>" }
      }'

Create a SKU group

createSkuGroup creates a new SKU group. The label and type fields are required. Live accepts PHYSICAL, DIGITAL, and PRODUCT for type. Metafield type must be lowercase (string, not STRING).

The following procedure creates a SKU group.

  1. Send the create mutation:

    curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/catalog-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: ${STORE_ID}" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "mutation CreateSkuGroup($input: MutationCreateSkuGroupInput!) { createSkuGroup(input: $input) { id label type status } }",
        "variables": {
          "input": {
            "label": "<SKU_GROUP_DISPLAY_LABEL>",
            "type": "STANDARD"
          }
        }
      }'
  2. Review the response including the new SKU group ID:

    {
      "data": {
        "createSkuGroup": {
          "id": "<SKU_GROUP_UUID>",
          "label": "<SKU_GROUP_DISPLAY_LABEL>",
          "type": "STANDARD",
          "status": "<LIFECYCLE_STATUS>"
        }
      }
    }

Create a SKU

createSku creates a new SKU. The label field is required. Pass skuGroupId to attach it to a product (SKU group) in the same call, or use addSkusToSkuGroup afterwards. You can also create SKUs inline on createSkuGroup via skus.

When you set prices or unitCost, for SimpleMoneyInput.value send 1999 for $19.99 USD, not 19.99. Metafield type must be lowercase (string, not STRING).

SKU label is not the product title

createSku.label is the variant label. The Commerce products UI uses the SKU group label as the product title. Changing a SKU label does not rename the product — use updateSkuGroup for that. To change an existing SKU price, use updateSkuPrice; createSkuPrice fails if the SKU already has a price.

The following procedure creates a SKU.

  1. Send the create mutation:

    curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/catalog-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: ${STORE_ID}" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "mutation CreateSku($input: CreateSKUInput!) { createSku(input: $input) { id label code status } }",
        "variables": {
          "input": {
            "label": "<SKU_DISPLAY_LABEL>",
            "code": "<SKU_CODE>"
          }
        }
      }'
  2. Review the response including the new SKU ID:

    {
      "data": {
        "createSku": {
          "id": "<SKU_UUID>",
          "label": "<SKU_DISPLAY_LABEL>",
          "code": "<SKU_CODE>",
          "status": "<LIFECYCLE_STATUS>"
        }
      }
    }

Update a SKU

updateSku updates one or more fields on an existing SKU. All input fields are optional. Only include the fields you want to change.

The following procedure updates the label of a SKU.

  1. Send the update mutation:

    curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/catalog-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: ${STORE_ID}" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "mutation UpdateSku($id: String!, $input: MutationUpdateSkuInput!) { updateSku(id: $id, input: $input) { id label code status } }",
        "variables": {
          "id": "<SKU_UUID>",
          "input": {
            "label": "<UPDATED_SKU_DISPLAY_LABEL>"
          }
        }
      }'
  2. Review the response confirming the updated fields:

    {
      "data": {
        "updateSku": {
          "id": "<SKU_UUID>",
          "label": "<UPDATED_SKU_DISPLAY_LABEL>",
          "code": "<SKU_CODE>",
          "status": "<LIFECYCLE_STATUS>"
        }
      }
    }

Archive a SKU

archiveSku marks a SKU as archived (there's no delete mutation). Archived SKUs are excluded from active queries unless you filter by status: ARCHIVED.

  • Archive a SKU by its id:

    curl -s -X POST "https://api.godaddy.com/v2/commerce/stores/${STORE_ID}/catalog-subgraph" \
      -H "Authorization: Bearer $GODADDY_PAT" \
      -H "x-store-id: ${STORE_ID}" \
      -H "Content-Type: application/json" \
      -d '{
        "query": "mutation ArchiveSku($id: String!) { archiveSku(id: $id) { id status } }",
        "variables": { "id": "<SKU_UUID>" }
      }'

Common errors

StatusMost likely cause
400x-store-id header is missing, or the GraphQL selection is invalid (for example selecting id on the Option union without ... on ListOption). A path {storeId} that doesn't match the header is not a 400 — the subgraph still uses x-store-id.
401PAT is missing or expired. Go to Authentication to generate a new token.
403Token doesn't include commerce.product:read or commerce.product:write.
404SKU or SKU group ID doesn't exist or isn't accessible with the provided token.
429Rate limit exceeded (RateLimit-Remaining: 0). Wait RateLimit-Reset seconds, or Retry-After if present. Do not assume 60 req/min.

HTTP 200 doesn't mean success

GraphQL requests may return HTTP 200 even when there are errors. Always check the errors array in the response body. Schema validation errors (unknown fields, missing variables) return HTTP 400, but runtime errors (invalid UUIDs, business rule violations) return HTTP 200 with an errors array alongside data.

GraphQL behavior notes

Non-existent IDs return null

When you query an entity by ID (for example skuGroup(id: "...") or sku(id: "...")), a non-existent or inaccessible ID returns null with no error. This is standard GraphQL behavior, not a failure.

{
  "data": {
    "skuGroup": null
  }
}

Placeholder UUIDs in documentation

Code examples in the API reference use placeholder UUIDs like ID_VALUE or 497f6eca-6276-4993-bfeb-53cbbbba6f08. These are documentation placeholders — replace them with real IDs from your store. Querying a placeholder UUID returns null.

References are read via parent objects

There is no top-level reference(id: ...) query. References follow a HATEOAS pattern — you read them through the parent object they're attached to:

# Read references on a SKU group
query {
  skuGroup(id: "your-sku-group-id") {
    references {
      edges {
        node {
          id
          type
          value
        }
      }
    }
  }
}

To manage references, use mutations like addReferencesToSkuGroup, removeReferencesFromSkuGroup, addReferencesToSku, etc.

Agent & Automation Notes

Scopescommerce.product:read, commerce.product:write
Rate limitRead RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset on each catalog-subgraph response. On 429, wait RateLimit-Reset or Retry-After.
IdempotentNo
DestructiveNo
On failureQuery operations are safe to retry. For mutations, check the current state before retrying to avoid duplicate creates.

Last updated on

How is this guide?

On this page