Shopify is one of the cleaner integrations — well-documented REST and GraphQL APIs, predictable rate limits, native webhooks. The quirks come from its data model: every Shopify object has a globally unique GID, inventory is split across locations, and the auth flow needs the shop's myshopify.com domain up front.
Shop domain
Every Shopify store has a permanent domain like acme-store.myshopify.com. Even if the store uses a custom domain on the storefront, the API hostname is always <shop>.myshopify.com. Pass shop when starting the OAuth flow:
curl "https://appengine.appmint.io/connect/shopify/auth-url?shop=acme-store.myshopify.com" \
-H "Authorization: Bearer $JWT" -H "orgid: $ORG"
The channel stores shop and uses it to build the API base URL: https://acme-store.myshopify.com/admin/api/2024-10/....
GIDs and numeric IDs
Shopify's GraphQL API exposes Global IDs like gid://shopify/Product/1234567890. The REST API uses bare numeric IDs (1234567890). The provider deals in GIDs internally, since GraphQL is the path forward for new features (Bulk Operations, Storefront API).
When mapping Shopify products in POST /sales-channel/mappings/categories or referencing locations, always use the GID form:
{
"channel": "shopify",
"sku": "SKU-100",
"channelSku": "gid://shopify/ProductVariant/9876543210",
"metadata": { "productGid": "gid://shopify/Product/1234567890" }
}
Location-based inventory
A Shopify shop has one or more locations (physical warehouses, retail stores, third-party fulfillment). Inventory levels are tracked per (variant, location). The default location is set in admin; multi-location shops require explicit decisions about which location each push affects.
During channel enable, set defaultLocationId:
{
"shop": "acme-store.myshopify.com",
"defaultLocationId": "gid://shopify/Location/123"
}
Inventory pushes go to the default location unless overridden. To split master across locations, use the channel mapping per-SKU:
{
"sku": "SKU-100",
"locationSplit": {
"gid://shopify/Location/123": 0.7,
"gid://shopify/Location/456": 0.3
}
}
The push allocates 70/30 between the two locations.
Rate limits
Shopify's REST API uses a leaky bucket — 40 requests for the bucket, leaks at 2/s. The GraphQL API uses a points-based cost model: 1,000 points per query, restored at 50/s. Bulk Operations API runs queries asynchronously without blocking the regular budget.
The module config caps Shopify at 40 req/min, 40,000/day. For large catalog pushes, the provider switches to Bulk Operations automatically.
Webhooks
Shopify supports HMAC-signed webhooks. The provider auto-registers these on enable:
orders/create,orders/updated,orders/cancelledproducts/create,products/update,products/deleteinventory_levels/updateapp/uninstalled(drives credential invalidation)
The receiver verifies the HMAC against the shared secret, then writes the event into the unified order list or fires a sync.
Variants and options
A Shopify product has up to three options (Size, Color, Material) and multiple variants — each with its own SKU, price, and inventory. The provider treats Storefront variants and Shopify variants 1:1 by SKU. Shopify enforces:
- Maximum 100 variants per product (default; can be raised to 2000 with the GraphQL
productOptionsCreate). - Maximum 3 options per product. More requires multiple products.
- Unique SKUs within a shop are not enforced by Shopify but are by the provider — duplicate SKU pushes return
mapping_conflict.
Currency and markets
Shopify Markets lets a shop sell in multiple currencies and regions. Pricing rules can target a specific market via:
{
"channel": "shopify",
"scope": { "type": "all" },
"adjustment": { "type": "set_price", "value": 24.99, "currency": "EUR", "marketId": "gid://shopify/Market/55" }
}
Without marketId, the rule applies to the shop's primary market.
Common failure modes
| Symptom | Likely cause |
|---|---|
| 401 on every call | Access token revoked (app uninstalled). Re-OAuth. |
| 429 burst on bulk push | Hit the leaky bucket. Switch to Bulk Operations. |
| Inventory drift on multi-location shops | Wrong defaultLocationId. Set per-SKU locationSplit. |
| Variants missing after sync | Product hit 100-variant cap. Split into multiple products. |
| Webhook not received | Wrong app URL or signing-secret rotation. Re-register webhooks. |
The Shopify Admin API version is pinned (e.g. 2024-10) per provider release. Major Shopify API versions are released quarterly and supported for 12 months — the provider auto-upgrades on each release.