The Feedance AI features is rolling out.
Check it out!

Fixing Google Content API 410 Errors: Migrating Your Feed Pipeline to Merchant API

Google's Content API for Shopping was sunset on August 18, 2026. Since September 1, requests from projects without an approved extension have been failing intermittently with HTTP 410, and the endpoints shut down completely in early 2027 (Google's sunset notice). If a script, plugin or in-house connector still pushes your products to Merchant Center through the old API, some of those updates are already being dropped.

This guide is for developers and feed owners who maintain that pipeline themselves. By the end you will be able to find every remaining Content API call, map each one to its Merchant API equivalent, create the data source the new API requires, and confirm in Merchant Center that products and prices are still landing.

How to tell whether you are being hit by the sunset

The failure is easy to miss because it is intermittent. Google documents the error body as a 410 with a message that begins "Content API for Shopping was sunset on August 18, 2026", and it includes your Google Cloud project ID, project number and a help-center link. Search your integration logs for that string and for shoppingcontent.googleapis.com.

Three symptoms usually show up before anyone reads a log:

  • Price or availability changes reach Google hours late, or only on some runs.
  • A daily job reports success on most batches and fails on a few.
  • Merchant Center shows stale data while your store shows the correct price.

The last symptom has a second possible cause, which is Google's own automatic item updates overriding your values. We cover that separately in stopping Google from silently overriding your feed's price and availability. Rule out the 410s first, because they are cheaper to confirm.

Step 1: Inventory every caller of the old API

Google's own guidance is to review your application code for direct calls to Content API endpoints. In practice the calls hide in four places: the store platform's Google plugin, a custom script a previous developer wrote, a feed or ERP middleware, and a Google Ads script or Apps Script someone scheduled years ago.

Build a short register with one row per caller. Record what it does, which Google Cloud project it authenticates with, and who owns it. The project ID matters because extensions and the 410 message are tied to it.

CallerWhat it sendsOwnerAction
Store pluginFull catalog, dailyPlatform vendorAsk which API version it uses now
Inventory scriptPrice and stock, hourlyYour developerMigrate to Merchant API
Feed management toolOptimised feedTool vendorAsk for migration confirmation in writing

If a vendor manages the connection, your job is to ask, not to rebuild. Productsup and Feedonomics have both published migration write-ups, and a mature vendor will have moved already. Ask every vendor on your list the same question and keep the answers.

Step 2: Decide whether you need an extension

Google offers a Content API extension request form for organisations that need more time. Approved extensions protect a project from the scheduled error responses for the approved window, and they do not extend past final decommissioning in early 2027. Google does not state who qualifies.

Use this decision rule. If every caller can be migrated and tested within a few weeks, skip the extension and spend the time on the migration. If a caller belongs to a vendor with a confirmed but unscheduled migration, request an extension for that project only. An extension is a buffer, not a plan.

Step 3: Map each call to its Merchant API equivalent

Merchant API splits the old monolith into sub-APIs and versions the URL (/products/v1/). Version v1 reached general availability in July 2025 and v1beta was sunset on February 28, 2026, so build against v1 and ignore any v1beta tutorials you find (Merchant API release notes).

Content APIMerchant APIWhat changes
products.insertproductInputs.insertRequires a dataSource query parameter
products.updateproductInputs.patchPersistent update of one product input
products.deleteproductInputs.deleteRequires a dataSource parameter
products.get / listproducts.get / listReturns the processed product, read-only
productstatuses.get / listproducts.get / listStatus is now part of the Product resource
custombatchParallel asynchronous callsNo customBatch method exists
datafeedsdataSourcesEach data source targets one feed label and language

Source: Google's product migration mapping and data source mapping. The conceptual shift is the split between a ProductInput, which is the raw data you write, and a Product, which is the processed result you can only read. A processed product is built from one primary input plus any supplemental inputs after feed rules run (products overview).

Step 4: Create the API data source before you insert anything

This is the step that breaks most first migrations. The Content API created a "Content API" data source automatically on your first insert. Merchant API does not. Google states that you must create at least one data source of type API, and that the Products sub-API can only write to data sources of that type (data source migration).

Each data source now maps to a single combination of feedLabel and contentLanguage. If you served Turkey in Turkish and the UAE in English from one multi-target feed, you now need separate data sources. Create them through the Data Sources sub-API or in Merchant Center, then use the resulting resource name, in the form accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}, on every write.

Step 5: Rewrite the payload, with a worked example

Three field changes cause most of the bugs. Price moves from a decimal string to integer micros, where one million micros is one currency unit. Product attributes move into a productAttributes object. And targetCountry is replaced by feedLabel, while channel disappears.

The old product identifier looked like this, and the new one uses tildes and drops the channel:

Content API:  online:en:US:SKU12345
Merchant API: en~US~SKU12345

A product input that Google's own guide uses as its example looks like this (insert with POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}):

{
  "offerId": "SKU12345",
  "contentLanguage": "en",
  "feedLabel": "US",
  "productAttributes": {
    "title": "Classic Cotton T-Shirt",
    "link": "https://www.example.com/p/SKU12345",
    "imageLink": "https://www.example.com/img/SKU12345.jpg",
    "availability": "IN_STOCK",
    "price": { "amountMicros": "15990000", "currencyCode": "USD" },
    "condition": "NEW",
    "gtins": ["9780007350896"]
  }
}

Compare that with the old shape: "price": {"value": "15.99", "currency": "USD"} becomes amountMicros and currencyCode, and availability becomes an enum, so in stock becomes IN_STOCK. Source: Google's add and manage products guide.

For Turkish lira, 1,249.90 TRY is "amountMicros": "1249900000". Compute micros with integer arithmetic on the minor unit, not by multiplying a float, or you will ship 1249899999 and wonder why prices differ by a hair.

Also use the new versionNumber field when several jobs write the same product. It prevents an older update from overwriting a newer one when requests arrive out of order.

Step 6: Replace batching and read status from the product

There is no customBatch. Replace it with parallel asynchronous requests and cap your concurrency, then retry only the failures. Keep a per-offer result log so a partial failure does not silently become a stale catalog.

For status, stop calling productstatuses. Read the processed Product instead, which carries its status. Google notes there can be a delay of a few minutes between an insert or update and the final product becoming available, so a read immediately after a write is not a test of failure.

Step 7: Verify before you switch off the old path

Run the new path against a small, low-risk slice first, such as 50 products in one feed label. Then score the cutover using this checklist. Every line should be a yes before you retire the old caller.

  • The caller authenticates against the project you registered, and returns no 410 for seven consecutive days.
  • An API data source exists for each feed label and language pair you serve.
  • For the test slice, the processed product matches your source of truth on price, availability and link.
  • Nothing else still writes the same offer IDs from the old data source.
  • Failed offers are logged with a retry, not dropped.
  • The vendor-managed callers on your register all have a written migration confirmation.

The fourth item deserves attention. A second writer for the same offer ID, for example the old caller and a new API data source, is how you get conflicting values. Decide which source owns each product and remove the other.

Where this guide breaks down

We wrote this from Google's published documentation and have not migrated your codebase. Several things sit outside it. Google does not state extension eligibility, so we cannot tell you whether a given project will be approved. The product overview does not document timing beyond "a few minutes", so any stricter latency expectation is yours to measure. Local inventory, regional inventory, promotions and reviews each have their own Merchant API sub-resources, and we have not covered their mappings here.

If you do not want to own an API integration at all, a managed feed platform is the better answer than a rewrite. Productsup and Feedonomics both publish Merchant API migration guidance, and for an enterprise team with unusual data models either may fit better than our setup does. For Google Shopping specifically, our own setup is described on the Google Merchant Center integration page.

Frequently asked questions

Is the Content API for Shopping still working?

Not reliably. Google states it was sunset on August 18, 2026, that requests without an active extension began intermittently failing with HTTP 410 from September 1, 2026, and that all endpoints shut down in early 2027.

What does the Content API 410 error say?

The message begins "Content API for Shopping was sunset on August 18, 2026". The response includes your GCP project ID, project number and a help-center link, which tells you which project to migrate or extend.

Can I get more time with an extension?

Google provides a Content API extension request form. Approved extensions protect your project from the scheduled errors for the approved window only, and they do not go past the early 2027 decommissioning.

Why does productInputs.insert ask for a dataSource?

Merchant API writes belong to an explicit data source. Unlike the old API, it does not create a "Content API" data source on your first insert, so you must create an API-type data source and pass its resource name.

How do I send prices in Merchant API?

Use amountMicros as an integer string and currencyCode in ISO 4217 form. One million micros equals one currency unit, so 15.99 USD is 15990000.

Does Merchant API support batching?

There is no customBatch method. Google's guidance is to use asynchronous parallel calls, which means you should add your own concurrency limit and per-offer retries.

Where did productstatuses go?

Status is part of the processed Product resource now. Use products.get or products.list to read it, remembering that processing can lag an insert by a few minutes.

Which Merchant API version should I build on?

Build on v1, which reached general availability in July 2025. The v1beta version was sunset on February 28, 2026, so tutorials written against it will fail.

Check what Google actually sees

After the migration, the fastest sanity check is to compare your source feed with what Merchant Center processed. Run your live feed through our free product feed audit tool to get a completeness and quality score, and fix whatever it flags before the next ad cycle.

Prev Article
Rule-Based vs AI Product Titles: Which One Your Feed Needs

Related to this topic:

Schedule your 15-minute demo now

Schedule my demo

We’ll tailor your demo to your immediate needs and answer all your questions. Get ready to see how it works!