Calls Shopify Admin and Storefront GraphQL over curl with X-Shopify-Access-Token, GID ids, bulk operations, and webhooks, without an SDK. Use when listing or updating products, orders, customers, inventory, or metafields on a myshopify.com shop. Not for Liquid themes, Hydrogen storefronts, or the frozen REST Admin API. Do not run destructive mutations on production without confirmation.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Calls Shopify Admin and Storefront GraphQL over curl with X-Shopify-Access-Token, GID ids, bulk operations, and webhooks, without an SDK. Use when listing or updating products, orders, customers, inventory, or metafields on a myshopify.com shop. Not for Liquid themes, Hydrogen storefronts, or the frozen REST Admin API. Do not run destructive mutations on production without confirmation.
[{"name":"SHOPIFY_ACCESS_TOKEN","prompt":"Shopify Admin API access token (starts with shpat_)","help":"Shopify admin → Settings → Apps and sales channels → Develop apps → Create an app → API credentials. Token shown ONCE on install."},{"name":"SHOPIFY_STORE_DOMAIN","prompt":"Your shop subdomain without protocol (e.g. my-store.myshopify.com)","help":"The permanent myshopify.com domain, not your custom domain."},{"name":"SHOPIFY_API_VERSION","prompt":"Shopify API version (default 2026-01)","help":"Stable quarterly version. Override if you need an older one."}]
Work with Shopify stores directly through curl: list products, manage inventory, pull orders, update customers, read metafields. No SDK, no app framework — just the GraphQL endpoint and a custom-app access token.
The REST Admin API is legacy since 2024-04 and only receives security fixes. Use GraphQL Admin for all admin work. Use Storefront GraphQL for read-only customer-facing queries (products, collections, cart).
When to Use
Listing, searching, creating, or updating products, variants, and inventory
Pulling orders, customers, fulfillments, or draft orders
Reading or writing metafields and metaobjects on any resource
Running bulk exports of large catalogs or historical order data
Subscribing to webhooks for event-driven workflows
Building headless / Storefront API queries for customer-facing apps
Any task mentioning "Shopify," "store admin," "product catalog," "shopify GraphQL," or "myshopify.com"
Prerequisites
In Shopify admin: Settings → Apps and sales channels → Develop apps → Create an app.
Click Configure Admin API scopes, select what you need (examples below), save.
Install app → the Admin API access token appears ONCE. Copy it immediately — Shopify will never show it again. Tokens start with shpat_.
Heads up: As of January 1, 2026, new "legacy custom apps" created in the Shopify admin are gone. New setups should use the Dev Dashboard (shopify.dev/docs/apps/build/dev-dashboard). Existing admin-created apps keep working. If the user's shop has no existing custom app and it's after 2026-01-01, direct them to Dev Dashboard instead of the admin flow.
Method: always POST, always Content-Type: application/json, body is {"query": "...", "variables": {...}}
HTTP 200 does not mean success. GraphQL returns errors in a top-level errors array and per-field userErrors. Always check both.
IDs are GID strings:gid://shopify/Product/10079467700516, gid://shopify/Variant/..., gid://shopify/Order/.... Pass these verbatim — don't strip the prefix.
Rate limit: calculated via query cost (leaky bucket). Each response has extensions.cost with requestedQueryCost, actualQueryCost, throttleStatus.{currentlyAvailable, maximumAvailable, restoreRate}. Back off when currentlyAvailable drops below your next query's cost. Standard shops = 100 points bucket, 50/s restore; Plus = 1000/100.
Pipe through jq for readable output. -sS keeps errors visible but hides the progress bar.
Windows (PowerShell): If running on a Windows host, use curl.exe (built into Windows 10+) and jq from a package manager like scoop install jq. The bash function above works inside WSL or Git Bash. In native PowerShell, inline the curl command with here-strings for the JSON body.
Step 2 — Verify connectivity (Discovery)
shop_gql '{ shop { name myshopifyDomain primaryDomain { url } currencyCode plan { displayName } } }' | jq
Inventory lives on inventory items tied to variants, quantities tracked per location.
# Get inventory for a variant across all locations
shop_gql '
query($id: ID!) {
productVariant(id: $id) {
id sku
inventoryItem {
id tracked
inventoryLevels(first: 10) {
edges { node { location { id name } quantities(names: ["available","on_hand","committed"]) { name quantity } } }
}
}
}
}''{"id":"gid://shopify/ProductVariant/..."}'
REST endpoints still exist but are frozen. Don't write new integrations against /admin/api/.../products.json. Use GraphQL.
Token format check. Admin tokens start with shpat_. Storefront public tokens with shpua_. If you have one and the wrong header, every request returns 401 without a useful error body.
403 with a valid token = missing scope. Shopify returns {"errors":[{"message":"Access denied for ..."}]}. Re-configure Admin API scopes on the app, then reinstall to regenerate the token.
userErrors is empty != success. Also check data.<mutation>.<resource> is non-null. Some failures populate neither — inspect the whole response.
GID vs numeric ID. Legacy REST gave numeric IDs; GraphQL wants full GID strings. To convert: gid://shopify/Product/<numeric>.
Rate limit surprise. A single products(first: 250) with deep nesting can cost 1000+ points and throttle immediately on a standard-plan shop. Start narrow, read extensions.cost, adjust.
Pagination order.products(first: N, reverse: true) sorts by id DESC, not created_at. Use sortKey: CREATED_AT, reverse: true for "newest first."
read_all_orders for historical data. Without it, orders(...) silently caps at the 60-day window. You won't get an error, just fewer results than expected. For Shopify Plus merchants with many orders, request this scope via the app's protected-data settings.
Currencies are strings. Amounts come back as "49.00" not 49.0. Don't jq tonumber blindly if you care about zero-padding.
Multi-currency Money fields have shopMoney (store's currency) AND presentmentMoney (customer's). Pick one consistently.
Mutations are live on production. Before running productDelete, orderCancel, refundCreate, or any bulk mutation: state clearly what the change is, on which shop, and confirm with the user. There is no staging clone of production data unless the user has a separate dev store.
Verification
Confirm env vars are set:
echo"Token prefix: ${SHOPIFY_ACCESS_TOKEN:0:6}"# should print: shpat_echo"Domain: ${SHOPIFY_STORE_DOMAIN}"echo"API version: ${SHOPIFY_API_VERSION:-2026-01}"
Confirm connectivity and auth:
shop_gql '{ shop { name myshopifyDomain plan { displayName } } }' | jq
Expected: a JSON object with data.shop.name populated. If you see errors with "Access denied," the token is wrong or scopes are missing.
Confirm a read query works:
shop_gql '{ products(first: 1) { edges { node { id title } } } }' | jq '.data.products.edges | length'
Expected: 0 or 1 (not an error object).
Check rate-limit status after a query:
shop_gql '{ shop { name } }' | jq '.extensions.cost.throttleStatus'
Expected: object with currentlyAvailable, maximumAvailable, restoreRate.