Merchant API in Google Ads Scripts: Apr 22 Migration
Google Ads Scripts gain Merchant API support April 22, 2026. Content API sunsets August 18. Script-by-script port guide with before/after code diffs.
Rollout Date
Sunset Date
Migration Window
Sub-APIs
Key Takeaways
On April 9, 2026 the Google Ads Developer Blog announced that the Merchant API will be available in Google Ads Scripts starting April 22, 2026, shipped as an Advanced API. In the same announcement Google confirmed the hard sunset of the Content API for Shopping on August 18, 2026. That gives every agency running Shopping scripts approximately four months to rewrite every feed, inventory, promotions, and reviews script they own.
This post is the script-by-script port guide. It covers the semantic changes you will hit (resource names, micros, URL format), the sub-API priority order Google itself recommends, before-and-after Apps Script diffs for the four most common script shapes, the shadow-mode validation recipe, and a 90-day rollout calendar calibrated for a typical agency portfolio. If you want the broader strategic context on programmatic Google Ads in 2026, pair this with the Google Ads API v23.1 + April 2026 core update playbook.
Silent failure mode: when the Content API is retired, poorly-written scripts do not throw — they return empty result sets. Pending bids, broken ads, stale inventory. Migrating before end of July 2026 leaves a two-week cushion for exactly this class of bug.
Two Dates That Matter
Ships as an Advanced API in the Google Ads Scripts editor. Requires linking the script project to a Google Cloud project and registering that project with your Merchant Center account. After enablement, the new service is importable alongside (not instead of) the existing Content API.
Hard retirement. Any Ads Script — or any other integration — still calling Content API endpoints after this date will fail. No grace period. Target end-of-July for completed migrations so you have a two-week buffer for silent regressions.
What's Actually Changing
The Merchant API is not a version bump of the Content API. It is a different surface with a different architecture. Three semantic changes matter most:
| Change | Content API | Merchant API |
|---|---|---|
| URL format | shoppingcontent/v2.1/{merchantId}/products | merchantapi.googleapis.com/products/v1beta/accounts/{account}/products |
| Resource identifier | Numeric ID | Resource name string (accounts/X/products/Y) |
| Price field | price.value (float), price.currency | price.amountMicros (int64), price.currencyCode |
| Architecture | Monolithic | Modular sub-APIs (Products, Inventories, Promotions, ...) |
| Notifications | Poll-based | Push via Notifications API |
Micros gotcha: amountMicros is int64. A product priced $49.99 is now 49990000. Every arithmetic operation in your scripts that divides, sums, or formats prices needs the / 1_000_000 conversion — or it will produce wildly wrong totals.
Sub-API Migration Priority
Google explicitly calls out four sub-APIs as the priority migration targets: Accounts, Products, Data Sources, and Reports. The ranking below extends that to the rest of the Merchant API surface, ordered by typical agency script impact.
| Priority | Sub-API | Typical agency script uses |
|---|---|---|
| 1 | Accounts | Multi-client account listing, sub-account spawning |
| 2 | Products | Feed uploads, SKU sync, attribute overrides |
| 3 | Data Sources | Supplemental feeds, primary feed rotation |
| 4 | Reports | Performance pulls for dashboards and alerts |
| 5 | Inventories (local & regional) | Stock level sync, in-store availability |
| 6 | Promotions | Sale and coupon rollouts |
| 7 | Reviews (product & merchant) | Review feed imports |
| 8 | Notifications | Replace polling with push subscriptions |
| 9 | Shipping Settings | Regional shipping overrides |
| 10 | Conversion Sources | Conversion tracking wiring |
Enabling Merchant API in Ads Scripts
Three-step enablement, done once per script project:
- Link the script project to a Google Cloud project. In the Ads Scripts editor: Project Settings → Google Cloud Platform project → set the project ID. The project needs the Merchant API enabled under APIs & Services.
- Register the Cloud project with Merchant Center. In Merchant Center: Developer settings → register your Cloud project ID. This is the step that actually grants the script permission to call Merchant API on behalf of the merchant account.
- Enable the Merchant API Advanced Service in the Ads Scripts editor. Resources → Advanced Google services → toggle on the Merchant API service(s) you need (Products, Inventories, Promotions, etc.). Each sub-API is a separate toggle.
Once enabled, call the service in-script like any other Apps Script advanced service: MerchantApiProducts.Accounts.Products.list(parent). The namespace mirrors the REST resource hierarchy directly.
Product Script: Before and After
The most common Shopping script pattern is a daily product fetch to feed a reporting sheet. Here is the full before/after for a hypothetical low-stock alerter.
Content API (legacy)
function lowStockAlert_contentApi() {
const merchantId = '123456789';
const products = ShoppingContent.Products.list(merchantId).resources || [];
const alerts = [];
for (const p of products) {
if (p.availability === 'out_of_stock') {
alerts.push({
id: p.id, // numeric ID
title: p.title,
price: parseFloat(p.price.value), // price is a float string
currency: p.price.currency,
});
}
}
Logger.log(`Found ${alerts.length} out-of-stock items.`);
}Merchant API (new)
function lowStockAlert_merchantApi() {
const parent = 'accounts/123456789';
const res = MerchantApiProducts.Accounts.Products.list(parent);
const products = res.products || [];
const alerts = [];
for (const p of products) {
if (p.productStatus?.destinationStatuses?.some(
ds => ds.approvalStatus === 'disapproved' ||
p.availability === 'OUT_OF_STOCK'
)) {
alerts.push({
name: p.name, // resource name
title: p.attributes?.title,
priceDollars: Number(p.price.amountMicros) / 1_000_000, // micros → dollars
currency: p.price.currencyCode,
});
}
}
Logger.log(`Found ${alerts.length} out-of-stock items.`);
}Five things changed: the service namespace, the identifier format (parent is now a resource name), the product shape (many old top-level fields moved into p.attributes), the price arithmetic (divide micros by 1,000,000), and the status enum casing (OUT_OF_STOCK not out_of_stock).
Inventory and Promotions Diffs
Regional inventory update
Content API: Inventory.set with merchant ID, product ID, and region. Merchant API: LocalInventories sub-resource on a product, keyed by store code.
// Content API → Merchant API
// OLD: ShoppingContent.Inventory.set(resource, merchantId, productId)
// NEW:
const name = `accounts/${account}/products/${productId}/localInventories/${storeCode}`;
MerchantApiInventories.Accounts.Products.LocalInventories.insert(
{
storeCode: storeCode,
availability: 'IN_STOCK',
price: { amountMicros: 4999000000, currencyCode: 'USD' },
quantity: 42,
},
`accounts/${account}/products/${productId}`
);Promotion insert
// Content API's promotions are now Merchant API's Promotions sub-API.
MerchantApiPromotions.Accounts.Promotions.insert(
{
promotionId: 'SPRING26',
contentLanguage: 'en',
targetCountry: 'US',
redemptionChannel: ['ONLINE'],
couponValueType: 'PERCENT_OFF',
percentOff: 20,
promotionDisplayDates: { ... },
},
'accounts/123456789'
);The Shadow-Mode Validation Pattern
Never cut over cold. The reliable pattern: run the old script and the new script side-by-side against the same account for two full reporting cycles, write both outputs to a shared sheet, and diff. Promote only after zero unexplained drift.
function shadowMode() {
const legacyRows = lowStockAlert_contentApi_returnRows();
const newRows = lowStockAlert_merchantApi_returnRows();
const sheet = SpreadsheetApp.openById('SHEET_ID').getSheetByName('ShadowDiff');
sheet.appendRow([
new Date(),
legacyRows.length,
newRows.length,
legacyRows.length - newRows.length,
]);
// Alert if |diff| > 2 across a full day
const threshold = 2;
if (Math.abs(legacyRows.length - newRows.length) > threshold) {
MailApp.sendEmail('alerts@agency.com', 'Shadow diff exceeded',
`Legacy: ${legacyRows.length}, New: ${newRows.length}`);
}
}The 90-Day Rollout Calendar
| Window | Work |
|---|---|
| Apr 22 – May 6 | Enable Merchant API in one sandbox Ads Scripts project. Port the lowest-risk Accounts + Products script. |
| May 7 – Jun 7 | Run both scripts in shadow mode. Compare daily. Promote after 14 days of zero drift. |
| Jun 8 – Jul 15 | Port Data Sources, Reports, Inventories, Promotions in that order. Budget a week per script. |
| Jul 16 – Jul 31 | Reviews, Notifications, Shipping, Conversion Sources. Stop all new Content API writes by July 31. |
| Aug 1 – Aug 17 | Contingency buffer. Hunt silent regressions. August 18 the Content API is gone. |
Agency coordination: publish this calendar internally so account teams know when to expect disruption. Talk to our eCommerce solutions team if you need help executing the port at portfolio scale.
Common Pitfalls and Fixes
| Pitfall | Fix |
|---|---|
| Prices off by 6 orders of magnitude | Apply / 1_000_000 to every amountMicros before formatting or math. |
| INVALID_ARGUMENT on product name | Resource name must be accounts/{account}/products/{product} — plain IDs fail. |
| Advanced service not callable | Enable the sub-API in Resources → Advanced services; also enable it in the GCP console. |
| PERMISSION_DENIED | Register the GCP project with Merchant Center Developer settings. |
Enum casing mismatch (out_of_stock vs OUT_OF_STOCK) | Merchant API uses UPPER_SNAKE_CASE for every enum. Update comparisons. |
| Attribute lookup fails | Most former top-level product fields are now inside p.attributes. Rewrite property access. |
Portfolio-Scale Migration Checklist
For agencies with 20+ client accounts on Shopping, these are the moves that keep the migration from spiraling:
- Inventory all Shopping scripts across the portfolio. Build the list before April 22 — if you find it on August 10 you are too late.
- Group by script template. Most agencies run 5-10 canonical script shapes copied across clients. Port once, reuse across accounts.
- Centralize the migration helper. Write one shared Apps Script library with the price-conversion and resource-name helpers; include it in every migrated script.
- Automate the comparison sheet.One sheet per client, same shadow-mode diff formula, auto-email on delta > 2.
- Communicate rollout windows to clients so a week of shadow-mode weirdness doesn't generate escalations.
Conclusion
The Merchant API is a better surface than the Content API. Modular sub-APIs, push notifications, resource-name consistency with the rest of Google Ads API — all genuine improvements. But the migration is real work, and silent failures after August 18, 2026 will cost agencies orders of magnitude more than the port itself. The agencies we see doing it well started in late April. The calendar above is the fastest safe path.
Ship the Merchant API Migration on Schedule
We port Shopping scripts across agency portfolios — from the first sandbox enablement to the August 17 cutover — with shadow-mode validation on every script.
Frequently Asked Questions
Related Guides
More on programmatic Google Ads, Merchant Center, and Shopping automation.