A reliable Shopify integration uses the GraphQL Admin API, stays inside its rate limits, pages with cursors, verifies every webhook and retries failures with backoff.
This guide covers each of those. They’re the integration checks I make on every Shopify project.
GraphQL first, REST only where you must
Shopify made the REST Admin API legacy in October 2024. New public apps have had to use the GraphQL Admin API since April 2025, and new features only arrive in GraphQL. Existing integrations can keep using REST for now, but write new code against GraphQL.
GraphQL also suits most integration work better:
- Ask for exactly the fields you need
- Fetch related data in one request
- Some features, such as metaobjects and stores with large variant counts, only work through GraphQL
Example GraphQL query:
{
products(first: 3) {
edges {
node {
id
title
variants(first: 2) { edges { node { price } } }
}
}
}
}
Authentication options
Each kind of app authenticates differently:
- Custom apps for a single store: an Admin API access token issued when the app is installed, sent in the
X-Shopify-Access-Tokenheader - Embedded apps: session tokens from App Bridge, exchanged for an access token on your backend
- Standalone public apps: the OAuth authorization code grant
“Private apps” with basic auth no longer exist. Shopify replaced them with custom apps in 2022.
Never expose tokens on the frontend. Keep them in environment variables or a secrets manager.
Handle rate limiting
The two APIs limit you differently.
REST uses a leaky bucket per app per store. On standard plans the bucket holds 40 requests and drains at 2 a second. Shopify Plus stores get ten times that: 400 requests, draining at 20 a second.
GraphQL charges each query a calculated cost in points. The restore rate depends on the store’s plan, from 100 points a second on standard plans to 1,000 on Shopify Plus. No single query may cost more than 1,000 points.
Staying under the limits
- For REST, read
X-Shopify-Shop-Api-Call-Limitto see how full the bucket is, and wait forRetry-Afterseconds after a429 - For GraphQL, read
extensions.costin each response.throttleStatusshows how many points are available and how fast they come back - Request only the fields you use. Large
first:values and nested connections push query cost up quickly - Use bulk operations for large exports instead of paging through thousands of records
Pagination
Use cursor-based pagination in GraphQL:
products(first: 50, after: $cursor) {
pageInfo { hasNextPage endCursor }
edges { node { id title } }
}
Legacy REST endpoints also use cursors, through page_info in the Link header:
Link: <https://...&page_info=abc>; rel="next"
The old page=2 parameter no longer works.
Webhooks
Webhooks tell your integration when something changes:
orders/paidproducts/updatecustomers/create
Verify every delivery before trusting it. Shopify signs the raw request body with your app’s client secret and sends the base64 signature in the X-Shopify-Hmac-SHA256 header:
const digest = crypto.createHmac("sha256", clientSecret).update(rawBody).digest();
const received = Buffer.from(req.get("X-Shopify-Hmac-SHA256"), "base64");
const valid = digest.length === received.length && crypto.timingSafeEqual(digest, received);
Use the raw body. If a JSON parser has already touched it, the signature won’t match.
Shopify waits five seconds at most for your 200 OK. Store the payload, respond, and process it in a queue.
Webhooks can arrive late, twice or not at all. Make handlers safe to run twice, and run a scheduled reconciliation job for anything that matters, such as stock or order status.
Retries and errors
- Retry on rate limits and 5xx errors, not on validation errors
- Use exponential backoff with some random jitter, so parallel workers don’t retry in step
- Cap the number of retries, then alert someone
- Log failed requests with enough context to replay them, but never log access tokens or customer personal data
Secure your requests
- Always use HTTPS
- Validate incoming parameters
- Never put tokens in URLs or query strings
- Ask for the narrowest access scopes the app needs
Related reading
I follow these rules when I connect a store to its CRM, finance provider or stock system, as part of the Shopify app integrations I build.
Published , updated .
Part 5 of Shopify Essentials.