{
  "openapi": "3.1.1",
  "info": {
    "title": "Catalog GraphQL API",
    "version": "2.0.0",
    "description": "Commerce catalog **GraphQL subgraph** for a store. Send standard GraphQL POST requests (query, variables, operationName) to this HTTP endpoint."
  },
  "servers": [
    {
      "url": "https://api.godaddy.com/v2/commerce",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Catalog subgraph",
      "description": "Execute GraphQL operations against the commerce catalog subgraph for a store. The GraphQL schema is referenced from this repository for tooling and review (`x-godaddy-graphql-schema`)."
    }
  ],
  "paths": {
    "/stores/{storeId}/catalog-subgraph": {
      "post": {
        "operationId": "postCatalogGraphql",
        "summary": "Catalog GraphQL endpoint",
        "description": "Proxies GraphQL to the catalog subgraph. Use the `query` field for the GraphQL document and optional `variables` / `operationName`. 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. This endpoint is rate-limited per credential per window. Read the RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset response headers; do not assume 60 requests per minute. Exceeding the live limit returns HTTP 429; honor RateLimit-Reset or Retry-After before retrying.",
        "tags": [
          "Catalog subgraph"
        ],
        "x-godaddy-graphql-schema": "./graphql/schema.graphql",
        "x-codeSamples": [
          {
            "lang": "graphql",
            "label": "GraphQL",
            "source": "query GetSku($id: String!) {\n  sku(id: $id) {\n    id\n    name\n    status\n  }\n}"
          },
          {
            "id": "direct-api-access",
            "lang": "js",
            "label": "Direct API Access",
            "source": "const response = await fetch(\n  'https://api.godaddy.com/v2/commerce/stores/{storeId}/catalog-subgraph',\n  {\n    method: 'POST',\n    headers: {\n      Authorization: 'Bearer $ACCESS_TOKEN',\n      'Content-Type': 'application/json',\n      'x-store-id': '{storeId}',\n    },\n    body: JSON.stringify({\n      query: `\n        query GetSku($id: String!) {\n          sku(id: $id) {\n            id\n            name\n            status\n          }\n        }\n      `,\n      variables: { id: 'SKU_ID' },\n    }),\n  },\n);\n\nconst { data } = await response.json();\nconsole.log(data);"
          }
        ],
        "security": [
          {
            "PAT": [
              "commerce.product:read"
            ]
          },
          {
            "PAT": [
              "commerce.product:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "storeId",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/x-ext/38af770"
            }
          },
          {
            "name": "x-store-id",
            "in": "header",
            "required": true,
            "description": "Required store ID. Send the same value as `{storeId}` in the path. If they differ, the subgraph uses this header.",
            "schema": {
              "$ref": "#/x-ext/38af770"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query"
                ],
                "properties": {
                  "query": {
                    "type": "string"
                  },
                  "variables": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "operationName": {
                    "type": "string"
                  }
                }
              },
              "examples": {
                "default": {
                  "value": {
                    "query": "query GetSku($id: String!) { sku(id: $id) { id name status } }",
                    "variables": {
                      "id": "SKU_ID"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GraphQL response. RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset are present on every response (including 200).",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/x-ext/f5fae09"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/x-ext/f5fae09"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/x-ext/f5fae09"
                }
              }
            }
          },
          "404": {
            "description": "Store not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/x-ext/f5fae09"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (RateLimit-Remaining is 0). Wait RateLimit-Reset seconds. Honor Retry-After when the gateway sends it.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/x-ext/f5fae09"
                }
              }
            }
          },
          "500": {
            "description": "Internal server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/x-ext/f5fae09"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "headers": {
      "RateLimitLimit": {
        "description": "Requests allowed in the current window. Value is set by the gateway (not 60/min). Read this header; do not hardcode it.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Requests remaining in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Seconds until the current window resets.",
        "schema": {
          "type": "integer"
        }
      },
      "RetryAfter": {
        "description": "Seconds until the client may retry, when present. Prefer RateLimit-Reset if both headers are sent.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "securitySchemes": {
      "PAT": {
        "type": "http",
        "scheme": "bearer",
        "description": "Personal Access Token (PAT). Include as `Authorization: Bearer $GODADDY_PAT`. Required scopes: `commerce.product:read`, `commerce.product:write`."
      }
    }
  },
  "x-ext-urls": {
    "38af770": "../common-types/v1/schemas/json/uuid.json",
    "f5fae09": "../common-types/v1/schemas/json/error.json",
    "e450f2f": "../common-types/v1/schemas/json/error-details.json",
    "1f8da99": "../common-types/v1/schemas/json/link-description.json"
  },
  "x-ext": {
    "38af770": {
      "description": "A universally unique identifier (UUID) in [RFC-4122 format](https://tools.ietf.org/html/rfc4122).",
      "type": "string",
      "format": "uuid"
    },
    "e450f2f": {
      "title": "Error Details",
      "type": "object",
      "description": "The error details. Required for client-side `4XX` errors.",
      "properties": {
        "field": {
          "type": "string",
          "description": "The field that caused the error. If the field is in the body, set this value to the JSON pointer to that field. Required for client-side errors."
        },
        "value": {
          "type": "string",
          "description": "The value of the field that caused the error."
        },
        "location": {
          "type": "string",
          "description": "The location of the field that caused the error. Value is `body`, `path`, or `query`.",
          "default": "body"
        },
        "issue": {
          "type": "string",
          "description": "The unique fine-grained application-level error code."
        },
        "description": {
          "type": "string",
          "description": "The human-readable description for an issue. The description MAY change over the lifetime of an API, so clients MUST NOT depend on this value."
        }
      },
      "required": [
        "issue"
      ]
    },
    "1f8da99": {
      "title": "Link Description",
      "type": "object",
      "description": "A request-related [HATEOAS link](https://datatracker.ietf.org/doc/html/draft-handrews-json-schema-hyperschema-02).",
      "properties": {
        "href": {
          "description": "The complete target URL, or link, to use in combination with the method to make the related call, as defined by [RFC 6570 - URI Template](https://tools.ietf.org/html/rfc6570), with the addition of the `$`, `(`, and `)` characters for pre-processing. The `href` is the key HATEOAS component that links a completed call with a subsequent call.",
          "type": "string",
          "format": "uri"
        },
        "rel": {
          "description": "The [link relation type](https://tools.ietf.org/html/rfc5988#section-4), which is an identifier for a link that unambiguously describes the semantics of the link. For values, see [Link Relationship Types](https://www.iana.org/assignments/link-relations/link-relations.xhtml).",
          "type": "string"
        },
        "title": {
          "description": "The link title.",
          "type": "string"
        },
        "targetMediaType": {
          "description": "The [RFC 2046-defined media type](https://www.ietf.org/rfc/rfc2046.txt) that describes the link target.",
          "type": "string"
        },
        "targetSchema": {
          "description": "The schema that describes the link target."
        },
        "method": {
          "description": "The method to use to request the link target. For example, for HTTP, this might be `GET` or `DELETE`.",
          "type": "string"
        },
        "submissionMediaType": {
          "description": "The media type with which to submit data with the request.",
          "type": "string",
          "default": "application/json"
        },
        "submissionSchema": {
          "description": "The schema that describes the request data."
        }
      },
      "required": [
        "rel",
        "href"
      ]
    },
    "f5fae09": {
      "type": "object",
      "title": "Error",
      "description": "The error information.",
      "definitions": {
        "error-details": {
          "$ref": "#/x-ext/e450f2f"
        },
        "link-description": {
          "$ref": "#/x-ext/1f8da99"
        }
      },
      "properties": {
        "name": {
          "type": "string",
          "description": "The human-readable, unique name of the error."
        },
        "correlationId": {
          "type": "string",
          "description": "Internal identifier used for correlation purposes."
        },
        "message": {
          "type": "string",
          "description": "The message that describes the error."
        },
        "informationLink": {
          "type": "string",
          "description": "The URI for detailed information related to this error for the developer."
        },
        "details": {
          "type": "array",
          "description": "An array of additional details about the error. Required for client-side `4XX` errors.",
          "additionalItems": false,
          "items": {
            "$ref": "#/x-ext/f5fae09/definitions/error-details"
          }
        },
        "links": {
          "type": "array",
          "description": "An array of error-related HATEOAS links.",
          "readOnly": true,
          "items": {
            "$ref": "#/x-ext/f5fae09/definitions/link-description",
            "readOnly": true
          }
        }
      },
      "required": [
        "name",
        "correlationId",
        "message"
      ]
    }
  }
}
