api-graphql
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
// 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
// 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
# 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
}
}
}
}
}
# 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
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
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
query GetCollection($handle: String!) {
collectionByHandle(handle: $handle) {
id
title
description
products(first: 20) {
nodes {
id
title
featuredImage {
url
}
}
}
}
}
Inventory
query GetInventory($locationId: ID!) {
location(id: $locationId) {
inventoryLevels(first: 100) {
nodes {
id
available
item {
id
variant {
id
displayName
sku
}
}
}
}
}
}
Common Mutations
Create Product
mutation CreateProduct($input: ProductInput!) {
productCreate(input: $input) {
product {
id
title
handle
}
userErrors {
field
message
}
}
}
Variables:
{
"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
mutation UpdateProduct($input: ProductInput!) {
productUpdate(input: $input) {
product {
id
title
}
userErrors {
field
message
}
}
}
Variables:
{
"input": {
"id": "gid://shopify/Product/123456",
"title": "Updated Title",
"tags": ["sale", "featured"]
}
}
Create Order
mutation CreateDraftOrder($input: DraftOrderInput!) {
draftOrderCreate(input: $input) {
draftOrder {
id
invoiceUrl
}
userErrors {
field
message
}
}
}
Update Inventory
mutation AdjustInventory($input: InventoryAdjustQuantityInput!) {
inventoryAdjustQuantity(input: $input) {
inventoryLevel {
available
}
userErrors {
field
message
}
}
}
Variables:
{
"input": {
"inventoryLevelId": "gid://shopify/InventoryLevel/123456",
"availableDelta": 10
}
}
Metafields
Read Metafields
# 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
mutation SetMetafields($metafields: [MetafieldsSetInput!]!) {
metafieldsSet(metafields: $metafields) {
metafields {
id
key
value
}
userErrors {
field
message
}
}
}
Variables:
{
"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
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
query {
products(first: 100) {
nodes {
id
title
}
}
}
Response includes:
{
"extensions": {
"cost": {
"requestedQueryCost": 102,
"actualQueryCost": 52,
"throttleStatus": {
"maximumAvailable": 2000,
"currentlyAvailable": 1948,
"restoreRate": 100
}
}
}
}
Handling Rate Limits
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
const storefrontClient = new StorefrontApiClient({
privateAccessToken: process.env.STOREFRONT_ACCESS_TOKEN,
storeDomain: "your-store.myshopify.com",
apiVersion: "2025-01",
});
Product Query (Storefront)
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)
# 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
mutation WebhookSubscriptionCreate(
$topic: WebhookSubscriptionTopic!
$webhookSubscription: WebhookSubscriptionInput!
) {
webhookSubscriptionCreate(
topic: $topic
webhookSubscription: $webhookSubscription
) {
webhookSubscription {
id
topic
endpoint {
... on WebhookHttpEndpoint {
callbackUrl
}
}
}
userErrors {
field
message
}
}
}
Variables:
{
"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
mutation BulkProducts {
bulkOperationRunQuery(
query: """
{
products {
edges {
node {
id
title
variants {
edges {
node {
id
sku
price
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
Poll Bulk Operation
query BulkOperationStatus {
currentBulkOperation {
id
status
objectCount
url
}
}
Best Practices
- Request only needed fields - Reduces cost and response size
- Use fragments - Reuse common field selections
- Handle errors - Check for userErrors in mutations
- Implement pagination - Don't request all records at once
- Monitor rate limits - Use throttle status in responses
- Use bulk operations - For large data exports
Resources
- Admin API Reference
- Storefront API Reference
- GraphQL Basics
- Rate Limits
- Webhooks Reference
- GraphiQL Explorer
For app integration, see the app-development skill.
More from dragnoir/shopify-agent-skills
headless-hydrogen
Build headless Shopify storefronts with Hydrogen and Oxygen. Use this skill for creating custom React-based storefronts, using Hydrogen components, deploying to Oxygen hosting, working with the Storefront API, and building high-performance e-commerce experiences. Also covers bringing your own stack with custom frameworks.
37app-development
Build Shopify apps with extensions and embedded experiences. Use this skill for creating new Shopify apps, adding app extensions, building admin interfaces, working with OAuth authentication, managing app configuration, and deploying to the Shopify App Store. Covers Shopify CLI for apps, Polaris UI, and app bridge.
13theme-development
Build, customize, and deploy Shopify themes. Use this skill for creating new themes, modifying existing themes, understanding theme architecture, working with sections/blocks, and optimizing theme performance. Covers Skeleton theme, Dawn theme, layouts, templates, and the theme editor customization experience.
12liquid-templating
Master Shopify Liquid templating language. Use this skill for writing Liquid code, using objects, filters, and tags, accessing product/collection/cart data, creating dynamic content, handling conditionals and loops, and working with Liquid best practices. Essential for theme customization.
12checkout-customization
Customize Shopify checkout with UI extensions and functions. Use this skill for building checkout UI extensions, adding custom fields, implementing payment customizations, creating post-purchase experiences, and extending customer accounts. Covers Checkout UI Extensions API and checkout branding.
12shopify-functions
Build backend logic with Shopify Functions. Use this skill for creating custom discounts, delivery customization, payment customization, cart and checkout validation, and order routing. Functions run on Shopify's infrastructure using WebAssembly. Supports Rust and JavaScript.
12