Shopify Global Catalog REST Ends Nov 2: Migrate to MCP and UCP
Shopify's Global Catalog REST API goes dark Nov 2, 2026. Here is the endpoint map, a TypeScript MCP client, and the hidden-caller audit to finish first.
On this page
If your app searches products across Shopify stores, you have four days left, not a quarter. Shopify's Global Catalog REST API stops serving traffic on November 2, 2026, and the changelog is blunt about the scope: every request to the old host fails after that date, saved catalogs included. I read the changelog, the catalog docs, and the migration guides that are already live so you can skip the panic and do the swap in order. Short version: this is not a GraphQL rewrite, the endpoint swap is small, and the work that actually bites is finding every hidden caller and re-checking every downstream field.
The short answer
Shopify deprecated the Global Catalog REST API in April 2026 and replaced it with Global Catalog MCP, which implements the Universal Commerce Protocol (UCP). On November 2, 2026, the REST API stops serving traffic. After that date, all four of these endpoints fail:
GET /global/v2/searchGET /global/v2/p/{upid}GET /global/v2/p/by-variant/{vid}POST /global/v2/lookup
The replacement lives at https://catalog.shopify.com/api/ucp/mcp and exposes three tools. Search becomes search_catalog, the two single-product lookups become get_product, and batch lookup becomes lookup_catalog with a limit of 50 identifiers per request on the Global Catalog. That mapping is the whole migration on paper. The rest of this post is about the parts that are not on paper: the agent profile every call now needs, the response shape changes, the callers you forgot about, and the downstream systems that read your catalog data.
First, check whether this deadline is even yours
This deadline only hits you if something in your stack calls the Global Catalog, which is the cross-merchant catalog. It is not the same as a single store's Storefront API, and it is not the same as the per-store Storefront Catalog MCP at https://{shop}.myshopify.com/api/ucp/mcp. If your app only reads one merchant's own products, this post is not your migration. If your app compares products across merchants, builds recommendations across stores, or resolves a product ID it got from somewhere else in the Shopify ecosystem, check now.
Run the audit before you write any migration code, because the audit decides how big the job is:
# Search every repo you own for the old host and paths
grep -rn "discover.shopifyapps.com/global" --include="*.ts" --include="*.js" --include="*.py" .
grep -rn "/global/v2/" --include="*.ts" --include="*.js" --include="*.py" .Then go beyond your own repos. Check outbound request logs for the old host, check agency scripts and middleware wrappers, check scheduled jobs, and check any third-party App Store app that touches catalog data. Ask each vendor in writing whether they still call the old endpoints. The migration guides already live agree on this point: the endpoint swap is small, and the failures come from callers nobody remembered, including outdated app versions still in the wild. If a vendor cannot confirm, treat their integration as still calling the old API until you have proof otherwise.
The endpoint-to-tool map
Here is the full map, taken from Shopify's changelog and catalog docs:
| Old REST endpoint | New MCP tool | What changes in the call |
|---|---|---|
GET /global/v2/search | search_catalog | Free-text query, filters, pagination, and buyer context move into the tool arguments. Results are clustered by Universal Product ID (UPID) and include offers from multiple merchants. |
GET /global/v2/p/{upid} | get_product | Pass a product global ID and get full details, including all option combinations with availability signals and checkout links. |
GET /global/v2/p/by-variant/{vid} | get_product | Pass a variant global ID instead of a product ID. Use the selected argument to anchor a specific variant. |
POST /global/v2/lookup | lookup_catalog | Batch lookup by identifier, up to 50 per request on the Global Catalog. Unresolved IDs are reported in messages, so check that field instead of assuming every ID resolved. |
Two limits are worth keeping straight because the docs use the same tool names for two different catalogs. The Global Catalog lookup_catalog resolves up to 50 identifiers per request. The per-store Storefront Catalog lookup_catalog supports up to 10. If you copy a limit from a Storefront example into Global Catalog code, or the other way round, you will build a batching bug that only shows up at volume.
The discovery flow also changes shape. The documented pattern is two steps: discover first with search_catalog or lookup_catalog, then evaluate with get_product once a buyer has picked something, so you can refine the variant choice and read pricing and seller checkout links for the exact variant. search_catalog also accepts a text query, an image, or a set of product IDs to find similar items, which the old search endpoint did not offer in the same form.
What every new call must carry
The biggest behavioral change is not the URL. It is the agent profile. Every Global Catalog MCP request must include a meta.ucp-agent.profile URL pointing at your agent's UCP profile, and the tools your agent can call depend on the capabilities that profile advertises. Shopify's catalog docs state the profile requirement plainly. Independent reports describe the failure mode when it is missing: a 422 response naming the missing profile. Build the profile into your client once, not per call site, so a future capability change is one edit.
Saved catalogs change form too. The old API addressed a saved catalog through its URL. The new API takes the saved catalog's ID in the request body, as catalog_id, according to the migration guides. If you port the old URL logic literally, saved-catalog calls will fail in a way that looks like a permissions problem. It is not permissions. It is the wrong addressing.
Authentication is the one thing that does not change, according to the migration guides: existing Dev Dashboard bearer tokens keep working against the new endpoint. I am attributing that to the guides rather than the changelog, because the changelog itself lists the endpoint and tools without a separate auth section. Verify it with one authenticated call in your own environment before cutover day, and do not let an auth assumption be the thing you discover on November 2.
Here is the shape of a call, adapted from the documented JSON-RPC pattern. Treat this as a starting template to verify against Shopify's live catalog docs, not as code I ran against your catalog:
// Minimal Global Catalog MCP search over JSON-RPC 2.0
// Verify the profile URL and scopes against Shopify's catalog docs
// before you ship this, and keep the profile in one shared client.
async function searchCatalog(query: string) {
const res = await fetch("https://catalog.shopify.com/api/ucp/mcp", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json, text/event-stream",
// Authorization: `Bearer ${process.env.SHOPIFY_DEV_TOKEN}`,
},
body: JSON.stringify({
jsonrpc: "2.0",
method: "tools/call",
id: 1,
params: {
name: "search_catalog",
arguments: {
meta: {
"ucp-agent": {
profile: "https://your-agent.example/ucp/profile.json",
},
},
catalog: {
query,
context: { address_country: "US", currency: "USD" },
filters: { available: true },
pagination: { limit: 10 },
},
},
},
}),
});
if (!res.ok) {
throw new Error(`Catalog search failed: ${res.status}`);
}
const data = await res.json();
return data.result?.structuredContent?.products ?? [];
}Three details in that template deserve attention. First, the Accept header allows both JSON and event-stream responses, because MCP servers can stream. Second, the buyer context (country and currency) now travels with the request, so a search that used to inherit context from somewhere else must pass it explicitly. Third, the products come back under structuredContent, not as a top-level REST body, so every parser downstream of the old response shape needs a rewrite, not a rename.
The downstream-field audit most teams skip
The endpoint swap takes an afternoon. The downstream audit takes the rest of the week, and it is where a November 2 migration actually fails. Catalog data rarely stops at the search response. It flows into pricing displays, stock checks, recommendation rankings, ERP records, and order creation. A renamed field, a re-nested variant, or a price that now arrives in minor units can pass your own smoke test and break a downstream system days later, when the bad data has already spread.
Walk every field your code reads from the old response and map it to the new UCP catalog schema before you cut over:
- Price vs list price. Each variant carries
price, the price the buyer pays when available, and optionallylist_price, the merchant's compare-at price for the buyer's market. If your old code treated the first price it found as the selling price, confirm which field that was. A strikethrough price shown as the selling price is a pricing bug your customers will find first. - Availability signals.
get_productreturns availability signals per option combination. If your old code cached availability from search results, stop. Shopify's catalog guidance says not to cache search results, because they reflect merchant preferences on pricing, availability, and presentation. Cache policy is now a correctness issue, not a performance choice. - Images. Images may only be used in connection with the related merchant's product listing and must be rendered in real time, not downloaded to your servers, per the same guidance. If your pipeline downloads catalog images for re-hosting, that step has to go.
- Unresolved IDs.
lookup_catalogreports unresolved IDs inmessages. Your batch code must handle partial success: some IDs resolve, some do not, and the response is still a success. Code that assumes a batch either fully works or fully fails will silently drop products. - Checkout authority. Catalog responses reflect the business's current terms for that request, but they are not transactional commitments. Checkout is authoritative. Re-validate price and availability at checkout instead of trusting a catalog response you fetched earlier in the session, and never reuse a catalog response across sessions without re-validation.
Run the old and new paths side by side for at least one full day before you switch traffic. Log mismatches per field, not just per request, so a single renamed field shows up as a pattern instead of one noisy error. The goal of the shadow run is not to prove the new API works. It is to prove your downstream systems still agree with it.
The four-day cutover plan
Today is October 29. The cutoff is November 2. Here is the order I would use, with the risky work first:
Day 1, October 29: audit and map
Grep every repo, check outbound logs, and get written vendor confirmations. Map every old field your code reads to the new UCP schema. Decide whether you own a Global Catalog caller at all, and if you do, list every downstream consumer of its data.
Day 2, October 30: swap and parse
Build the shared MCP client with the agent profile in one place. Port search, single-product lookup, variant lookup, and batch lookup to the three tools. Rewrite every parser for the new response shape. Do not ship yet.
Day 3, October 31: shadow run
Run old and new paths side by side. Compare field by field, fix the mismatches, and check the unresolved-ID path in batch lookup with a deliberately bad ID. Confirm saved catalogs resolve through
catalog_idin the body.Day 4, November 1 to 2: cut over and watch
Switch traffic before the cutoff, not on it. Watch search-empty rates, lookup failure rates, and downstream pricing and order errors for 24 hours. Keep the old code path behind a flag for rollback, but remember the old endpoint itself will not come back, so rollback means fixing forward on the new API.
If you cannot finish the shadow run, cut over anyway before November 2 with the new path and a tight watch, because the alternative is a guaranteed outage on the old path. A new-path bug you can see in logs beats an old-path outage you cannot fix. If you have no Global Catalog caller at all, the right move is to do nothing and say so in your incident notes, so nobody re-opens this migration in a panic on November 2.
What this migration is really about
The protocol shift matters beyond this one deadline. UCP is the open standard Google and Shopify co-developed for agents to search catalogs, build carts, check out, link accounts, and track orders through one contract, instead of one custom integration per store. The Global Catalog MCP is the catalog slice of that contract, exposed as tools an agent can call. Your migration is therefore not just a URL change. It moves your cross-merchant discovery onto the same tool-calling pattern agents already use for single-store catalogs, carts, and checkout.
That also reframes the money question. The teams that will get migration work out of this deadline are not the ones who can rename an endpoint. They are the ones who can audit a stack, find the hidden callers, map the downstream fields, and cut over without a pricing incident. If you run a Shopify app or an agentic-commerce integration, that audit is a sellable service this week: a fixed-scope check that answers whether a client calls the old API, what breaks on November 2, and what the new path costs. The deadline does the selling. Your job is to make the audit thorough enough that the client trusts the answer.
Tools and sources
| Tool or doc | What it is for | Official link |
|---|---|---|
| Shopify changelog: Global Catalog REST API stops serving traffic on November 2, 2026 | The deadline, the four endpoints, the new endpoint, and the three replacement tools | https://shopify.dev/changelog/posts/global-catalog-rest-api-stops-serving-traffic-on-november-2-2026 |
| Shopify docs: Global Catalog MCP | The two-step discover-then-evaluate flow, UPID clustering, and the ucp CLI path | https://shopify.dev/docs/agents/catalog/global-catalog |
| Shopify docs: About Catalogs | The shared rules for both catalog interfaces, including the image and caching rules and the 50 vs 10 lookup limits | https://shopify.dev/docs/agents/catalog |
My verdict: what I would do, and what I would not
If I owned a Global Catalog caller today, I would start with the audit, not the code, and I would cut over on November 1 at the latest, with a full day of shadow-run logs behind me. I would not start a GraphQL rewrite, I would not cache search results or re-host images under the new rules, and I would not trust a vendor's silence as confirmation. The one condition that flips my answer is simple: if the audit proves nothing calls the old API, I would do nothing at all, and I would write that finding down so the question does not come back on deadline day. Four days is enough for a careful swap and not enough for a careless one, so spend the days on the callers and the fields, not on the endpoint rename.
Frequently asked questions
When does Shopify's Global Catalog REST API stop working?
On November 2, 2026. Shopify's developer changelog says the API stops serving traffic on that date, including requests against saved catalogs. It was deprecated in April 2026 and replaced by Global Catalog MCP.
What replaces the Global Catalog REST API?
Global Catalog MCP at https://catalog.shopify.com/api/ucp/mcp. It implements the Universal Commerce Protocol (UCP) and exposes three catalog tools: search_catalog, lookup_catalog, and get_product.
How do the old REST endpoints map to the new MCP tools?
GET /global/v2/search maps to search_catalog. GET /global/v2/p/{upid} and GET /global/v2/p/by-variant/{vid} both map to get_product. POST /global/v2/lookup maps to lookup_catalog, which resolves up to 50 identifiers per request on the Global Catalog.
Does the Global Catalog MCP need an agent profile on every call?
Yes. Every request must include a meta.ucp-agent.profile URL pointing at your agent's UCP profile. Shopify's catalog docs state this as a requirement, and independent migration reports describe a 422 response when the profile is missing.
Is this the same as migrating to the Shopify GraphQL Admin API?
No. The GraphQL Admin API covers a single store's own data. The Global Catalog covers products across many Shopify merchants, so its replacement is the cross-merchant Global Catalog MCP, not a per-store GraphQL rewrite.
What breaks first if I miss the November 2 deadline?
Cross-merchant search goes empty and product lookups fail, because every call to discover.shopifyapps.com/global fails after the cutoff. If catalog data feeds pricing, stock checks, or order creation downstream, the visible failure can arrive days later as wrong prices or stalled orders.
Want this migration done on your app instead of reading about it? I build commerce and agent integrations for a living - tell me about your stack and I will tell you honestly whether this is a one-day swap or a downstream audit first.
If agentic buying is the wider question behind this migration, start with my Agentic Checkout Checklist - being found in a catalog is the gate before an agent can buy.

