api-graphql

Work with Shopify GraphQL APIs including Admin API and Storefront API. Use this skill for querying and mutating Shopify data, managing products, orders, customers, handling pagination, working with metafields, and understanding rate limits. Covers authentication, queries, mutations, and webhooks.

dragnoir/shopify-agent-skills18 installsMITSynced Aug 22

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: api-graphql
description: Work with Shopify GraphQL APIs including Admin API and Storefront API. Use this skill for querying and mutating Shopify data, managing products, orders, customers, handling pagination, working with metafields, and understanding rate limits. Covers authentication, queries, mutations, and webhooks.
license: MIT
---

# Shopify GraphQL APIs

## When to use this skill

Use this skill when:

- Querying Shopify data (products, orders, customers)
- Creating or updating resources via mutations
- Building integrations with Shopify stores
- Working with metafields and metaobjects
- Handling pagination in API responses
- Managing API authentication and rate limits

## API Types

### Admin API

- Full store access (backend only)
- Requires authentication (OAuth or API key)
- Used by apps and integrations

### Storefront API

- Public storefront access
- Uses public access token
- Safe for frontend/client-side

## Getting Started

### Admin API Authentication

```javascript
// Using @shopify/shopify-api
import { shopifyApi, LATEST_API_VERSION } from "@shopify/shopify-api";

const shopify = shopifyApi({
  apiKey: process.env.SHOPIFY_API_KEY,
  apiSecretKey: process.env.SHOPIFY_API_SECRET,
  scopes: ["read_products", "write_products"],
  hostName: "your-app.com",
  apiVersion: LATEST_API_VERSION,
});
```

### Making Requests

```javascript
// In a Remix app route
import { authenticate } from "../shopify.server";

export async function loader({ request }) {
  const { admin } = await authenticate.admin(request);

  const response = await admin.graphql(`
    query {
      products(first: 10) {
        nodes {
          id
          title
        }
      }
    }
  `);

  return response.json();
}
```

## Common Queries

### Products

```graphql
# Get products with variants
query GetProducts($first: Int!, $after: String) {
  products(first: $first, after: $after) {
    pageInfo {
      hasNextPage
      endCursor
    }
    nodes {
      id
      title
      handle
      description
      status
      vendor
      productType
      tags
      featuredImage {
        url
        altText
      }
      variants(first: 10) {
        nodes {
          id
          title
          sku
          price
          compareAtPrice
          inventoryQuantity
          selectedOptions {
            name
            value
          }
        }
      }
      priceRange {
        minVariantPrice {
          amount
          currencyCode
        }
        maxVariantPrice {
          amount
          currencyCode
        }
      }
    }
  }
}
```

```graphql
# Get single product by ID
query GetProduct($id: ID!) {
  product(id: $id) {
    id
    title
    description
    variants(first: 100) {
      nodes {
        id
        title
        price
      }
    }
  }
}

# Get product by handle
query GetProductByHandle($handle: String!) {
  productByHandle(handle: $handle) {
    id
    title
  }
}
```

### Orders

```graphql
query GetOrders($first: Int!, $query: String) {
  orders(first: $first, query: $query) {
    nodes {
      id
      name
      email
      createdAt
      displayFinancialStatus
      displayFulfillmentStatus
      totalPriceSet {
        shopMoney {
          amount
          currencyCode
        }
      }
      customer {
        id
        firstName
        lastName
        email
      }
      lineItems(first: 50) {
        nodes {
          id
          title
          quantity
          variant {
            id
            sku
          }
          originalTotalSet {
            shopMoney {
              amount
            }
          }
        }
      }
      shippingAddress {
        address1
        city
        province
        country
        zip
      }
    }
  }
}
```

### Customers

```graphql
query GetCustomers($first: Int!, $query: String) {
  customers(first: $first, query: $query) {
    nodes {
      id
      firstName
      lastName
      email
      phone
      ordersCount
      totalSpent {
        amount
        currencyCode
      }
      addresses(first: 5) {
        address1
        city
        province
        country
        zip
      }
      tags
      createdAt
    }
  }
}
```

### Collections

```graphql
query GetCollection($handle: String!) {
  collectionByHandle(handle: $handle) {
    id
    title
    description
    products(first: 20) {
      nodes {
        id
        title
        featuredImage {
          url
        }
      }
    }
  }
}
```

### Inventory

```graphql
query GetInventory($locationId: ID!) {
  location(id: $locationId) {
    inventoryLevels(first: 100) {
      nodes {
        id
        available
        item {
          id
          variant {
            id
            displayName
            sku
          }
        }
      }
    }
  }
}
```

## Common Mutations

### Create Product

```graphql
mutation CreateProduct($input: ProductInput!) {
  productCreate(input: $input) {
    product {
      id
      title
      handle
    }
    userErrors {
      field
      message
    }
  }
}
```

Variables:

```json
{
  "input": {
    "title": "New Product",
    "descriptionHtml": "<p>Product description</p>",
    "vendor": "My Store",
    "productType": "Apparel",
    "tags": ["new", "featured"],
    "variants": [
      {
        "price": "29.99",
        "sku": "NEW-001",
        "inventoryManagement": "SHOPIFY",
        "inventoryPolicy": "DENY"
      }
    ]
  }
}
```

### Update Product

```graphql
mutation UpdateProduct($input: ProductInput!) {
  productUpdate(input: $input) {
    product {
      id
      title
    }
    userErrors {
      field
      message
    }
  }
}
```

Variables:

```json
{
  "input": {
    "id": "gid://shopify/Product/123456",
    "title": "Updated Title",
    "tags": ["sale", "featured"]
  }
}
```

### Create Order

```graphql
mutation CreateDraftOrder($input: DraftOrderInput!) {
  draftOrderCreate(input: $input) {
    draftOrder {
      id
      invoiceUrl
    }
    userErrors {
      field
      message
    }
  }
}
```

### Update Inventory

```graphql
mutation AdjustInventory($input: InventoryAdjustQuantityInput!) {
  inventoryAdjustQuantity(input: $input) {
    inventoryLevel {
      available
    }
    userErrors {
      field
      message
    }
  }
}
```

Variables:

```json
{
  "input": {
    "inventoryLevelId": "gid://shopify/InventoryLevel/123456",
    "availableDelta": 10
  }
}
```

## Metafields

### Read Metafields

```graphql
# Product metafields
query GetProductMetafields($id: ID!) {
  product(id: $id) {
    metafields(first: 20) {
      nodes {
        id
        namespace
        key
        value
        type
      }
    }
    # Specific metafield
    careInstructions: metafield(namespace: "custom", key: "care_instructions") {
      value
    }
  }
}
```

### Write Metafields

```graphql
mutation SetMetafields($metafields: [MetafieldsSetInput!]!) {
  metafieldsSet(metafields: $metafields) {
    metafields {
      id
      key
      value
    }
    userErrors {
      field
      message
    }
  }
}
```

Variables:

```json
{
  "metafields": [
    {
      "ownerId": "gid://shopify/Product/123456",
      "namespace": "custom",
      "key": "care_instructions",
      "value": "Machine wash cold",
      "type": "single_line_text_field"
    },
    {
      "ownerId": "gid://shopify/Product/123456",
      "namespace": "custom",
      "key": "dimensions",
      "value": "{\"width\": 10, \"height\": 20, \"depth\": 5}",
      "type": "json"
    }
  ]
}
```

### Metafield Types

| Type                     | Description | Example Value            |
| ------------------------ | ----------- | ------------------------ |
| `single_line_text_field` | Short text  | `"Hello"`                |
| `multi_line_text_field`  | Long text   | `"Line 1\nLine 2"`       |
| `number_integer`         | Integer     | `"42"`                   |
| `number_decimal`         | Decimal     | `"19.99"`                |
| `boolean`                | True/False  | `"true"`                 |
| `date`                   | Date        | `"2025-01-15"`           |
| `json`                   | JSON object | `"{\"key\": \"value\"}"` |
| `url`                    | URL         | `"https://example.com"`  |
| `color`                  | Color hex   | `"#FF0000"`              |

## Pagination

### Cursor-Based Pagination

```javascript
async function getAllProducts(admin) {
  let products = [];
  let hasNextPage = true;
  let cursor = null;

  while (hasNextPage) {
    const response = await admin.graphql(
      `
      query GetProducts($first: Int!, $after: String) {
        products(first: $first, after: $after) {
          pageInfo {
            hasNextPage
            endCursor
          }
          nodes {
            id
            title
          }
        }
      }
    `,
      {
        variables: { first: 50, after: cursor },
      },
    );

    const data = await response.json();
    products = [...products, ...data.data.products.nodes];
    hasNextPage = data.data.products.pageInfo.hasNextPage;
    cursor = data.data.products.pageInfo.endCursor;
  }

  return products;
}
```

## Rate Limits

### Understanding Cost

```graphql
query {
  products(first: 100) {
    nodes {
      id
      title
    }
  }
}
```

Response includes:

```json
{
  "extensions": {
    "cost": {
      "requestedQueryCost": 102,
      "actualQueryCost": 52,
      "throttleStatus": {
        "maximumAvailable": 2000,
        "currentlyAvailable": 1948,
        "restoreRate": 100
      }
    }
  }
}
```

### Handling Rate Limits

```javascript
async function queryWithRetry(admin, query, variables, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await admin.graphql(query, { variables });
      const data = await response.json();

      if (data.errors?.some((e) => e.extensions?.code === "THROTTLED")) {
        const waitTime = Math.pow(2, attempt) * 1000;
        await new Promise((resolve) => setTimeout(resolve, waitTime));
        continue;
      }

      return data;
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
    }
  }
}
```

## Storefront API

### Authentication

```javascript
const storefrontClient = new StorefrontApiClient({
  privateAccessToken: process.env.STOREFRONT_ACCESS_TOKEN,
  storeDomain: "your-store.myshopify.com",
  apiVersion: "2025-01",
});
```

### Product Query (Storefront)

```graphql
query GetProduct($handle: String!) {
  product(handle: $handle) {
    id
    title
    description
    images(first: 5) {
      nodes {
        url
        altText
      }
    }
    variants(first: 100) {
      nodes {
        id
        title
        price {
          amount
          currencyCode
        }
        availableForSale
      }
    }
  }
}
```

### Cart Operations (Storefront)

```graphql
# Create cart
mutation CreateCart($lines: [CartLineInput!]!) {
  cartCreate(input: { lines: $lines }) {
    cart {
      id
      checkoutUrl
      lines(first: 10) {
        nodes {
          id
          quantity
          merchandise {
            ... on ProductVariant {
              title
            }
          }
        }
      }
    }
  }
}

# Add to cart
mutation AddToCart($cartId: ID!, $lines: [CartLineInput!]!) {
  cartLinesAdd(cartId: $cartId, lines: $lines) {
    cart {
      id
      lines(first: 10) {
        nodes {
          id
          quantity
        }
      }
    }
  }
}
```

## Webhooks

### Subscribe to Webhooks

```graphql
mutation WebhookSubscriptionCreate(
  $topic: WebhookSubscriptionTopic!
  $webhookSubscription: WebhookSubscriptionInput!
) {
  webhookSubscriptionCreate(
    topic: $topic
    webhookSubscription: $webhookSubscription
  ) {
    webhookSubscription {
      id
      topic
      endpoint {
        ... on WebhookHttpEndpoint {
          callbackUrl
        }
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

Variables:

```json
{
  "topic": "PRODUCTS_CREATE",
  "webhookSubscription": {
    "callbackUrl": "https://your-app.com/webhooks",
    "format": "JSON"
  }
}
```

### Webhook Topics

| Topic                     | Description       |
| ------------------------- | ----------------- |
| `PRODUCTS_CREATE`         | Product created   |
| `PRODUCTS_UPDATE`         | Product updated   |
| `PRODUCTS_DELETE`         | Product deleted   |
| `ORDERS_CREATE`           | Order placed      |
| `ORDERS_UPDATED`          | Order modified    |
| `ORDERS_PAID`             | Order paid        |
| `CUSTOMERS_CREATE`        | Customer created  |
| `INVENTORY_LEVELS_UPDATE` | Inventory changed |

## Bulk Operations

### Bulk Query

```graphql
mutation BulkProducts {
  bulkOperationRunQuery(
    query: """
    {
      products {
        edges {
          node {
            id
            title
            variants {
              edges {
                node {
                  id
                  sku
                  price
                }
              }
            }
          }
        }
      }
    }
    """
  ) {
    bulkOperation {
      id
      status
    }
    userErrors {
      field
      message
    }
  }
}
```

### Poll Bulk Operation

```graphql
query BulkOperationStatus {
  currentBulkOperation {
    id
    status
    objectCount
    url
  }
}
```

## Best Practices

1. **Request only needed fields** - Reduces cost and response size
2. **Use fragments** - Reuse common field selections
3. **Handle errors** - Check for userErrors in mutations
4. **Implement pagination** - Don't request all records at once
5. **Monitor rate limits** - Use throttle status in responses
6. **Use bulk operations** - For large data exports

## Resources

- [Admin API Reference](https://shopify.dev/docs/api/admin-graphql)
- [Storefront API Reference](https://shopify.dev/docs/api/storefront)
- [GraphQL Basics](https://shopify.dev/docs/apps/build/graphql)
- [Rate Limits](https://shopify.dev/docs/api/usage/rate-limits)
- [Webhooks Reference](https://shopify.dev/docs/api/admin-graphql/latest/enums/WebhookSubscriptionTopic)
- [GraphiQL Explorer](https://shopify.dev/docs/apps/build/graphql/basics/graphiql)

For app integration, see the [app-development](../app-development/SKILL.md) skill.

More API Design skills

← All API Design skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY