The route from "mozimo.in displays Shopify products" to "mozimo.in sells them", as a plan with a phase spine and gates, plus the open decision tickets that still shape it and the evidence they rest on. - .scratch/shopify-headless-commerce/: plan.md (phases and gates), map.md (the wayfinder map), 10 open decision tickets - CONTEXT.md: Storefront / Theme store / Cart / Parity vocabulary - docs/adr/0001-0003: Checkout stays Shopify-hosted, one Variant per product, the checkout domain stays shop.mozimo.in - docs/research/ and docs/shopify-catalog-inventory.md: verified store facts, the Cart API probe, and the catalogue inventory Raw Shopify doc scrapes under .scratch/shopify-research/ are ignored: they are working material, not record.
78 KiB
Shopify headless commerce: capabilities, limits and dates (verified 2026-10-13)
Subject context. Luxury chocolate brand mozimo.in (India, INR, small catalog of bars/boxes/hampers).
Custom headless storefront on TanStack Start (React 19 + Vite) with a custom Node SSR server
(server.mjs), Docker behind Caddy. It reads products/collections from the Shopify Storefront
GraphQL API and is strictly read-only (src/lib/shopify.ts). Buying happens today on a separate
classic Shopify theme storefront at shop.mozimo.in (the Shopify Online Store
channel). Credentials are minted by an OAuth client-credentials app that mints an admin token and then a
storefront access token.
Purpose. Facts, constraints, limits and dates only. No architectural recommendations.
Every claim carries the canonical shopify.dev (or Shopify-owned) URL it came from. Where a fact could
not be verified against a primary source it is marked UNVERIFIED with a description of what was found
instead.
How this was verified. All shopify.dev pages were fetched as raw Markdown
(<url>.md, e.g. https://shopify.dev/docs/api/usage/versioning.md), which is the un-truncated source of
the same HTML page; the front-matter api_version on Storefront API reference pages was used to confirm
the version actually behind /latest/. shopify.dev sitemap inventory
(https://shopify.dev/sitemap_standard.xml.gz) was used to establish what does and does not exist in the
current API surface. help.shopify.com was mostly unreachable (HTTP 403 bot challenge for both curl and
the fetch tool); the two pages that did return are cited as such and the failures are recorded in
§7. Shopify Community threads were read through the forum's own JSON API
(https://community.shopify.com/t/<id>.json) — these are community pages, not Shopify documentation,
and are labelled as such.
0. Critical version findings (read first)
0.1 Current stable API version is 2026-10; 2025-01 is retired
From Shopify's own release-schedule table (https://shopify.dev/docs/api/usage/versioning):
| Stable version | Release date | Accessible until | Status |
|---|---|---|---|
| 2025-04 | April 1, 2025 | April 16, 2026 15:00 UTC | Unsupported |
| 2025-07 | July 1, 2025 | July 16, 2026 15:00 UTC | Unsupported |
| 2025-10 | October 1, 2025 | October 16, 2026 15:00 UTC | Unsupported |
| 2026-01 | January 1, 2026 | January 16, 2027 15:00 UTC | Stable |
| 2026-04 | April 1, 2026 | April 16, 2027 15:00 UTC | Stable |
| 2026-07 | July 1, 2026 | July 16, 2027 15:00 UTC | Stable |
| 2026-10 | October 1, 2026 | October 16, 2027 15:00 UTC | Latest stable |
| 2027-01 | January 1, 2027 | January 16, 2028 15:00 UTC | Release candidate |
- Current stable (and what
/latest/resolves to):2026-10. Confirmed by the front-matter of the current reference pages — e.g.api_version: 2026-10on https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate and on https://shopify.dev/docs/api/customer/latest. 2025-01is not in the table at all. The oldest accessible stable version is2026-01, so2025-01is past its support window. The exact retirement date is not published in that table; because each stable version is "supported for a minimum of 12 months" (https://shopify.dev/docs/api/usage/versioning),2025-01would have gone inaccessible around January 2026. Treat the precise date as UNVERIFIED; the retirement itself is certain.- Shopify falls forward rather than erroring: "If your app targets an inaccessible version, Shopify
falls forward and responds using the oldest accessible stable version." Responses carry
X-Shopify-API-Versionreflecting the version actually used, so a repository pinned to2025-01is in practice being served2026-01. Source: https://shopify.dev/docs/api/usage/versioning - Imminent:
2025-10becomes inaccessible on October 16, 2026 15:00 UTC (three days after this research). Source: https://shopify.dev/docs/api/usage/versioning src/lib/shopify.tscurrently setsAPI_VERSION = "2025-01"andADMIN_API_VERSION = "2026-07". Stated as fact only:2025-01is retired, and2026-07(Admin API) is still a supported stable version until July 16, 2027.
0.2 Release and deprecation cadence
- New version every three months at 5pm UTC on the first day of the quarter; version names are date-based. Each stable version is supported ≥12 months, with ≥9 months of overlap between consecutive versions. Source: https://shopify.dev/docs/api/usage/versioning
- Deprecation practice: "Deprecated fields or types are removed in a subsequent release—for example,
something deprecated in
2026-10might be removed in2027-01." Deprecations are announced in the developer changelog (https://shopify.dev/changelog). An entire API can be deprecated: "A deprecated API stays available but is unsupported, and it can stop working at any time." Source: https://shopify.dev/docs/api/usage/versioning - The Shopify CLI "prevents deploys targeting versions older than 12 months" (Polaris section of the same page).
- App-Store-specific enforcement (applies to published apps, not to a merchant's private integration): continuing to use unsupported resources after the upgrade deadline causes delisting and blocks installs for a minimum of seven days. Source: https://shopify.dev/docs/api/usage/versioning
0.3 Plan naming: two vocabularies in Shopify's own materials
- Merchant-facing plans are Basic / Grow / Advanced / Plus — with INR pricing on Shopify's India pricing page: Basic ₹1,499/mo (yearly), Grow ₹5,599/mo, Advanced ₹22,680/mo, Plus from ₹1,75,000/mo. Source: https://www.shopify.com/in/pricing
- API rate-limit documentation uses a different vocabulary: Standard / Advanced Shopify / Shopify Plus / Shopify for enterprise (Commerce Components). Sources: https://shopify.dev/docs/apps/build/apis/graphql-admin/rate-limits, https://shopify.dev/docs/api/customer#rate-limits
- Plan gates in the docs are usually written as "Shopify Plus" vs "all plans except Shopify Starter", so they are unaffected by the Basic/Grow/Advanced renaming. Where a gate is expressed as a rate-limit tier this document says so explicitly.
1. Cart API on the Storefront GraphQL API
Endpoint pattern (current): POST https://{shop}.myshopify.com/api/2026-10/graphql.json
(https://shopify.dev/docs/api/storefront).
1.1 Current shape of the operations
| Operation | Signature (2026-10) | Returns |
|---|---|---|
cartCreate |
cartCreate(input: CartInput!) |
CartCreatePayload { cart, userErrors: [CartUserError!]!, warnings: [CartWarning!]! } |
cartLinesAdd |
cartLinesAdd(cartId: ID!, lines: [CartLineInput!]!) |
CartLinesAddPayload { cart, userErrors!, warnings! } |
cartLinesUpdate |
cartLinesUpdate(cartId: ID!, lines: [CartLineUpdateInput!]!) |
CartLinesUpdatePayload { cart, userErrors!, warnings! } |
cartLinesRemove |
cartLinesRemove(cartId: ID!, lineIds: [ID!], viewKeys: [String!]) |
CartLinesRemovePayload { cart, userErrors!, warnings! } |
cartBuyerIdentityUpdate |
cartBuyerIdentityUpdate(cartId: ID!, buyerIdentity: CartBuyerIdentityInput!) |
CartBuyerIdentityUpdatePayload { cart, userErrors!, warnings! } |
cart (query) |
cart(id: ID!): Cart |
Cart |
Sources: https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate, https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd, https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesUpdate, https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesRemove, https://shopify.dev/docs/api/storefront/latest/mutations/cartBuyerIdentityUpdate, https://shopify.dev/docs/api/storefront/latest/queries/cart.
Documented behaviour that matters:
cartCreate— "Creates a newCartfor a buyer session. You can optionally initialize the cart with merchandise lines, discount codes, gift card codes, buyer identity for international pricing, and custom attributes. The returned cart includes acheckoutUrlthat directs the buyer to complete their purchase." (https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate)cartLinesAdd— "Quantity defaults to1if not provided." Each line takes merchandise, quantity, selling plan, custom attributes, and parent relationships for nested line items such as warranties or add-ons. (https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd)cartLinesUpdate— "You can modify the quantity, swap the merchandise, change custom attributes, or update the selling plan for each line." Omittingattributesor setting it tonullpreserves existing line attributes; an empty array clears them all. (https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesUpdate)cartLinesRemove— accepts eitherlineIdsorviewKeys, "Mutually exclusive withlineIds." (https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesRemove)cartBuyerIdentityUpdate— used to "associate a logged-in customer via access token, set a B2B company location, or configure checkout preferences like delivery method. Preferences prefill checkout fields but don't sync back to the cart if overwritten at checkout." The buyer's country determines international pricing. (https://shopify.dev/docs/api/storefront/latest/mutations/cartBuyerIdentityUpdate)cartquery — "Returns aCartby its ID. The cart contains the merchandise lines a buyer intends to purchase, along with estimated costs, applied discounts, gift cards, and delivery options." (https://shopify.dev/docs/api/storefront/latest/queries/cart)Cartobject: "Use thecheckoutUrlfield to direct buyers to Shopify's web checkout to complete their purchase." (https://shopify.dev/docs/api/storefront/latest/objects/Cart)- Cart IDs carry a key in the ID itself, e.g.
gid://shopify/Cart/Z2NwLXVzLWV4YW1wbGU6MDEyMzQ1Njc4OTAxMjM0NTY3ODkw?key=examplekey1234567890(https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage).
1.2 Documented limits
| Limit | Value | Source |
|---|---|---|
| Line items per cart (total) | 500 — "The cart supports a maximum of 500 line items." | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart |
Lines per request (cartLinesAdd, cartLinesUpdate, cartLinesRemove) |
250 — "You can add up to 250 lines in a single request"; argument is annotated "The input must not contain more than 250 values." Same for update and remove. |
https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd, https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesUpdate, https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesRemove |
| Array-input cap, all Shopify APIs | 250 — "Input arguments that accept an array have a maximum size of 250, on every Shopify API. Requests return an error if an input array exceeds 250 items." | https://shopify.dev/docs/api/usage/limits |
| Quantity per line | No maximum documented. CartLineInput.quantity is Int, Default: 1, described only as "The quantity of the merchandise." |
https://shopify.dev/docs/api/storefront/latest/input-objects/CartLineInput, https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd |
| Cart lifetime (abandoned) | "Unused and abandoned carts automatically expire within 30 days of creation." | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart |
| Cart lifetime (completed) | "Shopify automatically deletes the cart when the customer completes their checkout." | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart |
| Number of carts | "A shop or customer can create an unlimited number of carts." | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart |
| Cart rate limits | "Carts don't have any global API rate limits." But: "The cart is subject to the same throttling restrictions as the Storefront API." | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart |
| Bot protection on cart | "Shopify Plus bot protection is available for cart." → Shopify Plus only | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart, matching the "Just for Plus" bullet on https://www.shopify.com/in/pricing |
| Headless storefronts per shop | Docs: "You can have a maximum of 100 active storefronts and access tokens per shop." Pricing page feature row "Build headless storefronts": 1 / 1 / 1 / 25 (Basic / Grow / Advanced / Plus). These two figures are not obviously measuring the same thing — see §6.3. | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/manage-headless-channels, https://www.shopify.com/in/pricing |
| Active storefront access tokens | "Apps can have a maximum of 100 active storefront access tokens per shop." | https://shopify.dev/docs/api/storefront |
1.3 checkoutUrl behaviour and domain
What the docs state:
- Field type
checkoutUrl: URL!(non-null), documented as "The URL of the checkout for the cart." (https://shopify.dev/docs/api/storefront/latest/objects/Cart) - It "direct[s] buyers to Shopify's web checkout" (https://shopify.dev/docs/api/storefront/latest/objects/Cart) and the manage-cart guide says the response "includes a URL that redirects customers through Shopify's web checkout." (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage)
- Documented example value — note the host and path shape:
{"checkoutUrl": "https://exam.myshopify.com/cart/c/29567c413f68cf5e8c1cb623954f3a28"}(https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage) - "For security reasons, the
checkoutUrlshould be requested when the buyer is ready to navigate to checkout and can be re-requested if it is stale." (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage) - When a customer access token is set on the cart, the
checkoutUrlyields a logged-in checkout; to preserve that for server-side Storefront API calls you must send theShopify-Storefront-Buyer-IPheader. "Without theShopify-Storefront-Buyer-IPheader, Shopify can't differentiate requests from different buyers, which can result in throttled API requests, limited bot protection, and unauthenticated flows at checkout." (https://shopify.dev/docs/api/storefront, https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage)
UNVERIFIED (domain selection). No current shopify.dev page states which host the checkoutUrl uses.
The only first-party statement found is a Shopify maintainer reply (September 8, 2022) in Shopify's own
storefront-api-feedback repository: the reporter's checkoutCreate.webUrl returned
foo.myshopify.com while the cart query returned the merchant's custom domain; the maintainer's accepted
answer was "try initializing the API (ex. yourcustomdomain.com/api/graphql) with your custom domain vs.
the .myshopify.com domain." (https://github.com/Shopify/storefront-api-feedback/discussions/130)
That implies the returned URL follows the host used for the API request (or the shop's primary domain), not
the headless storefront's domain. This is four years old and should be treated as unconfirmed; the
current documented example uses *.myshopify.com
(https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage). Practical
consequence to be aware of: the checkout host is a Shopify-owned host, and because the headless storefront
lives on mozimo.in while the Online Store channel is shop.mozimo.in, a checkout redirect crosses
domains.
1.4 Cart-related changes you inherit when you leave 2025-01
Because the API falls forward, cart behaviour observed in production today is 2026-01 behaviour, and new
cart work is written against 2026-01+ semantics. Relevant entries:
2026-01— "Calls to the Storefront APIcartDiscountCodesUpdatemutation must now include thediscountCodesargument" (previously accepted but a no-op). Also returnsGIFT_CARD_RECIPIENT_INVALIDinuserErrorsforcartCreate/cartLinesAddinstead of an empty cart. (https://shopify.dev/changelog/release-notes/2026-01)2026-04— Storefront API returnsMERCHANDISE_LINE_TRANSFORMERS_RUN_ERRORwhen a Cart Transform Function errors duringcartCreate/cartLinesAdd, replacing the genericINVALID. (https://shopify.dev/changelog/release-notes/2026-04)2026-07—CartLine.viewKeyadded ("returning the same value rendered by Liquid storefronts and accepted bycartLinesUpdateandcartLinesRemove");cartLinesUpdate/cartLinesRemoveacceptview_key/viewKeys; newCartWarningcodePRODUCT_UNAVAILABLE_IN_BUYER_LOCATION; and an action-required migration away from deprecatedcart.discountAllocationstocart.discountApplications,cart.lines[].discountAllocations(lineLevelOnly: false)andcart.deliveryGroups[].discountAllocations. (https://shopify.dev/changelog/release-notes/2026-07)2026-10—@inContextgained an optionalchannelIdargument to apply a sales channel's context (channel-specific availability and pricing) across a query. (https://shopify.dev/changelog/release-notes/2026-10)
2. Can checkout be rendered on the merchant's own domain?
Short answer, stated from primary sources: no supported mechanism exists to render or host Shopify's checkout yourself, on any plan. What varies by plan is how much you may customise the Shopify-hosted checkout, not where it runs.
2.1 The headless cart hands off to Shopify's hosted checkout
- Storefront Cart API: "The returned cart includes a
checkoutUrlthat directs the buyer to complete their purchase." / "the response includes a URL that redirects customers through Shopify's web checkout." / "Use thecheckoutUrlfield to direct buyers to Shopify's web checkout to complete their purchase." (https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate, https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage, https://shopify.dev/docs/api/storefront/latest/objects/Cart) - The documented headless checkout step is literally "Redirect the buyer to the
checkoutUrl." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/checkout-authentication)
2.2 The API that used to complete orders outside checkout is gone
- "In API version 2024-04, Checkout APIs on the REST Admin and Storefront API are deprecated, with the exception of the REST Admin API's Abandoned checkouts resource. In version 2025-04, the Checkout APIs will be sunset and no longer function." The documented replacement is the Storefront Cart API or Checkout Kit for native mobile apps. (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/migrate-to-cart-api)
- Corroborated by the current API inventory: the
shopify.devsitemap contains no Storefront API mutations or queries undercheckout*for the current version. The only surviving payment-adjacent members of the Storefront API areshopPayPaymentRequestSessionCreate,shopPayPaymentRequestSessionSubmit, thepaymentSettingsquery and thePaymentSettingsobject (https://shopify.dev/sitemap_standard.xml.gz, and see https://shopify.dev/docs/api/storefront). Those Shop Pay mutations are the single documented exception to "checkout happens on Shopify's checkout" — see §2.6. - Consequence: setting the Shop Pay exception aside, there is no documented API path to create a Shopify order (and therefore to take payment for one) outside Shopify's own checkout, on any plan.
2.3 What Checkout Extensibility actually allows
Checkout Extensibility is Shopify's supported customisation surface, and it runs inside Shopify's checkout:
| Technology | Customisation type | Availability (verbatim) |
|---|---|---|
| Checkout UI extensions | "Add custom UI or content to the checkout process and Order status page" | "Shopify Plus. Thank you and Order status extensions are available to all plans except Shopify Starter. Market overrides are available to Advanced." |
| Checkout UI extensions: post-purchase | "Add new content to the post-purchase page" | "All plans except Shopify Starter. Currently in beta." Live-store use requires access request. |
GraphQL Admin API (checkoutAndAccountsConfigurationUpdate) |
"Customize the look and feel of checkout" | "Shopify Plus" |
| Shopify Functions | "Extend or replace key parts of Shopify's backend with custom logic" | "All plans except Shopify Starter." Merchants with checkout.liquid customisations must upgrade first. |
| Web pixel extensions | "Track customer behavior" | "All plans except Shopify Starter." |
Source: https://shopify.dev/docs/apps/build/checkout/technologies.
Additional plan statements from Shopify's own docs:
- Checkout styling: "Checkout styling customizations are available only to Shopify Plus merchants." (https://shopify.dev/docs/apps/build/checkout/styling)
- The Checkout and Accounts Configuration API "styles checkout, customer accounts, and sign-in through a single, unified API" and is likewise gated: "Checkout styling customizations are available only to Shopify Plus merchants." (https://shopify.dev/docs/apps/build/checkout/styling/checkout-and-accounts-configuration)
- Market-specific checkout/account overrides: "Merchants on Advanced or Plus who use markets can tailor their checkout and customer accounts experience for regional and company location markets." (https://shopify.dev/docs/apps/build/checkout/technologies)
- Extensions run with declared capabilities in
shopify.extension.toml—api_access,network_access,block_progress,collect_buyer_consent(https://shopify.dev/docs/apps/build/checkout/capabilities). The presence of a declared-capability sandbox, rather than arbitrary page control, is the shape of the customisation model. - Shopify's India pricing page summarises the same gating as a feature row, "Checkout customization": Limited / Limited / Limited / Full across Basic / Grow / Advanced / Plus, and lists "Fully customizable checkout" under "Just for Plus". (https://www.shopify.com/in/pricing)
2.4 checkout.liquid — deprecation, sunset and status
Verbatim current notice (Deprecated banner) on https://shopify.dev/docs/storefronts/themes/architecture/layouts/checkout-liquid and repeated on https://shopify.dev/docs/apps/build/checkout:
"
checkout.liquidis now unsupported for the Information, Shipping, and Payment checkout steps.checkout.liquidand additional scripts were sunset for the Thank you and Order status pages on August 28, 2025. Script tags were sunset on those pages on August 28, 2025 for Plus stores, and are sunset for non-Plus stores on August 26, 2026."
checkout.liquid"renders the checkout and is available only to Shopify Plus merchants." Non-Plus merchants customise in the theme editor instead. (https://shopify.dev/docs/storefronts/themes/architecture/layouts/checkout-liquid)- Guidance: "Stores that still use
checkout.liquidfor the Thank you and Order status pages must upgrade to Shopify Extensions in Checkout." Merchants can "revert tocheckout.liquid… until its sunset dates". (https://shopify.dev/docs/apps/build/checkout) - Dates summary: Information/Shipping/Payment steps — already unsupported (no date restated on the
current page); Thank you + Order status
checkout.liquidand additional scripts — sunset 2025-08-28; script tags on those pages — 2025-08-28 for Plus, 2026-08-26 for non-Plus. - The original deprecation announcement date is UNVERIFIED: it is not restated on the current
pages, the
changelog.shopify.comlegacy site returns 404 for its sitemap/JSON/search endpoints, and archived announcement URLs were not retrievable. The dates above are the authoritative current ones.
2.5 Is a fully custom (non-Shopify-hosted) checkout possible on any plan?
No general-purpose path is documented, on any plan — with one narrow, heavily gated exception for Shop Pay Wallet (§2.6). The evidence chain for the general case:
- The only documented successor to the removed Checkout APIs is a redirect to "Shopify's web checkout" (§2.1, §2.2).
- No
checkout*mutation survives in the current Storefront API inventory (see §2.2 for the exact surviving payment-adjacent members, and §2.6 for the Shop Pay exception). - Custom payment providers are not a merchant-side capability: "The option to build a custom payment extensions is limited to eligible Shopify Plus Merchants only. Contact Shopify Plus Support to confirm eligibility." and "Only approved Partners can build payments extensions on Shopify's Payments Platform." (https://shopify.dev/docs/apps/build/payments) Those extensions still process payments "during the customer's purchase flow" in Shopify checkout (https://shopify.dev/docs/apps/build/payments).
- If 3-D Secure is mandated in a country, a payment provider must support it: "If you offer credit card payment methods in a country where 3-D Secure authentication is mandated, then you must support 3-D Secure authentication." (https://shopify.dev/docs/apps/build/payments/requirements)
UNVERIFIED (custom checkout domain). No shopify.dev page was found that documents serving Shopify
checkout, or a Shopify-completed order flow, on a merchant-controlled non-Shopify domain. Even in the one
merchant-built-checkout path (§2.6), "Most interactions in Shop Pay checkout happen within the context of a
Shopify-hosted popup window." Shopify's India pricing FAQ instead describes embedding buy buttons
elsewhere: "you can use the Buy Button sales channel to embed buy buttons on an external website or blog,
and let customers check out using Shopify Checkout." (https://www.shopify.com/in/pricing) Absence of a
documented capability is reported here as "not documented", not as a contractual prohibition — Shopify's
Terms of Service were not reviewed for this.
Payment-gateway implications if attempted (facts, not recommendations): taking money outside Shopify's checkout leaves no documented API to create the corresponding Shopify order (§2.2, §2.6 is the sole exception); Shopify's supported custom-gateway mechanism (payments extensions) is Plus-only and Partner-only (§2.5 point 3); and using a third-party provider at Shopify's checkout incurs Shopify's third-party transaction fee, which on India plans is 2% (Basic) / 1% (Grow) / 0.6% (Advanced) / 0.2% (Plus) (https://www.shopify.com/in/pricing). Shopify also requires Shopify Payments for some adjacent features — the India pricing comparison marks local-currency presentment, accepting local payment methods, and estimating/collecting duties and taxes with "Requires Shopify Payments" (https://www.shopify.com/in/pricing).
2.6 The one documented exception: Shop Pay Wallet (merchant-built checkout)
This is the only current first-party mechanism found where the merchant's own checkout surface takes the buyer through payment and Shopify creates the order. Its constraints are strict and, for this merchant, decisive.
- What exists in the Storefront API (
api_version: 2026-10):shopPayPaymentRequestSessionCreate— "Creates a Shop Pay payment request session for processing payments. The session includes a checkout URL where customers complete their purchase and a token for subsequent operations like submitting the payment." (https://shopify.dev/docs/api/storefront/latest/mutations/shopPayPaymentRequestSessionCreate)shopPayPaymentRequestSessionSubmit— "Finalizes a Shop Pay payment request session… TheidempotencyKeyargument ensures the payment transaction occurs only once, preventing duplicate charges. On success, returns aShopPayPaymentRequestReceiptwith the processing status and a receipt token." (https://shopify.dev/docs/api/storefront/latest/mutations/shopPayPaymentRequestSessionSubmit)
- Purpose, verbatim: "Use Shop Pay Wallet to offer Shop Pay in your existing checkout… Add the Shop Pay frontend components to your checkout. Create payment request sessions and respond to Shop Pay checkout events. Submit payment requests and reconcile asynchronous order creation." (https://shopify.dev/docs/api/commerce-components/pay)
- Hard eligibility constraints, verbatim from the same page:
- "You can't use the Shop Pay Wallet API on an existing Shopify store. To get started, create a new store for Shop Pay Wallet."
- Requirements include "Complete the full Shopify Payments sign-up, then activate test mode for
development", declaring the allowed origins where the SDK loads, "Configure API access for the
Storefront API and the GraphQL Admin API", and a content security policy allowing
cdn.shopifycloud.com,cdn.shopify.com,shop.app,pay.shopify.com,*.shopifysvc.comand*.stripe.com. - Production readiness requires "Complete production Shopify Payments setup."
- It is a separate plan on that new store: "you'll notice that this plan has a refined UI, including only the features and settings that are relevant to Shop Pay Wallet"; "🟡 Plan: Information about your Shopify plan"; "Credit card rates vary by plan, and may require manual configuration by Shopify"; and "the Shop Pay Wallet plan will have a Custom App pre-configured with the essential Storefront API permissions required for use of Shop Pay Wallet." (https://shopify.dev/docs/api/commerce-components/pay/shop-configuration)
- Division of responsibility: the merchant system remains source of truth for catalog/cart, while
"Shopify is the source of truth for Shop Pay payment and order records", "Shopify processes the payment
using Shop Pay and Shopify Payments", and "Most interactions in Shop Pay checkout happen within the
context of a Shopify-hosted popup window." Order creation is asynchronous: "Shopify creates orders
asynchronously. Don't rely only on the client-side
paymentcompleteevent to confirm order creation, because the customer can close the popup or lose network connectivity. Use webhooks and a reconciliation job…" — subscribing toORDERS_CREATEandORDER_TRANSACTIONS_CREATE. (https://shopify.dev/docs/api/commerce-components/pay) - Net characterisation: not a general-purpose custom checkout. It is Shop-Pay-only, Shopify-Payments-only, unavailable on an existing store, and provisioned as its own plan; the payment authorisation itself still runs in a Shopify-hosted popup. Whether an India-based merchant can obtain Shopify Payments (and therefore this plan at all) is the open question in §4.1 — UNVERIFIED for India specifically, since Shopify does not publish a country eligibility list for Shop Pay Wallet on the pages reviewed.
3. Headless customer accounts
3.1 Which API is current
- Current: the Customer Account API — a versioned GraphQL API (
api_version: 2026-10on https://shopify.dev/docs/api/customer/latest), listed as versioned alongside the Admin, Storefront and other APIs on https://shopify.dev/docs/api/usage/versioning. "The Customer Account API offers a secure way to access private customer-scoped data… You can access data including customers, orders, payments, fulfillment, discounts, refunds, and metafields." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api) - Older: the Storefront API customer flow (
customerAccessTokenCreate,customerAccessTokenRenew,customer(customerAccessToken:),customerCreate,customerRecover, …). The reference forcustomerAccessTokenCreatenow opens with: "Requiresunauthenticated_write_customersaccess scope. For legacy customer accounts only." (https://shopify.dev/docs/api/storefront/latest/mutations/customerAccessTokenCreate) Note the precise status: the mutation itself is not flaggedDeprecatedin the reference (only itsuserErrorsfield is); what is deprecated is legacy customer accounts as a product surface, and Shopify recommends the Customer Account API for custom storefronts. - Legacy customer accounts deprecation (dated): changelog post "Legacy customer accounts are now
deprecated" —
postedAt 2026-02-26,effectiveAt 2026-02-19, tagged "Deprecation announcement". Verbatim: "Legacy customer accounts are no longer available to new stores and existing stores not using it. Shopify will stop providing feature updates and technical support for this older version." and "A final sunset date for legacy customer accounts will be announced later in 2026." For custom storefronts: "If you build custom storefronts or apps that currently use Storefront API customer-scoped mutations, we recommend switching to the Customer Account API as soon as possible." (https://shopify.dev/changelog/posts/legacy-customer-accounts-are-deprecated) - UNVERIFIED (final legacy sunset date): as of 2026-10-13 no final sunset date appears in the recent changelog feed (https://shopify.dev/changelog.md) or the 2026-01/2026-04/2026-07/2026-10 release notes. The changelog explicitly says it will be announced "later in 2026", so it is still pending.
3.2 How authentication works
- Protocol: OAuth 2.0 / OpenID Connect. Two client types: "Confidential - A client capable of keeping a client secret confidential… typically used for server-side applications" and "Public - A client unable to keep a client secret confidential." — "For public clients, we use Proof Key for Code Exchange or PKCE." (https://shopify.dev/docs/api/customer)
- Discovery (use these, not hardcoded URLs): on the storefront domain,
GET /.well-known/openid-configuration(standard OIDC format) andGET /.well-known/customer-account-api(Shopify-specific: GraphQL + MCP endpoints). (https://shopify.dev/docs/api/customer) - Documented endpoint values:
(https://shopify.dev/docs/api/customer)
"authorization_endpoint": "https://{shopDomain}/authentication/oauth/authorize", "token_endpoint": "https://{shopDomain}/authentication/oauth/token", "end_session_endpoint": "https://{shopDomain}/authentication/logout", "jwks_uri": "https://{shopDomain}/authentication/.well-known/jwks.json", "issuer": "https://shopify.com/authentication/{shopId}" - Scope string:
openid email customer-account-api:full(required) (https://shopify.dev/docs/api/customer) - Session/silent auth: append
&sso=silentto the cart'scheckoutUrlto have checkout verify the buyer's live Customer Accounts browser session via an OIDC-compliant flow. Caveat, verbatim: "sso=silentdoes not fall back to the buyer identity on the cart… If the buyer's session on the Customer Accounts domain has expired, checkout treats them as a guest — even if a validcustomerAccessTokenis set on the cart. The two authorization scopes are independent." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/checkout-authentication) - Cart-based checkout auth: "The
customerAccessTokenon the cart authenticates the buyer and authorizes the checkout session for that specific cart. The authorization is scoped to this cart — it doesn't establish a broader session on the Customer Accounts domain." Requirements: set it viacartBuyerIdentityUpdate(or at cart creation), refresh it before expiry, and after refreshing you "must also callcartBuyerIdentityUpdateagain to update the cart with the new token." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/checkout-authentication) - Where the login UI lives (hosted). "Seamless authentication: The hosted customer
authentication system enables passwordless login for customers, allowing them to have a single sign-on
experience across custom storefronts, online store, accounts, and checkout."
(https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api) The documented
integration is a full-page redirect (
window.location.href = authorizationRequestUrl.toString()), not an embedded widget (https://shopify.dev/docs/api/customer). - UNVERIFIED (embedding / login-page customisation): no
shopify.devpage was found documenting an embedded/iframe login, nor a documented iframe-blocking statement. What is documented is branding of sign-in surfaces via the Plus-only Checkout and Accounts Configuration API (https://shopify.dev/docs/apps/build/checkout/styling/checkout-and-accounts-configuration).
3.3 Setup and plan requirement
- Required app configuration: enable customer accounts in admin (Settings → Customer accounts → "Under Accounts in online store and checkout … Choose Customer accounts"), then in the Headless channel choose Customer Account API settings (or Hydrogen → Storefront settings), pick the client type (Public clients / Web clients / Mobile clients / Confidential clients), copy the client ID (and secret if applicable), set storefront permission controls, record the Authorization / Token / Logout endpoints, and configure Callback URL(s). (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/getting-started)
- Prerequisites: "You have Apps and channels permissions on the Shopify store that you're working with." and "Shopify's customer accounts is required to use the Customer Account API." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/getting-started)
- Plan requirement — no minimum plan documented. The Customer Account API docs name rate-limit tiers by
plan (see §3.5) but never state a required plan. UNVERIFIED / partly evidenced: the error list does
include a generic gate —
402 Payment Required→{"errors": "This shop's plan does not have access to this feature"}— which shows some Customer Account API features can be plan-gated, but the doc does not say which. (https://shopify.dev/docs/api/customer) It is not documented as Plus-only. - Merchant-side state: because legacy accounts are closed to new stores and existing stores not using them, and the recommended path is upgrading customer accounts (https://shopify.dev/changelog/posts/legacy-customer-accounts-are-deprecated), a store's customer-accounts version determines whether the legacy Storefront mutations work at all.
3.4 What data it exposes
- Top-level scope, verbatim: "customers, orders, payments, fulfillment, discounts, refunds, and metafields." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api)
- The reference's connection types include
OrderConnection,FulfillmentConnection,CustomerAddressConnection,ReturnConnection/ReturnableLineItemConnection,DraftOrderConnection,PaymentScheduleConnection,CompanyLocationConnection/CompanyContactConnection(B2B),MetafieldReferenceConnection,SaleConnection,SalesAgreementConnection. (https://shopify.dev/sitemap_standard.xml.gz →docs/api/customer/latest/connections/…; entry point https://shopify.dev/docs/api/customer) - Addresses:
customerAddressCreate/customerAddressUpdate/customerAddressDelete/customerUpdate(https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/customer-accounts). 2026-10removals (action required): "The deprecatedCustomer.lastIncompleteCheckoutfield is removed, along with the unreachableCheckouttype subtree. Remove any queries forCustomer.lastIncompleteCheckoutor nestedCheckoutfields before upgrading; there is no Customer Account API replacement." AlsoCustomerAddressInput/CustomerAddressgainedcountryCode(two-letterCountryCode), withterritoryCodedeprecated but still working andcountryCodetaking precedence. (https://shopify.dev/changelog/release-notes/2026-10)- Channel granularity of order history: no
shopify.devstatement was found restricting Customer Account API order history to one sales channel. UNVERIFIED — the docs do not describe channel filtering of the customer's orders.
3.5 Rate limits (relevant, because a headless account area multiplies calls)
- "Rate-limiting method: Calculated query cost, plus a per-customer request limit"
- "Quota: 7,500 cost points per app, per store and customer"
- Standard 100 points/second; Advanced Shopify 200; Shopify Plus 200; Shopify for enterprise (Commerce Components) 400
- "Per-customer request limit: 3,000 requests per minute per store and customer, shared across all apps, in a fixed 60-second window"
- Most fields cost 1 point and most mutations 10 points; responses return
requestedQueryCost/actualQueryCost;Shopify-GraphQL-Cost-Debug=1returns a per-field breakdown. Over-quota →THROTTLED(HTTP 200 for cost, HTTP 429 for the per-customer request limit, withRetry-After).
Source: https://shopify.dev/docs/api/customer#rate-limits
3.6 India-specific caveats
UNVERIFIED — no India-specific customer-account restriction was found on primary sources. What was
searched: the full Customer Account API reference and the headless Customer Account API guide set
(https://shopify.dev/docs/api/customer,
https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api,
…/getting-started, …/authenticate-customers, …/customer-accounts, …/checkout-authentication,
…/market-aware-auth-urls) contain no India-specific limitation; and a Shopify Community search for
India-specific customer-account/OTP issues returned no relevant thread
(https://community.shopify.com/search.json?q=customer+accounts+India+OTP). help.shopify.com's customer
accounts pages could not be retrieved (§7), so a merchant-facing India caveat there cannot be ruled out.
Note only, not a caveat: market-aware-auth-urls documents locale and region_country parameters for
market-aware login (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/market-aware-auth-urls).
3.7 Cross-channel customer identity
Documented sharing, which is directly relevant to running a theme storefront and a headless storefront on one shop:
- "The hosted customer authentication system enables passwordless login for customers, allowing them to have a single sign-on experience across custom storefronts, online store, accounts, and checkout." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api)
- "Customer accounts allow you to seamlessly persist customer logins across online store, Hydrogen, and checkout." (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/getting-started)
- "Shopify's customer accounts is required to use the Customer Account API." (same page) — so the sharing claim holds when both surfaces use the same (current) customer accounts.
4. India-specific constraints
4.1 Shopify Payments in India (INR, domestic)
- Shopify's own India pricing FAQ states Shopify Payments is country-restricted: "Some features vary by country—for example, Shopify Payments is available only in certain countries—so pricing and payment options can differ depending on where your business is based." (https://www.shopify.com/in/pricing)
- Shopify's Shopify Payments Terms of Service list Part II (Regional Terms) as exactly: A. Australia, B. Canada, C. United Kingdom, D. United States — with no India regional terms, and "The Regional Terms applicable to your Designated Country supplement… the Global Terms." Identical for the India-locale copy. (https://www.shopify.com/legal/terms-payments, https://www.shopify.com/in/legal/terms-payments; no occurrence of "Designated Country is India")
- Community evidence (not documentation): on https://community.shopify.com/t/why-shopify-payments-is-not-available-in-india/412204 a community member replied on 2025-05-02: "While Shopify Payments is not yet available in India, you can check other supported payment gateways here: …". A thread opened 2026-09-02 — "Shopify Payments in India — Can Shopify Please Share an Update?" — has three posts, all from merchants, with no Shopify staff reply, and no availability statement; the merchants describe having to "rely on third-party payment gateways" (https://community.shopify.com/t/shopify-payments-in-india-can-shopify-please-share-an-update/675672). Earlier threads in the same vein: https://community.shopify.com/t/shopify-payments-in-india/396271, https://community.shopify.com/t/when-will-shopify-payments-option-be-available-in-india/557214.
- Verdict: the weight of Shopify's own country-scoping statements plus consistent, still-active
merchant reports indicates Shopify Payments is not available to India-based merchants for domestic INR
selling. The official confirmation page could not be retrieved (
help.shopify.comreturns HTTP 403 bot challenges — see §7), so treat the official availability wording as UNVERIFIED and the conclusion as strongly evidenced but not first-party-verbatim. - Practical consequence documented on the pricing page: features marked "Requires Shopify Payments" (showing prices in local currencies, accepting local payment methods, estimating/collecting duties and taxes) are therefore unavailable in India as configured. (https://www.shopify.com/in/pricing)
4.2 Third-party gateways Shopify supports for India
-
Shopify's canonical list is the country-filtered page https://www.shopify.com/payment-gateways?country=in (the help centre points to this list: "Shopify's list of payment gateways by country can help you find out which payment gateway are available in your country and what currency they support." — https://help.shopify.com/en/manual/payments). The page is client-rendered; the gateway dataset is embedded in the page payload.
-
I parsed that payload (country identifier
21; inferred as India because several unmistakably India-only providers are tagged with exactly[21], and "CCAvenue UAE" is tagged[1042], not21). India-tagged providers, as named in Shopify's data:Provider (as displayed) India tag Internal name in payload 01 Cards, UPI, NB, Wallets by Razorpay21 + others Razorpay Payments-New Cards Onsite by 1Razorpay21 + 1 Razorpay Direct - Credit Cards Cards, UPI, NB by PayU India21 + 2 Payu India Onsite Card Payments by PayU India21 only Seamless Payment App Dev CCAvenue21 only CCAVTest BillDesk Payment App21 only BilldeskPaymentApp 01 PhonePe PG (UPI, Cards, EMI & NetBanking)21 only PPE PG Pay securely with Pine Labs21 only Plural PayGlocal21 only PGDeveloperApp airpay21 + 1 Airpay Payment Services 2C2P21 + 12 2C2P Payment Gateway Confidence note: this list is reconstructed from the minified client data payload of Shopify's own page (so the provider names are first-party), but the
21 ⇒ Indiamapping is inferred, not printed anywhere on the page. Verify against https://www.shopify.com/payment-gateways?country=in in a browser before relying on it. Treat as partially verified. -
Distinction to keep in mind: "integrated"/onsite gateway apps (selected at Shopify checkout) versus manual payment methods recorded against an order. The India-tagged entries above are provider apps surfaced through Shopify's payment-gateway list;
help.shopify.com's manual-payment-methods page could not be retrieved to enumerate those separately (§7).
4.3 Cash on Delivery
- Shopify's help centre documents manual payment methods including Cash on Delivery at https://help.shopify.com/en/manual/payments/manual-payments and https://help.shopify.com/en/manual/payments/manual-payments/cash-on-delivery (a legacy "Advanced Cash on Delivery" app page also exists at https://help.shopify.com/en/manual/payments/cash-on-delivery). One such page load did succeed during this research for the sibling section on additional payment methods (https://help.shopify.com/en/manual/payments/additional-payment-methods), but every COD page request returned HTTP 403, so COD's exact configuration, availability and India-specific rules are UNVERIFIED.
- Structural fact that is verified and relevant: payment-method choice happens at Shopify's checkout
("When a customer checks out, they can choose to pay for their order using any of the methods that
you've activated in the Payment providers area" — https://help.shopify.com/en/manual/payments), and
the headless cart's
checkoutUrlredirects there (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage). The Storefront Cart API reference exposes no documented mutation for selecting or configuring a payment method on a cart (inventory check: https://shopify.dev/sitemap_standard.xml.gz; the only related type is thePaymentSettingsobject).
4.4 Who can be a payment provider in India
- Verified, plan-gated statement applicable to any country: "The option to build a custom payment extensions is limited to eligible Shopify Plus Merchants only. Contact Shopify Plus Support to confirm eligibility." and "Only approved Partners can build payments extensions on Shopify's Payments Platform." (https://shopify.dev/docs/apps/build/payments)
- Payment extensions must integrate with Shopify checkout, and five types are documented (credit card; credit card with UI extensibility; custom credit card hosted fields; alternative payment; offsite; redeemables). (https://shopify.dev/docs/apps/build/payments)
- "If you offer credit card payment methods in a country where 3-D Secure authentication is mandated, then you must support 3-D Secure authentication." (https://shopify.dev/docs/apps/build/payments/requirements)
- UNVERIFIED (India-specific provider rules): no
shopify.devor retrievablehelp.shopify.compage was found stating RBI/regulatory requirements for who may be a payment provider in India, nor any rule that an Indian entity/Indian gateway is mandatory. Nothing found either way. Community threads discuss the practical need for Indian gateways but are not authoritative (https://community.shopify.com/t/how-can-i-enable-multi-currency-checkout-in-india-without-shopify-payments/270149).
4.5 Shopify Markets / multi-currency for a single-country INR store
- Markets context on the Storefront API is supported and opt-in. The Storefront API exposes markets /
international pricing, and
@inContextapplies country/language (and, from2026-10,channelId) context to a query; the cart'sbuyerIdentity.countryCodedrives cart pricing (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/markets, https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/in-context, https://shopify.dev/docs/changelog/release-notes/2026-10, https://shopify.dev/docs/api/storefront/latest/mutations/cartBuyerIdentityUpdate). - No documentation requires enabling Markets for a single-country INR store, and no India-specific
restriction on the Storefront API's
@inContextusage was found in those pages. UNVERIFIED as a positive statement (absence of a requirement in the docs is not the same as a documented "not required"). - Documented plan/feature coupling: presenting prices in local currencies, accepting local payment methods, and estimating/collecting duties and taxes are all marked "Requires Shopify Payments" on Shopify's India pricing comparison (https://www.shopify.com/in/pricing) — and Shopify Payments' availability in India is the open question in §4.1.
- Community evidence (not documentation): a 2024-08-24 reply in https://community.shopify.com/t/selling-in-multiple-currencies-from-india/349404 states: "since multi-currency is not available because India is not supported by Shopify payments, you can only choose one currency that you will use to your store"; follow-ups in 2025 and new threads in 2026 repeat the same complaint, including a 2026-02-16 thread seeking multi-currency checkout "in India directly" (https://community.shopify.com/t/how-to-enable-multicurrency-checkout-on-my-store-based-in-india/588501). Label this as community-sourced, not a Shopify statement.
- India tax/invoicing (GST display, INR invoicing rules): UNVERIFIED — no
shopify.devpage describing India GST price-display or invoicing requirements for headless storefronts was found, and the relevanthelp.shopify.compages were unreachable (§7).
5. Shopify changes in 2026 that materially affect a headless build
5.1 API sunset cadence
See §0.2. The load-bearing facts: quarterly releases, ≥12 months of
support per stable version, ≥9 months of overlap, fields deprecated in one release can be removed in the
next, inaccessible versions fall forward rather than failing, and X-Shopify-API-Version reports the
version actually used (https://shopify.dev/docs/api/usage/versioning). Triggering events inside 2026:
2025-10 dies 2026-10-16; 2026-01 is the oldest accessible stable version.
5.2 Storefront API rate limits — the model has changed, and the bucket figures are not current
Verbatim from the Storefront API overview, section Rate limits (https://shopify.dev/docs/api/storefront#rate-limits):
"The Storefront API scales with buyer traffic: requests from real buyers aren't subject to a fixed request-per-minute limit. Automated traffic and checkout creation are limited."
- Rate-limiting method: None for buyer traffic
- Automated traffic: Bots and crawlers are limited, most strictly when unsigned. Sign with Web Bot Auth for higher limits.
- Checkout creation: Throttled per minute, returning a
200 Throttlederror- Tokenless access: Query complexity limit of 1,000
Additional documented details:
- "If a request appears to be malicious, Shopify responds with a
430 Shopify Security Rejectionerror code." (https://shopify.dev/docs/api/storefront#rate-limits) - Checkout-level throttle: "Shopify limits the amount of checkouts that can be created on the
Storefront API per minute. If an API client exceeds this throttle, then a
200 Throttlederror response is returned." Recommended handling: a request queue with exponential backoff. (https://shopify.dev/docs/api/storefront#rate-limits) - Tokenless access has a query complexity limit of 1,000, calculated like GraphQL Admin API costs;
exceeding it returns
MAX_COMPLEXITY_EXCEEDEDwithcostandmaxCostinerrors.extensions. (https://shopify.dev/docs/api/storefront#rate-limits) - Public access capacity scales with the number of buyers, based on their IP address; apps can have a
maximum of 100 active storefront access tokens per shop. Private tokens must be sent in
Shopify-Storefront-Private-Token; buyer-derived server requests must also send the case-sensitiveShopify-Storefront-Buyer-IPheader. (https://shopify.dev/docs/api/storefront) - Web Bot Auth, dated: changelog "Bots and agents should identify themselves via Web Bot Auth" —
postedAt 2026-05-07,effectiveAt 2026-05-30, flagged "Action required": "Shopify now applies stricter rate limits to bots and agents that access the Storefront API and Shopify-hosted online store pages. Bots and agents that don't sign their requests are subject to the strictest limits." (https://shopify.dev/changelog/posts/bots-and-agents-should-identify-themselves-via-web-bot-auth)
On the specific "leaked/actual" figures in the question (query-cost bucket size and restore rate per storefront token): these are not published for the Storefront API in the current documentation, and the current documentation says the model does not work that way for buyer traffic. The generic leaky-bucket page explains that "Most Shopify rate limits are enforced with a leaky bucket algorithm" and that "Both the bucket size and the restore rate vary by API and by plan", but then explicitly carves out the Storefront API: "The Storefront API works differently. Buyer traffic isn't rate-limited at all, and the limits it does apply are described in Storefront API rate limits." (https://shopify.dev/docs/api/usage/limits) The only current cost-based bucket figures in Shopify's docs are for other APIs:
| API | Documented figures | Source |
|---|---|---|
| Storefront API | No bucket size / restore rate published; buyer traffic not fixed-rate-limited; bots limited; checkout creation throttled per minute; tokenless complexity 1,000 | https://shopify.dev/docs/api/storefront#rate-limits, https://shopify.dev/docs/api/usage/limits |
| Customer Account API | Quota 7,500 cost points per app per store+customer; 100 pts/s Standard, 200 Advanced/Plus, 400 enterprise; 3,000 requests/min per store+customer | https://shopify.dev/docs/api/customer#rate-limits |
| GraphQL Admin API | 100 pts/s Standard, 200 Advanced Shopify, 1000 Plus, 2000 enterprise (leaky bucket) | https://shopify.dev/docs/apps/build/apis/graphql-admin/rate-limits |
| Carts specifically | "Carts don't have any global API rate limits" but the cart "is subject to the same throttling restrictions as the Storefront API" | https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart |
So: any figure like "1,000-point bucket, 50 points/second restore per storefront token" should be treated as legacy/unverified against current primary sources.
5.3 unauthenticated_read_* scopes do not cover cart mutations
From the access-scopes reference, the unauthenticated (Storefront API) scope table maps:
| Scope | Access |
|---|---|
unauthenticated_read_checkouts unauthenticated_write_checkouts |
Cart |
unauthenticated_read_content |
Storefront content: Article, Blog, Comment |
unauthenticated_read_customer_tags |
tags field on Customer |
unauthenticated_read_customers unauthenticated_write_customers |
Customer |
unauthenticated_read_metaobjects |
Metaobject, MetaobjectField, MetaobjectSEO |
unauthenticated_read_product_inventory |
quantityAvailable, totalAvailable |
unauthenticated_read_product_listings |
Product, Collection |
unauthenticated_read_product_pickup_locations |
Location, StoreAvailability |
unauthenticated_read_product_tags |
tags field on Product |
unauthenticated_read_selling_plans |
Selling plan content on Product |
unauthenticated_read_shop_pay_installments_pricing |
shopPayInstallmentsPricing |
Source: https://shopify.dev/docs/api/usage/access-scopes#unauthenticated-access-scopes
- So: read scopes alone are insufficient for cart writes. Cart reads need
unauthenticated_read_checkouts; cart mutations needunauthenticated_write_checkouts. The docs further state: "Use unauthenticated access scopes to interact with a store on behalf of a customer" and "For the Headless channel, permissions are managed in your Shopify admin. Refer to request storefront permissions." (https://shopify.dev/docs/api/usage/access-scopes, and https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/manage-headless-channels which lists "Edit storefront permissions" as a Headless-channel task). - Related scope requirements seen in the reference:
customerAccessTokenCreate"Requiresunauthenticated_write_customersaccess scope." (https://shopify.dev/docs/api/storefront/latest/mutations/customerAccessTokenCreate) - Token model: public access token (
storefrontAccessTokenCreateon the GraphQL Admin API, sent asX-Shopify-Storefront-Access-Token) vs private access token (sent asShopify-Storefront-Private-Token, obtained via the Headless channel, a delegate access token, or by requesting unauthenticated access scopes). (https://shopify.dev/docs/api/storefront) The repository's current flow — client-credentials admin token, then mint a storefront access token via…/admin/api/{version}/storefront_access_tokens.json(src/lib/shopify.ts) — corresponds to the public token category; the GraphQL equivalentstorefrontAccessTokenCreateis not marked deprecated in the current reference (https://shopify.dev/docs/api/admin-graphql/latest/mutations/storefrontAccessTokenCreate).
5.4 Other 2026 changes worth knowing
- 2027-01 action required (announced 2026-10-08): "New
owner_typefield for metafield declarations in Checkout and Customer Account UI extensions, required in 2027-01" (https://shopify.dev/changelog/posts/metafield-owner-types-required-for-checkout-and-customer-account-ui-extensions). - Customer Account API
2026-10removals (§3.4) andcountryCodeon addresses (https://shopify.dev/changelog/release-notes/2026-10). - Cart line identification (
viewKey) landed in2026-07(§1.4), including a required migration away fromcart.discountAllocations. @inContextchannelId(2026-10) — channel-scoped availability/pricing in a single query (https://shopify.dev/changelog/release-notes/2026-10).- Deprecation announcements in 2026 include legacy customer accounts (2026-02-26) (§3.1) and the Global Catalog REST API, "Global Catalog REST API stops serving traffic on November 2, 2026" (https://shopify.dev/changelog.md, post dated 10.09).
6. Alternative headless approaches
6.1 Hydrogen — and whether adopting it means abandoning the existing TanStack Start app
- Hydrogen is a framework, not a drop-in library. "Built on React Router, Hydrogen is a Shopify storefront toolkit that provides a set of components, functions, and utilities used for building custom storefronts on React Router apps. Hydrogen is built and optimized to use data coming from the Storefront API." (https://shopify.dev/docs/storefronts/headless/getting-started/build-options)
- Shopify's build-options table frames the three paths as: Hydrogen for "a custom storefront with a React Router app"; Hydrogen React for "a custom storefront using a third-party React framework and Shopify's library of components, reusable functions, and utilities"; or the Headless channel to build "headless using the framework of your choice and Shopify's backend using only the Storefront API." (same page)
- Hydrogen React is explicitly framework-agnostic: "Hydrogen React is a performant, framework-agnostic library of React components, reusable functions, and utilities for interacting with Shopify's Storefront API. It's bundled with Hydrogen, but can be used by any React-based web app." (https://shopify.dev/docs/api/hydrogen-react). Stated as fact: adopting Hydrogen the framework means running a React Router app, whereas Hydrogen React can be used inside any React app.
- Deployment: the Hydrogen channel deploys to Oxygen (Shopify's included edge hosting) and "automatically creates and populates public and private environment variables necessary for integration with the Storefront API", with GitHub integration and order attribution. "Make headless and self-hosted Hydrogen experiences possible in the Headless channel without needing to create a custom app." (https://shopify.dev/docs/storefronts/headless/getting-started/build-options) A migration guide exists at https://shopify.dev/docs/custom-storefronts/hydrogen/migrate.
6.2 Running the classic theme storefront and the headless storefront on one Shopify backend
- Channels are designed for exactly this. "You can use the Shopify admin to manage your commerce data across multiple channels to make sure that all customer touchpoints are in sync. You can also create a custom channel complementary to your online store channel, such as a mobile app, or create your own custom website to replace your online store." (https://shopify.dev/docs/storefronts/headless/getting-started/build-options)
- Shared — the product catalog and inventory: one Shopify store, one catalog; the Headless channel "gives you all of Shopify's channel features, such as product publishing, scheduled product publishing, analytics, and reporting sales by channel", and "Order attribution is at the channel level, and a Headless storefront is treated as a channel." Publishing is per channel, so per-channel product publication must be managed in admin. (https://shopify.dev/docs/storefronts/headless/getting-started/build-options, https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/manage-headless-channels)
- Shared — customers and their logins: see §3.7: "single sign-on experience across custom storefronts, online store, accounts, and checkout" (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api) and "persist customer logins across online store, Hydrogen, and checkout" (https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/getting-started).
- Not shared — carts. Two different cart implementations exist and no bridging mechanism is documented:
the theme storefront uses the Liquid/Ajax cart, and "The Ajax API can only be used by themes that are
hosted by Shopify. You can't use the Ajax API on a Shopify custom storefront."
(https://shopify.dev/docs/api/ajax) The headless storefront uses the Storefront Cart API
(https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart). No
shopify.devpage documents a cart shared between the two. What is shared is the destination: both ultimately send the buyer to the same shop's Shopify-hosted checkout (§2.1). Treat carts as explicitly not shared. - Orders: all channels write orders into the same Shopify admin, attributed by channel (https://shopify.dev/docs/storefronts/headless/getting-started/build-options).
6.3 Headless storefront entitlements
- Documentation: "You can have a maximum of 100 active storefronts and access tokens per shop." (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/manage-headless-channels)
- Shopify's India pricing feature table row "Build headless storefronts" shows 1 / 1 / 1 / 25 for Basic / Grow / Advanced / Plus. (https://www.shopify.com/in/pricing)
- These two figures are not obviously reconcilable, and this is materially important for a merchant on a non-Plus plan planning a second (or staging) headless storefront. Flagged as an apparent discrepancy — verify with Shopify; neither page explains the relationship.
- Also Plus-only per the same pricing page's "Just for Plus" list: "High volume checkout", "Bot protection", "Up to 500% higher API call limits" (https://www.shopify.com/in/pricing), consistent with cart bot protection being Plus (https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart).
7. Verification notes and gaps
Source quality
- Everything cited to
shopify.dev,www.shopify.com/legal,www.shopify.com/in/pricingorwww.shopify.com/payment-gatewaysis Shopify first-party. - Items cited to
github.com/Shopify/storefront-api-feedbackare Shopify-hosted but community/answer content, explicitly labelled with their date where used. - Items cited to
community.shopify.comare community forum posts, not documentation. Where a community reply is used (India payments, India multi-currency), it is labelled as such and not treated as establishing a fact.
What could not be retrieved
help.shopify.comis behind a bot challenge: the overwhelming majority of requests returned403with a "Verifying your connection…" body, for bothcurl(including a browser User-Agent) and the fetch tool. Two pages did return — https://help.shopify.com/en/manual/payments and https://help.shopify.com/en/manual/payments/additional-payment-methods — and are cited for the payment-method-selection statement only. Consequently the following are UNVERIFIED: the official Shopify Payments country-availability list; India's third-party provider list as Shopify's help centre words it; Cash on Delivery configuration and India rules; Shopify's manual payment method list; India billing/GST/invoicing guidance.- The legacy changelog host
changelog.shopify.comreturns 404 forsitemap.xml,posts.jsonandsearch, so the originalcheckout.liquiddeprecation announcement (and its first-round deadlines) could not be retrieved; only the current, authoritative deprecation notice onshopify.devis reported. shopify.dev/changelog.mdreturns only the most recent window of entries;?page=2returns the same first page. Older announcements (e.g. the Storefront rate-limit model change, if it had a post) were therefore not systematically enumerable. Individual post URLs work and.mdfetches succeed.
Reverse-engineered data (treat as partial)
- The India payment-gateway table in §4.2 comes from
the embedded client data payload of https://www.shopify.com/payment-gateways?country=in. The provider
names and their country arrays are first-party data, but the
country id 21 ⇒ Indiamapping is inferred. The parse was validated internally (India-only providers such as BillDesk, PhonePe, Pine Labs/Plural, PayGlocal, CCAvenue are tagged with exactly[21]; "CCAvenue UAE" is[1042]), but it is still an inference.
Open questions flagged for follow-up
- Which host the Storefront API returns in
checkoutUrlfor this shop (myshopify.com vs a custom/primary domain) — the only first-party statement is from 2022 and unconfirmed (§1.3). AnX-Shopify-API-Version/checkoutUrlprobe against the live store would settle both this and the fall-forward version in §0.1. - The final sunset date for legacy customer accounts (announced as "later in 2026", not yet published) (§3.1).
- Whether the Customer Account API is plan-gated, and if so how (only a generic
402 … plan does not have accesserror code is documented) (§3.3). - Whether "1 headless storefront" on Basic/Grow/Advanced is a hard entitlement or a documentation inconsistency with the "100 storefronts per shop" limit (§6.3).
- Any official India availability statement for Shopify Payments, and India COD/GST rules (§4).
File location. This repo keeps prose notes under docs/ (e.g. docs/analytics-setup.md) and has no
existing research folder, so this document was placed in docs/research/. Raw fetched sources used for it
are cached (gitignored) under .cache/shopify-docs/, with the fetcher at .cache/fetch.sh.