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.
1012 lines
78 KiB
Markdown
1012 lines
78 KiB
Markdown
# 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](#7-verification-notes-and-gaps). 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-10` on
|
|
<https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate> and on
|
|
<https://shopify.dev/docs/api/customer/latest>.
|
|
* **`2025-01` is not in the table at all.** The oldest accessible stable version is `2026-01`, so
|
|
`2025-01` is 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-01` would 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-Version` reflecting the version actually used, so a repository pinned to `2025-01` is in
|
|
practice being served `2026-01`.
|
|
Source: <https://shopify.dev/docs/api/usage/versioning>
|
|
* **Imminent:** `2025-10` becomes inaccessible on **October 16, 2026 15:00 UTC** (three days after this
|
|
research). Source: <https://shopify.dev/docs/api/usage/versioning>
|
|
* `src/lib/shopify.ts` currently sets `API_VERSION = "2025-01"` and `ADMIN_API_VERSION = "2026-07"`.
|
|
Stated as fact only: `2025-01` is retired, and `2026-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-10` might be removed in `2027-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 new `Cart` for 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 a `checkoutUrl` that directs the buyer to complete their
|
|
purchase."* (<https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate>)
|
|
* `cartLinesAdd` — *"Quantity defaults to `1` if 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."* Omitting `attributes` or setting it to `null` preserves
|
|
existing line attributes; an empty array clears them all.
|
|
(<https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesUpdate>)
|
|
* `cartLinesRemove` — accepts **either** `lineIds` **or** `viewKeys`, *"Mutually exclusive with
|
|
`lineIds`."* (<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>)
|
|
* `cart` query — *"Returns a `Cart` by 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>)
|
|
* `Cart` object: *"Use the `checkoutUrl` field 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](#63-headless-storefront-entitlements). | <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 `checkoutUrl` should 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 `checkoutUrl` yields a logged-in checkout; to
|
|
preserve that for **server-side** Storefront API calls you must send the `Shopify-Storefront-Buyer-IP`
|
|
header. *"Without the `Shopify-Storefront-Buyer-IP` header, 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 API `cartDiscountCodesUpdate` mutation must now include the
|
|
`discountCodes` argument"* (previously accepted but a no-op). Also returns
|
|
`GIFT_CARD_RECIPIENT_INVALID` in `userErrors` for `cartCreate`/`cartLinesAdd` instead of an empty cart.
|
|
(<https://shopify.dev/changelog/release-notes/2026-01>)
|
|
* **`2026-04`** — Storefront API returns `MERCHANDISE_LINE_TRANSFORMERS_RUN_ERROR` when a Cart Transform
|
|
Function errors during `cartCreate`/`cartLinesAdd`, replacing the generic `INVALID`.
|
|
(<https://shopify.dev/changelog/release-notes/2026-04>)
|
|
* **`2026-07`** — `CartLine.viewKey` added (*"returning the same value rendered by Liquid storefronts and
|
|
accepted by `cartLinesUpdate` and `cartLinesRemove`"*); `cartLinesUpdate`/`cartLinesRemove` accept
|
|
`view_key`/`viewKeys`; new `CartWarning` code `PRODUCT_UNAVAILABLE_IN_BUYER_LOCATION`; and an
|
|
action-required migration away from deprecated `cart.discountAllocations` to
|
|
`cart.discountApplications`, `cart.lines[].discountAllocations(lineLevelOnly: false)` and
|
|
`cart.deliveryGroups[].discountAllocations`.
|
|
(<https://shopify.dev/changelog/release-notes/2026-07>)
|
|
* **`2026-10`** — `@inContext` gained an optional `channelId` argument 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 `checkoutUrl` that directs the buyer to complete
|
|
their purchase."* / *"the response includes a URL that redirects customers through Shopify's web
|
|
checkout."* / *"Use the `checkoutUrl` field 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.dev` sitemap contains **no** Storefront API
|
|
mutations or queries under `checkout*` for the current version. The only surviving payment-adjacent
|
|
members of the Storefront API are `shopPayPaymentRequestSessionCreate`,
|
|
`shopPayPaymentRequestSessionSubmit`, the `paymentSettings` query and the `PaymentSettings` object
|
|
(<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](#26-the-one-documented-exception-shop-pay-wallet-merchant-built-checkout).
|
|
* 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.liquid` is now unsupported for the Information, Shipping, and Payment checkout steps.
|
|
> `checkout.liquid` and 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.liquid` for the Thank you and Order status pages must upgrade
|
|
to Shopify Extensions in Checkout."* Merchants can *"revert to `checkout.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.liquid` and 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.com` legacy 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:
|
|
|
|
1. The only documented successor to the removed Checkout APIs is a redirect to *"Shopify's web checkout"*
|
|
(§2.1, §2.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).
|
|
3. 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>).
|
|
4. 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… The
|
|
`idempotencyKey` argument ensures the payment transaction occurs only once, preventing duplicate
|
|
charges. On success, returns a `ShopPayPaymentRequestReceipt` with 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.com` and
|
|
`*.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 `paymentcomplete` event to confirm order creation,
|
|
because the customer can close the popup or lose network connectivity. Use webhooks and a reconciliation
|
|
job…"* — subscribing to `ORDERS_CREATE` and `ORDER_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](#41-shopify-payments-in-india-inr-domestic)
|
|
— **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-10` on
|
|
<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 for
|
|
`customerAccessTokenCreate` now opens with: *"Requires `unauthenticated_write_customers` access scope.
|
|
For **legacy customer accounts only**."*
|
|
(<https://shopify.dev/docs/api/storefront/latest/mutations/customerAccessTokenCreate>)
|
|
Note the precise status: the mutation itself is **not** flagged `Deprecated` in the reference (only its
|
|
`userErrors` field 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) and
|
|
`GET /.well-known/customer-account-api` (Shopify-specific: GraphQL + MCP endpoints).
|
|
(<https://shopify.dev/docs/api/customer>)
|
|
* **Documented endpoint values:**
|
|
```
|
|
"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}"
|
|
```
|
|
(<https://shopify.dev/docs/api/customer>)
|
|
* **Scope string:** `openid email customer-account-api:full` (required)
|
|
(<https://shopify.dev/docs/api/customer>)
|
|
* **Session/silent auth:** append `&sso=silent` to the cart's `checkoutUrl` to have checkout verify the
|
|
buyer's live Customer Accounts browser session via an OIDC-compliant flow. Caveat, verbatim: *"`sso=silent`
|
|
does 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 valid `customerAccessToken` is 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 `customerAccessToken` on 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 via
|
|
`cartBuyerIdentityUpdate` (or at cart creation), refresh it before expiry, and after refreshing you
|
|
*"must also call `cartBuyerIdentityUpdate` again 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.dev` page 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-10` removals (action required):** *"The deprecated `Customer.lastIncompleteCheckout` field is
|
|
removed, along with the unreachable `Checkout` type subtree. Remove any queries for
|
|
`Customer.lastIncompleteCheckout` or nested `Checkout` fields before upgrading; there is no Customer
|
|
Account API replacement."* Also `CustomerAddressInput`/`CustomerAddress` gained `countryCode` (two-letter
|
|
`CountryCode`), with `territoryCode` deprecated but still working and `countryCode` taking precedence.
|
|
(<https://shopify.dev/changelog/release-notes/2026-10>)
|
|
* **Channel granularity of order history:** no `shopify.dev` statement 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=1` returns a per-field breakdown. Over-quota → `THROTTLED`
|
|
(HTTP 200 for cost, HTTP 429 for the per-customer request limit, with `Retry-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.com` returns 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]`, not `21`).
|
|
India-tagged providers, as named in Shopify's data:
|
|
|
|
| Provider (as displayed) | India tag | Internal name in payload |
|
|
| - | - | - |
|
|
| `01 Cards, UPI, NB, Wallets by Razorpay` | 21 + others | Razorpay Payments-New |
|
|
| `Cards Onsite by 1Razorpay` | 21 + 1 | Razorpay Direct - Credit Cards |
|
|
| `Cards, UPI, NB by PayU India` | 21 + 2 | Payu India |
|
|
| `Onsite Card Payments by PayU India` | 21 only | Seamless Payment App Dev |
|
|
| `CCAvenue` | 21 only | CCAVTest |
|
|
| `BillDesk Payment App` | 21 only | BilldeskPaymentApp |
|
|
| `01 PhonePe PG (UPI, Cards, EMI & NetBanking)` | 21 only | PPE PG |
|
|
| `Pay securely with Pine Labs` | 21 only | Plural |
|
|
| `PayGlocal` | 21 only | PGDeveloperApp |
|
|
| `airpay` | 21 + 1 | Airpay Payment Services |
|
|
| `2C2P` | 21 + 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 ⇒ India` mapping 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 `checkoutUrl` redirects 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
|
|
the `PaymentSettings` object).
|
|
|
|
### 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.dev` or retrievable `help.shopify.com` page
|
|
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 `@inContext` applies country/language (and, from `2026-10`, `channelId`)
|
|
context to a query; the cart's `buyerIdentity.countryCode` drives 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 `@inContext` usage 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.dev` page
|
|
describing India GST price-display or invoicing requirements for headless storefronts was found, and the
|
|
relevant `help.shopify.com` pages were unreachable (§7).
|
|
|
|
---
|
|
|
|
## 5. Shopify changes in 2026 that materially affect a headless build
|
|
|
|
### 5.1 API sunset cadence
|
|
|
|
See [§0.2](#02-release-and-deprecation-cadence). 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 Throttled` error
|
|
> * **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 Rejection` error
|
|
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 Throttled` error 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_EXCEEDED` with `cost` and `maxCost` in `errors.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-sensitive
|
|
`Shopify-Storefront-Buyer-IP` header. (<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 need `unauthenticated_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` *"Requires
|
|
`unauthenticated_write_customers` access scope."*
|
|
(<https://shopify.dev/docs/api/storefront/latest/mutations/customerAccessTokenCreate>)
|
|
* Token model: public access token (`storefrontAccessTokenCreate` on the GraphQL Admin API, sent as
|
|
`X-Shopify-Storefront-Access-Token`) vs private access token (sent as `Shopify-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 equivalent
|
|
`storefrontAccessTokenCreate` is 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_type` field 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-10` removals** (§3.4) and **`countryCode` on addresses**
|
|
(<https://shopify.dev/changelog/release-notes/2026-10>).
|
|
* **Cart line identification (`viewKey`) landed in `2026-07`** (§1.4), including a required migration away
|
|
from `cart.discountAllocations`.
|
|
* **`@inContext` `channelId` (`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](#37-cross-channel-customer-identity): *"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.dev`
|
|
page 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/pricing` or
|
|
`www.shopify.com/payment-gateways` is **Shopify first-party**.
|
|
* Items cited to `github.com/Shopify/storefront-api-feedback` are Shopify-hosted but **community/answer
|
|
content**, explicitly labelled with their date where used.
|
|
* Items cited to `community.shopify.com` are **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.com` is behind a bot challenge: the overwhelming majority of requests returned
|
|
`403` with a "Verifying your connection…" body, for both `curl` (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.com` returns 404 for `sitemap.xml`, `posts.json` and
|
|
`search`, so the **original** `checkout.liquid` deprecation announcement (and its first-round deadlines)
|
|
could not be retrieved; only the current, authoritative deprecation notice on `shopify.dev` is reported.
|
|
* `shopify.dev/changelog.md` returns only the most recent window of entries; `?page=2` returns 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 `.md` fetches succeed.
|
|
|
|
**Reverse-engineered data (treat as partial)**
|
|
|
|
* The India payment-gateway table in [§4.2](#42-third-party-gateways-shopify-supports-for-india) 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 ⇒ India` mapping 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**
|
|
|
|
1. Which host the Storefront API returns in `checkoutUrl` for this shop (myshopify.com vs a custom/primary
|
|
domain) — the only first-party statement is from 2022 and unconfirmed (§1.3). An `X-Shopify-API-Version`
|
|
/ `checkoutUrl` probe against the live store would settle both this and the fall-forward version in §0.1.
|
|
2. The final sunset date for legacy customer accounts (announced as "later in 2026", not yet published)
|
|
(§3.1).
|
|
3. Whether the Customer Account API is plan-gated, and if so how (only a generic `402 … plan does not have
|
|
access` error code is documented) (§3.3).
|
|
4. 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).
|
|
5. 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`.
|
|
|
|
---
|
|
|
|
## 8. Primary source index
|
|
|
|
| URL | Used for |
|
|
| - | - |
|
|
| <https://shopify.dev/docs/api/usage/versioning> | Version table, support windows, fall-forward, cadence, deprecation practice |
|
|
| <https://shopify.dev/docs/api/usage/limits> | Global array cap 250, pagination cap 25,000, leaky bucket, Storefront carve-out |
|
|
| <https://shopify.dev/docs/api/usage/access-scopes> | Unauthenticated scopes → `Cart`/`Customer` mapping |
|
|
| <https://shopify.dev/docs/api/storefront> | Endpoint, token types, rate limits, bot auth, buyer-IP header, 100-token cap |
|
|
| <https://shopify.dev/docs/api/storefront/latest/objects/Cart> | `checkoutUrl`, Cart fields, 250-value inputs |
|
|
| <https://shopify.dev/docs/api/storefront/latest/queries/cart> | `cart(id:)` |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/cartCreate> | `cartCreate` shape |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesAdd> | `cartLinesAdd`, 250 lines, quantity default |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesUpdate> | `cartLinesUpdate`, 250 lines, attribute semantics |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/cartLinesRemove> | `cartLinesRemove`, `lineIds`/`viewKeys` |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/cartBuyerIdentityUpdate> | Buyer identity, logged-in checkout |
|
|
| <https://shopify.dev/docs/api/storefront/latest/input-objects/CartLineInput> | `quantity: Int` default 1, no max |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart> | 500 lines, 30-day expiry, unlimited carts, no cart rate limit, Plus bot protection |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/manage> | checkoutUrl example + staleness, buyer-IP header |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/cart/migrate-to-cart-api> | Checkout APIs deprecated 2024-04, sunset 2025-04 |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/manage-headless-channels> | 100 storefronts/tokens, storefront permissions, per-channel publishing |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/markets> | Markets/international pricing on Storefront API |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/in-context> | `@inContext` |
|
|
| <https://shopify.dev/docs/storefronts/headless/getting-started/build-options> | Hydrogen vs Hydrogen React vs Headless channel; multi-channel sync |
|
|
| <https://shopify.dev/docs/storefronts/headless/hydrogen> | Hydrogen |
|
|
| <https://shopify.dev/docs/api/hydrogen-react> | Hydrogen React framework-agnostic claim |
|
|
| <https://shopify.dev/docs/api/ajax> | Ajax API unusable on custom storefronts |
|
|
| <https://shopify.dev/docs/apps/build/checkout> | Checkout Extensibility entry, checkout.liquid notice, revert window |
|
|
| <https://shopify.dev/docs/apps/build/checkout/technologies> | Plan-gating table, market overrides |
|
|
| <https://shopify.dev/docs/apps/build/checkout/styling> | Checkout styling Plus-only |
|
|
| <https://shopify.dev/docs/apps/build/checkout/styling/checkout-and-accounts-configuration> | Checkout/accounts/sign-in styling Plus-only |
|
|
| <https://shopify.dev/docs/apps/build/checkout/capabilities> | Extension capabilities sandbox |
|
|
| <https://shopify.dev/docs/storefronts/themes/architecture/layouts/checkout-liquid> | checkout.liquid Plus-only + deprecation notice |
|
|
| <https://shopify.dev/docs/apps/build/payments> | Custom payment extensions Plus-only, Partner-only; extension types |
|
|
| <https://shopify.dev/docs/apps/build/payments/requirements> | 3-D Secure requirement |
|
|
| <https://shopify.dev/docs/api/commerce-components/pay> | Shop Pay Wallet: merchant-built checkout, new-store-only, Shopify Payments required, async order creation |
|
|
| <https://shopify.dev/docs/api/commerce-components/pay/shop-configuration> | Shop Pay Wallet plan, per-plan card rates, pre-configured custom app |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/shopPayPaymentRequestSessionCreate> | Shop Pay payment request session creation |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/shopPayPaymentRequestSessionSubmit> | Shop Pay session submit, idempotency, receipt |
|
|
| <https://shopify.dev/docs/api/storefront/latest/queries/paymentSettings> | `paymentSettings` query (only other payment surface) |
|
|
| <https://shopify.dev/docs/api/customer> | Customer Account API auth, discovery, scopes, rate limits, 402 gate |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api> | Hosted auth, SSO across surfaces, data scope |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/getting-started> | Enable customer accounts, client types, endpoints, permissions |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/checkout-authentication> | Cart token vs `sso=silent` |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-customer-account-api/customer-accounts> | Address/profile mutations |
|
|
| <https://shopify.dev/docs/api/storefront/latest/mutations/customerAccessTokenCreate> | Legacy-only status, `unauthenticated_write_customers` |
|
|
| <https://shopify.dev/docs/storefronts/headless/building-with-the-storefront-api/customer-accounts> | Legacy Storefront customer flow |
|
|
| <https://shopify.dev/changelog/posts/legacy-customer-accounts-are-deprecated> | Legacy deprecation, 2026-02-26 |
|
|
| <https://shopify.dev/changelog/posts/bots-and-agents-should-identify-themselves-via-web-bot-auth> | Web Bot Auth, effective 2026-05-30 |
|
|
| <https://shopify.dev/changelog/release-notes/2026-10> | 2026-10 changes, Cart/CAAPI/`@inContext` |
|
|
| <https://shopify.dev/changelog/release-notes/2026-07> | Cart `viewKey`, discount field migration |
|
|
| <https://shopify.dev/changelog/release-notes/2026-04> | Cart transform error code |
|
|
| <https://shopify.dev/changelog/release-notes/2026-01> | `cartDiscountCodesUpdate` requires `discountCodes` |
|
|
| <https://shopify.dev/docs/apps/build/apis/graphql-admin/rate-limits> | Admin plan tier names and figures |
|
|
| <https://www.shopify.com/in/pricing> | Plan names/prices in INR, 3rd-party fees, checkout customization row, headless storefronts row, "Requires Shopify Payments" features |
|
|
| <https://www.shopify.com/legal/terms-payments> | Shopify Payments regional terms (AU/CA/UK/US only) |
|
|
| <https://www.shopify.com/payment-gateways?country=in> | Country-filtered provider list (client-rendered) |
|
|
| <https://help.shopify.com/en/manual/payments> | Payment methods chosen at checkout; link to gateway list by country |
|
|
| <https://help.shopify.com/en/manual/payments/additional-payment-methods> | Additional payment methods; third-party transaction fees |
|
|
| <https://github.com/Shopify/storefront-api-feedback/discussions/130> | Maintainer answer on checkoutUrl domain (2022, unconfirmed) |
|
|
| <https://community.shopify.com/t/why-shopify-payments-is-not-available-in-india/412204> | Community: Shopify Payments not available in India (2025-05-02) |
|
|
| <https://community.shopify.com/t/shopify-payments-in-india-can-shopify-please-share-an-update/675672> | Community: still unavailable, 2026-09-02 |
|
|
| <https://community.shopify.com/t/selling-in-multiple-currencies-from-india/349404> | Community: India multi-currency tied to Shopify Payments (2024-08-24) |
|
|
| <https://community.shopify.com/t/how-to-enable-multicurrency-checkout-on-my-store-based-in-india/588501> | Community: 2026-02-16, same constraint |
|