A Shopify API integration starts with a clear data boundary. Products, orders, customers, and inventory managed for a merchant are not the same access surface as product discovery and cart activity in a storefront. This guide is for cross-border commerce and internal integration teams: it covers API choice, authentication, versions, throttling, errors, webhooks, and launch evidence. Every example uses placeholders rather than a real shop or credential.
Choose the API surface
For merchant-side products, orders, customers, inventory, and ERP synchronisation, start with the GraphQL Admin API. Shopify classifies the REST Admin API as legacy from 1 October 2024, so REST should not be the default for a new integration. Since 1 April 2025, new public apps submitted to the Shopify App Store must use only the GraphQL Admin API. REST remains relevant as a migration boundary for an existing connector, provided its fields, scopes, and deprecation work are recorded.
For a buyer-facing storefront or customer account, evaluate the Storefront API, Customer Account API, or the relevant extension surface separately. Never put an Admin API token in browser code, and do not grant a storefront component broad back-office access simply because it can read the same object. Webhooks deliver event signals; they do not replace an authoritative read and reconciliation process.
| Requirement | Starting point | Design check |
|---|---|---|
| Products, orders, customers, inventory, or ERP sync | GraphQL Admin API | Least-privilege scopes, cursor pagination, cost, idempotent writes |
| An existing REST connector | Versioned REST Admin API | Legacy impact, field migration, deprecation, rollback |
| Headless storefront, discovery, or cart | Storefront API | Public-token boundary, caching, markets, buyer data |
| Order or product event sync | Webhooks plus an Admin API read | HMAC, deduplication, queueing, retry, reconciliation |
Authentication and least privilege
The authentication path depends on where the app runs and whose shop it represents. An embedded app typically uses token exchange. An app running outside the Shopify admin typically uses the authorization code grant. A server-side integration that accesses only shops owned by its Shopify organisation can evaluate the client credentials grant. An app extension without its own backend uses Direct API access. These are different flows, not interchangeable OAuth boilerplate.
Every Admin API request needs an access token that matches the app, shop, and approved scopes, sent in the X-Shopify-Access-Token header. Request only the scopes the job needs, with particular care around customer and order data. Keep access tokens, client secrets, and signing secrets in server-side secret management. Separate development, test, and production credentials, and keep secrets out of logs, screenshots, and repositories. Distinguish online tokens tied to an employee session from offline tokens used by webhooks and scheduled jobs; when a token can expire, read expires_in instead of hard-coding its lifetime.
A minimal Admin GraphQL request
Start with a read-only query that verifies the network, app, shop, and scopes before adding writes. A request skeleton is POST https://{shop-domain}/admin/api/{api-version}/graphql.json; send Content-Type: application/json and X-Shopify-Access-Token: ${SHOPIFY_ACCESS_TOKEN}; begin with a body such as {"query":"query ShopIdentity { shop { name } }"}. {shop-domain}, {api-version}, and the environment variable are placeholders. Do not replace them with a real credential and commit it to public code.
As of 26 August 2026, Shopify lists 2026-07 as the current stable version. That value is a review-date example, not a permanent setting. Before launch, recheck support status and inspect the HTTP status, top-level GraphQL errors, mutation userErrors, and extensions.cost; a single HTTP 200 response is not a success criterion.
Put a time boundary around versions
Shopify releases API versions quarterly, and each stable version is supported for at least 12 months. Pin an available stable version in production URLs. Do not rely on latest, unstable, or a release candidate. If a requested version is no longer available, Shopify falls forward to an available stable version; the X-Shopify-API-Version response header shows the version that actually ran. A mismatch should raise an upgrade alert rather than pass silently.
Each quarter, review deprecations, developer updates, and the API health report. Use a development shop to verify fields, scopes, webhook payloads, and failure paths before upgrading. Record the version, review date, migration owner, and rollback method so 2026-07 cannot quietly become an unowned permanent dependency.
Pagination, query cost, and throttling
The GraphQL Admin API throttles by calculated query cost. Capacity is scoped to each app-and-shop pair, not to a fixed daily request allowance. On the review date, the documented restore rates are 100 points per second for Standard, 200 for Advanced, 1,000 for Plus, and 2,000 for Commerce Components. These figures are current documentation guidance and can be affected by platform policy and request shape; they are not a permanent promise for every shop.
Use cursor pagination for connections and control page size with first or last. Record requestedQueryCost, actualQueryCost, and throttleStatus from extensions.cost. Schedule bulk synchronisation through a queue and available-point budget. On throttling, network failure, or a 5xx response, use bounded exponential backoff with jitter. Use idempotency keys for writes. A single query is limited to 1,000 points and array inputs to 250 items; larger imports or exports should be assessed for bulk operations and segmented jobs.
For an existing REST integration, the documented bucket holds 40 requests per app and shop and restores at two requests per second; Shopify Plus increases the bucket and restore rate tenfold. REST responses expose X-Shopify-Shop-Api-Call-Limit, and a 429 response should follow Retry-After. This is not a daily allowance of 40,000 calls and is not a reason to choose REST for a new implementation.
Separate auth, throttling, and business errors
401 Unauthorized: the token is missing, invalid, expired, or associated with the wrong app or shop; verify the flow and token lifecycle.403 Forbidden: scopes or employee permissions are insufficient; do not hide a boundary problem by granting broad access.429 Too Many Requestsor GraphQLTHROTTLED: read throttle state, wait, and retry with backoff rather than issuing an immediate concurrent burst.5xx, connection failure, or timeout: record the request identifier, retry a bounded number of times, and alert or dead-letter the job instead of looping forever.- GraphQL can return HTTP 200 with a top-level
errorspayload; mutations also require inspection ofuserErrorsand returned data.
Logs should identify the shop, job, API version, status, latency, and request identifier while redacting tokens, customer fields, and client secrets. Persist idempotency keys and result states for retryable writes so a retry cannot duplicate an external order record or inventory decrement.
Webhook subscriptions, verification, and reconciliation
When every installed shop shares the same topic, destination, or filter, declare an app-specific subscription in shopify.app.toml. When each shop needs a different configuration, create a shop-specific subscription through the GraphQL Admin API. Confirm the required scopes, API version, and payload fields for each topic, and replay representative events in a development shop before an upgrade.
An HTTPS receiver must verify X-Shopify-Hmac-SHA256 against the raw request body and the client secret before parsing the payload. Deduplicate with X-Shopify-Webhook-Id, write the event to a durable queue, and return 2xx quickly; Shopify documents a five-second timeout for the complete request. Use bounded retries and a dead-letter record for failures, then reconcile periodically with the Admin API to catch missing, duplicated, reordered, or manually corrected events. Webhooks reduce detection latency; they do not prove completeness.
Launch acceptance checklist
- Document the owner and purpose of every data field, and confirm the boundary between Admin, Storefront, Customer Account, and extension surfaces.
- Test the authentication path for the app type, least-privilege scopes, online or offline token, expiry handling, and revocation.
- Pin the current stable version, record the review date, check
X-Shopify-API-Version, and schedule quarterly review. - In a development shop, test cursor pagination, query cost, the 1,000-point query ceiling, the 250-item array limit, and throttle backoff.
- Simulate 401, 403, 429,
THROTTLED, 5xx, timeout, top-levelerrors, mutationuserErrors, and duplicate writes. - Verify app-specific or shop-specific webhooks, raw-body HMAC, deduplication, fast 2xx, retry, dead-letter, and reconciliation behaviour.
- Confirm that logs and monitoring do not expose tokens or unnecessary customer data, and name the post-launch alert, rollback, and ownership contacts.
FAQ
Can a new public app still use REST Admin API as its default?
It should not. REST Admin API is legacy, and since 1 April 2025 new public apps submitted to the Shopify App Store must use only the GraphQL Admin API. An existing REST connector needs a migration plan covering fields, scopes, errors, and rollback.
Can Admin API and Storefront API share a token?
Do not share one. They serve different trust boundaries and purposes. Keep Admin credentials on the server, expose only the access method required by the storefront, and confirm permissions and data exposure against the official documentation.
Does an HTTP 200 GraphQL response mean the operation succeeded?
No. Check top-level errors, mutation userErrors, returned data, and extensions.cost. Treat the operation as successful only when the response, permissions, and business state meet the expected result.
Can webhooks replace scheduled reconciliation?
No. Webhooks reduce event latency but can be duplicated, reordered, missed, or followed by a manual correction. Retain event IDs and processing results, then reconcile periodically with the Admin API to detect drift.
For related implementation context, see Shopify API development and commerce extensions.