Agentic Commerce

Migrating from Content API to Merchant API v1: The Complete Developer Guide for 2026

Soumyadeep MukherjeeSoumyadeep MukherjeeFebruary 5, 202628 min read
Migrating from Content API to Merchant API v1: The Complete Developer Guide for 2026

Google announced it will shut down the Content API for Shopping on August 18, 2026. If your integration still sends product data through Content API endpoints, every product listing, every Shopping campaign, and every data pipeline you depend on will break on that date. The Merchant API v1beta version sunsets even sooner -- February 28, 2026 -- meaning developers who adopted the beta must migrate again within weeks.

This is not a cosmetic rename. According to Dataslayer.ai, the Merchant API is a complete rebuild created to support the demands of modern e-commerce. The two-resource model, new data structures, and mandatory GCP registration represent fundamental architectural changes that require careful planning.

At Ekamoira, we have already completed this migration and built our production Commerce Feed Optimizer on Merchant API v1. This guide shares the battle-tested patterns, undocumented gotchas, and real code examples from that implementation -- the kind of practical knowledge you will not find in official documentation alone.

What You'll Learn

  • The two critical deadlines and what breaks if you miss them

  • Why GCP registration is the silent migration killer (and how to fix it)

  • The two-resource model shift from single resource to ProductInput (write) vs Product (read-only)

  • Before/after code examples for every major structural change

  • When to use productInputs.patch vs supplemental data sources

  • AI-generated content disclosure requirements (structured_title and digital_source_type)

  • A complete migration checklist with rollback strategy

  • Rate limits, quota management, and error handling patterns

Summary: Key migration facts at a glance

Metric

Value

Source

Content API sunset date

August 18, 2026

Search Engine Land, 2025

v1beta sunset date

February 28, 2026

Google Merchant API Latest Updates, 2025

Max product updates per day

2 per product

Google Quotas & Limits, 2026

Max sub-account updates per day

1 per sub-account

Google Quotas & Limits, 2026

GTINs per product

Up to 10 (array)

ProductAttributes Reference

Complex migration timeline

16-20 weeks (4-5 months)

ALMcorp, 2026

Official code samples

Java, Python, PHP

Google merchant-api-samples, 2025

Migration Timeline - Key Deadlines

What are the migration deadlines and what happens if you miss them?

There are two distinct deadlines that developers must understand. Each applies to a different starting point, and missing either one has the same catastrophic result: your campaigns stop serving and your product data pipelines break.

Deadline 1: February 28, 2026 -- v1beta sunset. According to Google's latest updates page, the v1beta version of the Merchant API is scheduled for discontinuation on February 28, 2026. All API calls must be directed to v1 and v1alpha versions before this deadline. If you adopted the Merchant API early using v1beta endpoints, you must migrate again to v1.

Deadline 2: August 18, 2026 -- Content API for Shopping sunset. According to Search Engine Land, Google announced it will shut down the Content API for Shopping on August 18, 2026. After this date, the Content API will stop functioning entirely. This is the hard cutoff for all developers still using the legacy API.

Watch Out: According to ALMcorp's migration guide, campaigns relying on product data fed through the old API may stop serving after the cutoff dates. This is not a gradual degradation -- it is an immediate stop.

The business context makes this migration even more urgent. The agentic commerce ecosystem depends on structured, API-accessible product data. AI shopping agents need reliable programmatic access to your product catalog, and Merchant API v1 is the foundation that makes this possible. Merchant API v1 also serves as the data layer for the Universal Commerce Protocol, enabling AI agents to browse and purchase your products autonomously.

According to ALMcorp, high-complexity merchants should plan for 16-20 weeks (4-5 months) for a complete migration. That means if you have a complex setup and you start today (February 2026), you are cutting it dangerously close to the August deadline.

Key Finding: Two deadlines, not one: v1beta sunsets February 28, 2026, and Content API sunsets August 18, 2026. Both result in broken product listings and stalled data pipelines if missed. -- Google Merchant API Latest Updates and ALMcorp

Why is GCP registration the number one undocumented gotcha?

This is the single most painful step in the migration, not because it is difficult, but because it is invisible when missing. API calls fail silently without GCP registration. You will get empty results or cryptic errors, and nothing in the error messages points you toward the actual problem. Developers routinely waste hours debugging this.

According to Google's migration overview, you must create a link between your Google Cloud project and your primary Merchant Center account before any v1 methods will work. The GCP registration samples provide code that demonstrates the developerRegistration:registerGcp endpoint.

Here is what you need to know:

  • One-time registration per Google Cloud project. You only do this once, but you must do it before any other API call.

  • Admin privileges required. The person performing the registration needs admin access on the Merchant Center account.

  • Developer email restrictions. The email address used in registration must be a Gmail or Google Workspace account. Service account emails will not work.

  • Invitation flow. If the developer email does not already have access to the Merchant Center account, an invitation is sent that must be accepted.

Here is a TypeScript example for GCP registration based on the patterns from Ekamoira's production implementation:

// Step 0: Register GCP - MUST be done before any other Merchant API call
// This creates the link between your Google Cloud project and Merchant Center

async function registerGcp(merchantId: string, developerEmail: string) {
  const url = `https://merchantapi.googleapis.com/accounts/v1beta/accounts/${merchantId}/developerRegistration:registerGcp`;

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      // Developer email MUST be Gmail or Google Workspace
      // Service account emails will NOT work here
      gcpServiceAccountEmail: developerEmail,
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    // Common error: 403 = not admin on Merchant Center account
    // Common error: 400 = email is a service account, not Gmail/Workspace
    throw new Error(
      `GCP Registration failed: ${error.error?.message || response.statusText}. ` +
      `Ensure the email is Gmail/Workspace and you have admin access.`
    );
  }

  console.log('GCP Registration successful. You can now use Merchant API v1.');
  return response.json();
}

Pro Tip: Run GCP registration as the very first step of your migration. Add a startup check in your application that verifies registration status before making any product API calls. At Ekamoira, we built this check into our Commerce Feed Optimizer initialization sequence so that new merchant connections never hit the silent failure state.

What is the two-resource model and why does it matter?

The most fundamental conceptual change in Merchant API v1 is the shift from a single resource to a two-resource model. In Content API for Shopping, you had one products resource that handled both reading and writing product data. In Merchant API v1, this splits into two distinct resources.

ProductInput is the write resource. It represents the raw data you submit to Google. When you call productInputs.insert or productInputs.patch, you are writing to this resource. Think of it as your submission layer.

Product is the read-only resource. It represents the final processed result after Google applies its rules, policies, and any supplemental data source merges. When you call products.get or products.list, you are reading from this processed layer.

According to Google's add and manage products guide, after inserting, updating, or deleting a product input, it may take several minutes before the processed product can be retrieved. This processing delay is critical for testing and workflow design.

Aspect

Content API (Legacy)

Merchant API v1

Write resource

products.insert

productInputs.insert

Read resource

products.get

products.get (read-only)

Partial update

products.update

productInputs.patch + updateMask

Data source

Implicit

Explicit dataSource parameter required

Processing

Synchronous-like

Asynchronous (several minutes delay)

Attributes

Product.attributes (top-level)

Product.productAttributes (nested)

Watch Out: The processing delay between writing a ProductInput and reading the processed Product is measured in minutes, not milliseconds. Do not write automated tests that insert a product and immediately try to read it -- the product will not exist yet. Build polling or callback patterns into your test harness.

This two-resource model exists because Google now separates your input data from its processed output. This separation allows Google to apply policy rules, merge supplemental feeds, and validate data without modifying your original submission. Merchant API v1 is a traditional REST API -- if you are building AI agent integrations and want to understand how it compares to protocol-based approaches, see our guide on traditional REST APIs vs MCP.

How do data structures change from Content API to Merchant API v1?

The structural changes in Merchant API v1 will break every existing Content API integration that is not updated. Here are the key transformations with before/after code examples.

productAttributes nesting

In Content API, product attributes lived at the top level of the product object. In Merchant API v1, according to the migration overview, the Product.attributes field has been renamed to Product.productAttributes, and all attribute fields must be nested inside this object.

// BEFORE: Content API for Shopping - attributes at top level
const contentApiProduct = {
  offerId: 'SKU-12345',
  title: 'Premium Running Shoes',
  description: 'Lightweight performance running shoes',
  link: 'https://example.com/products/running-shoes',
  imageLink: 'https://example.com/images/running-shoes.jpg',
  price: {
    value: '129.99',
    currency: 'USD',
  },
  availability: 'in_stock',
  condition: 'new',
  brand: 'RunFast',
  gtin: '0195937087654',  // single value
  channel: 'online',
};

// AFTER: Merchant API v1 - attributes nested in productAttributes
const merchantApiProduct = {
  name: `accounts/${merchantId}/productInputs/online~en~US~SKU-12345`,
  offerId: 'SKU-12345',
  feedLabel: 'US',
  contentLanguage: 'en',
  productAttributes: {
    title: 'Premium Running Shoes',
    description: 'Lightweight performance running shoes',
    link: 'https://example.com/products/running-shoes',
    imageLink: 'https://example.com/images/running-shoes.jpg',
    price: {
      amountMicros: '129990000',  // $129.99 in micros
      currencyCode: 'USD',
    },
    availability: 'in_stock',
    condition: 'new',
    brand: 'RunFast',
    gtins: ['0195937087654'],  // array, not single value
    // channel removed -- use legacyLocal boolean instead
  },
};

Price format changes

The price format is one of the most common sources of runtime errors during migration. Content API accepted a simple {value, currency} object. Merchant API v1 requires {amountMicros, currencyCode} where amountMicros is an int64 string representing the price in millionths of the currency unit.

// Price conversion utility for migration
function convertPriceToMicros(value: string, currency: string) {
  // Content API: { value: "29.99", currency: "USD" }
  // Merchant API v1: { amountMicros: "29990000", currencyCode: "USD" }
  const micros = Math.round(parseFloat(value) * 1_000_000);
  return {
    amountMicros: micros.toString(),
    currencyCode: currency,
  };
}

// Usage:
const legacyPrice = { value: '129.99', currency: 'USD' };
const v1Price = convertPriceToMicros(legacyPrice.value, legacyPrice.currency);
// Result: { amountMicros: "129990000", currencyCode: "USD" }

GTIN changes

According to the v1beta to v1 migration guide, the gtin field has been renamed to gtins to better reflect that it can hold multiple values. The ProductAttributes reference confirms you can provide up to 10 GTINs per product.

Other structural changes

According to the v1beta to v1 migration guide:

  • taxes and taxCategory fields removed from productAttributes -- tax configuration is now handled at the account level

  • channel field removed -- replaced with a legacyLocal boolean for products sold in physical stores

TL;DR:

  • Nest all attributes inside productAttributes

  • Convert prices to amountMicros (int64 string) + currencyCode

  • Change gtin (string) to gtins (string array, up to 10)

  • Remove channel, use legacyLocal boolean for physical stores

  • Remove taxes and taxCategory from product-level attributes

How do you insert a product in Merchant API v1?

The productInputs.insert method is the Merchant API v1 replacement for Content API's products.insert. According to Google's add and manage products guide, the insert method requires you to provide the name of your primary data source as the dataSource parameter. The required attributes are feedLabel, contentLanguage, and offerId.

// Inserting a product via Merchant API v1
async function insertProduct(
  merchantId: string,
  dataSourceId: string,
  product: MerchantApiProduct
) {
  // dataSource is a REQUIRED query parameter -- Content API did not have this
  const dataSource = `accounts/${merchantId}/dataSources/${dataSourceId}`;
  const url = `https://merchantapi.googleapis.com/products/v1/accounts/${merchantId}/productInputs:insert?dataSource=${encodeURIComponent(dataSource)}`;

  const body = {
    offerId: product.offerId,
    feedLabel: product.feedLabel,       // e.g., "US"
    contentLanguage: product.contentLanguage, // e.g., "en"
    productAttributes: {
      title: product.title,
      description: product.description,
      link: product.link,
      imageLink: product.imageLink,
      price: {
        amountMicros: product.priceMicros,
        currencyCode: product.currencyCode,
      },
      availability: product.availability,
      condition: product.condition,
      brand: product.brand,
      gtins: product.gtins,
    },
  };

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Product insert failed: ${JSON.stringify(error)}`);
  }

  // IMPORTANT: The product is NOT immediately available for reading.
  // It may take several minutes before the processed Product appears.
  const result = await response.json();
  console.log(`ProductInput created: ${result.name}`);
  return result;
}

Key Finding: Every write operation in Merchant API v1 requires an explicit dataSource parameter. This is the single biggest difference from Content API, where the data source was implicit. If you forget this parameter, the API will reject your request immediately. -- Google Add and Manage Products

When should you use productInputs.patch vs supplemental data sources?

Merchant API v1 gives you two distinct approaches for updating product data. Choosing the wrong one can lead to data loss, rate limit exhaustion, or policy violations. Understanding when to use each approach is critical for a successful migration.

productInputs.patch: Direct partial updates

According to Google's frequent updates guide, the productInputs.patch method lets you make partial updates to existing products. You specify which fields to modify using the updateMask parameter -- a comma-separated list of field paths.

According to Google's quotas and limits documentation, you can only update your products up to twice per day. This is a hard limit that cannot be increased.

// Patching a product - update specific fields only
async function patchProduct(
  merchantId: string,
  dataSourceId: string,
  productName: string,
  updates: Partial<ProductAttributes>,
  updateMask: string[]
) {
  const dataSource = `accounts/${merchantId}/dataSources/${dataSourceId}`;
  const url = `https://merchantapi.googleapis.com/products/v1/${productName}:patch?dataSource=${encodeURIComponent(dataSource)}&updateMask=${updateMask.join(',')}`;

  const body = {
    productAttributes: updates,
  };

  const response = await fetch(url, {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Product patch failed: ${JSON.stringify(error)}`);
  }

  return response.json();
}

// Example: Update price and availability only
await patchProduct(
  merchantId,
  dataSourceId,
  `accounts/${merchantId}/productInputs/online~en~US~SKU-12345`,
  {
    price: { amountMicros: '139990000', currencyCode: 'USD' },
    availability: 'out_of_stock',
  },
  ['productAttributes.price', 'productAttributes.availability']
);

Supplemental data sources: Non-destructive enrichments

Supplemental data sources let you layer additional data on top of a merchant's primary feed without modifying the original. This is the approach Ekamoira's Commerce Feed Optimizer uses for AI-driven enrichments because it preserves the merchant's original data and prevents accidental overwrites.

// Step 1: Create a supplemental data source
async function createSupplementalDataSource(
  merchantId: string,
  displayName: string
) {
  const url = `https://merchantapi.googleapis.com/datasources/v1/accounts/${merchantId}/dataSources`;

  const body = {
    displayName: displayName,
    // Supplemental sources merge with primary source data
    supplementalProductDataSource: {
      feedLabel: 'US',
      contentLanguage: 'en',
    },
  };

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  if (!response.ok) {
    throw new Error(`Failed to create supplemental data source`);
  }

  const result = await response.json();
  console.log(`Supplemental source created: ${result.name}`);
  return result;
}

// Step 2: Insert enrichment via supplemental source
// This adds/overrides specific fields WITHOUT touching the primary feed
async function insertEnrichment(
  merchantId: string,
  supplementalDataSourceId: string,
  offerId: string,
  enrichments: Partial<ProductAttributes>
) {
  const dataSource = `accounts/${merchantId}/dataSources/${supplementalDataSourceId}`;
  const url = `https://merchantapi.googleapis.com/products/v1/accounts/${merchantId}/productInputs:insert?dataSource=${encodeURIComponent(dataSource)}`;

  const body = {
    offerId: offerId,
    feedLabel: 'US',
    contentLanguage: 'en',
    productAttributes: enrichments,
  };

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  return response.json();
}

This supplemental data source approach is the foundation of policy-first AI feed optimization, ensuring your AI-driven enrichments do not trigger Google suspensions by keeping them separate from the merchant's original product data.

Decision framework: Patch vs supplemental

Factor

Use productInputs.patch

Use Supplemental Data Source

Ownership

You own the primary feed

Merchant owns the primary feed

Update frequency

Infrequent (2/day limit)

Batch enrichments, no per-product limit

Data safety

Acceptable to overwrite

Must preserve original data

Use case

Price/availability updates

Title optimization, description enrichment

Rollback

Manual revert required

Delete supplemental source to revert

AI enrichments

Not recommended

Recommended -- non-destructive

Pro Tip: At Ekamoira, we use supplemental data sources for all AI-generated enrichments (optimized titles, enhanced descriptions, additional product attributes). This way, if an enrichment causes a policy issue, we can remove it without affecting the merchant's original product data. The patch method is reserved for merchant-initiated changes like price and availability updates.

How do you handle AI-generated content in Merchant API v1?

Google requires specific attribution for AI-generated product content. According to Google Merchant Center Help, titles created using generative AI must use the structured_title attribute with the digital_source_type set to trained_algorithmic_media. This requirement applies whether you use Google's own Product Studio or a third-party AI tool.

// Submitting AI-generated titles with required disclosure
const aiEnrichedProduct = {
  offerId: 'SKU-12345',
  feedLabel: 'US',
  contentLanguage: 'en',
  productAttributes: {
    // Standard title still required as fallback
    title: 'Running Shoes - Premium Lightweight',

    // AI-generated title with required disclosure
    structuredTitle: {
      digitalSourceType: 'trained_algorithmic_media',
      content: 'RunFast Premium Lightweight Running Shoes for Marathon Training - Breathable Mesh, Carbon Plate, Size 10',
    },

    // AI-generated description (same pattern)
    structuredDescription: {
      digitalSourceType: 'trained_algorithmic_media',
      content: 'Engineered for marathon distance with breathable mesh upper, carbon fiber plate for energy return, and responsive foam midsole. Available in 8 colorways.',
    },
  },
};

Watch Out: If you are using AI to optimize product titles or descriptions -- whether through your own models, Ekamoira's Commerce Feed Optimizer, or Google's Product Studio -- you must include the digital_source_type disclosure. Failing to do so risks policy violations that could lead to product disapprovals or account suspensions.

According to Google's Product Studio documentation, Product Studio is a suite of generative-AI tools that simplifies merchant workflows including generating SEO-optimized titles for products. The Product Studio Text API is currently in a controlled alpha launch and requires allowlist access and a Google Cloud project.

How do you check product status and diagnose issues?

After submitting products through Merchant API v1, you need to monitor their approval status. According to Google's product issues guide, the itemLevelIssues array contains data validation and policy issues found for each product. You can query the ProductView table to filter products by their approval status.

// Check product status and identify issues
async function getProductStatus(merchantId: string, productName: string) {
  const url = `https://merchantapi.googleapis.com/products/v1/${productName}`;

  const response = await fetch(url, {
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to get product: ${response.statusText}`);
  }

  const product = await response.json();

  // Check for issues
  if (product.productStatus?.itemLevelIssues?.length > 0) {
    for (const issue of product.productStatus.itemLevelIssues) {
      console.log(`Issue: ${issue.code}`);
      console.log(`Description: ${issue.description}`);
      console.log(`Severity: ${issue.severity}`);
      // severity: DISAPPROVED means the product cannot serve ads
      if (issue.severity === 'DISAPPROVED') {
        console.error(`CRITICAL: Product ${productName} is disapproved.`);
      }
    }
  }

  return product;
}

// Filter disapproved products across your catalog using ProductView
async function listDisapprovedProducts(merchantId: string) {
  const url = `https://merchantapi.googleapis.com/reports/v1/accounts/${merchantId}/reports:search`;

  const body = {
    query: `
      SELECT
        product_view.id,
        product_view.title,
        product_view.aggregated_reporting_context_status
      FROM ProductView
      WHERE aggregated_reporting_context_status = 'NOT_ELIGIBLE_OR_DISAPPROVED'
    `,
  };

  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${await getAccessToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  return response.json();
}

Pro Tip: Build automated monitoring that runs the disapproved products query daily. At Ekamoira, our Commerce Feed Optimizer checks itemLevelIssues after every enrichment cycle and automatically rolls back any AI-generated content that triggers policy disapprovals -- this is a core part of our policy-first architecture.

What are the rate limits and how do you manage quotas?

Merchant API v1 introduces a dynamic quota system that differs significantly from Content API's static limits. According to Google's quotas and limits documentation, the Merchant API automatically adjusts call quotas for your products and accounts based on your usage patterns.

Key limits confirmed in the documentation:

  • Maximum 2 updates per product per day -- this is a hard limit

  • Maximum 1 update per sub-account per day -- critical for MCA setups

  • Each request counts once, regardless of its type or items returned

  • Dynamic adjustment -- the system increases or decreases your quota based on usage patterns

When you exceed quotas, the API returns specific error codes:

  • quota/request_rate_too_high -- you are making requests too quickly

  • quota/daily_limit_exceeded -- you have hit your daily maximum

// Rate-limit-aware product update with exponential backoff
async function rateLimitedUpdate(
  merchantId: string,
  dataSourceId: string,
  updates: ProductUpdate[],
  maxConcurrent: number = 5
) {
  const results: UpdateResult[] = [];

  // Process in batches to respect rate limits
  for (let i = 0; i < updates.length; i += maxConcurrent) {
    const batch = updates.slice(i, i + maxConcurrent);

    const batchResults = await Promise.allSettled(
      batch.map(async (update) => {
        let retries = 0;
        const maxRetries = 3;

        while (retries < maxRetries) {
          try {
            return await patchProduct(
              merchantId,
              dataSourceId,
              update.productName,
              update.attributes,
              update.updateMask
            );
          } catch (error: any) {
            if (error.message.includes('quota/request_rate_too_high')) {
              retries++;
              // Exponential backoff: 1s, 2s, 4s
              const delay = Math.pow(2, retries) * 1000;
              console.log(`Rate limited. Retrying in ${delay}ms...`);
              await new Promise(resolve => setTimeout(resolve, delay));
            } else if (error.message.includes('quota/daily_limit_exceeded')) {
              throw new Error(
                `Daily quota exceeded for ${update.productName}. ` +
                `Max 2 updates per product per day.`
              );
            } else {
              throw error;
            }
          }
        }
        throw new Error(`Max retries exceeded for ${update.productName}`);
      })
    );

    results.push(...batchResults);

    // Pause between batches to avoid rate limiting
    if (i + maxConcurrent < updates.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }

  return results;
}

Quota Limits Comparison

What does a complete migration checklist look like?

Based on Ekamoira's production migration experience and the patterns documented in the Google migration overview and v1beta to v1 migration guide, here is a comprehensive step-by-step checklist. Google confirms that you can migrate in stages, updating one API at a time.

Phase 1: Preparation (Week 1-2)

  1. Audit your existing Content API integration. Document every endpoint you use, every product attribute you send, and every batch operation you perform. Map these to their Merchant API v1 equivalents.

  2. Complete GCP registration. Call developerRegistration:registerGcp with a Gmail or Google Workspace email. Verify admin access on the Merchant Center account first.

  3. Identify your data source IDs. Merchant API v1 requires explicit data source parameters for every write operation. Find your primary data source ID in Merchant Center.

  4. Set up a test environment. Create a sandbox Merchant Center account or use a limited product subset for testing.

Phase 2: Code migration (Week 3-8)

  1. Update authentication. Ensure your OAuth2 scopes include https://www.googleapis.com/auth/content (same scope, new endpoints).

  2. Migrate product insert logic. Replace products.insert with productInputs.insert. Add the dataSource parameter. Nest all attributes inside productAttributes.

  3. Convert price format. Replace {value, currency} with {amountMicros, currencyCode}. Build and test the conversion utility.

  4. Update GTIN handling. Change gtin (string) to gtins (string array).

  5. Remove deprecated fields. Delete channel, taxes, and taxCategory from product-level attributes. Use legacyLocal for physical store products.

  6. Migrate update logic. Replace products.update with productInputs.patch using updateMask. Respect the 2-updates-per-product-per-day limit.

  7. Add processing delay handling. Build polling or retry logic to handle the several-minute delay between write and read.

Phase 3: Testing and validation (Week 9-12)

  1. Test with a small product set. Insert 10-20 products through the new API. Wait for processing, then verify they appear correctly.

  2. Validate product status. Check itemLevelIssues for every test product. Confirm no new disapprovals compared to Content API.

  3. Run parallel operations. Send the same products through both Content API and Merchant API v1. Compare results to ensure parity.

  4. Test error handling. Deliberately trigger rate limits and quota errors to verify your retry logic works.

Phase 4: Cutover and monitoring (Week 13-16+)

  1. Switch production traffic gradually. Route 10%, then 50%, then 100% of your product updates through Merchant API v1.

  2. Monitor for errors. Watch for quota/request_rate_too_high and disapproval spikes.

  3. Keep Content API as fallback. Maintain your Content API integration until well past the switchover. Only decommission it once Merchant API v1 is proven stable in production.

  4. Document rollback triggers. Define specific error thresholds that trigger a rollback to Content API (e.g., disapproval rate exceeding 5%, processing delay exceeding 30 minutes).

Key Finding: According to ALMcorp, high-complexity merchants should plan for 16-20 weeks total. Simpler integrations may complete in less time, but do not underestimate the testing and validation phases.

What common errors will you encounter and how do you fix them?

Based on Ekamoira's production implementation and the verified documentation, here are the most common errors and their solutions:

Error

Root Cause

Fix

Empty API response / no data

GCP registration not completed

Run developerRegistration:registerGcp first

productAttributes not found

Attributes not nested correctly

Move all attributes inside productAttributes object

Invalid price format

Using {value, currency} instead of {amountMicros, currencyCode}

Convert to micros (multiply by 1,000,000)

quota/request_rate_too_high

Too many concurrent requests

Add exponential backoff, reduce concurrency

quota/daily_limit_exceeded

More than 2 updates/product/day

Batch updates, prioritize which products need updates

Product not found after insert

Processing delay (several minutes)

Wait and poll, do not read immediately after write

Missing dataSource parameter

Forgot to include in API call

Add dataSource query parameter to every write call

GTIN validation error

Sending single string instead of array

Change gtin: "value" to gtins: ["value"]

Tax-related errors

taxes / taxCategory in product attributes

Remove from product level, configure at account level

Watch Out: The silent failure from missing GCP registration is the most dangerous error because it does not produce a clear error message. If your API calls return empty results or generic authentication errors after migrating to v1, check GCP registration first. This saved us hours of debugging at Ekamoira.

Frequently asked questions

When exactly does Content API for Shopping shut down?

According to Search Engine Land, Google announced it will shut down the Content API for Shopping on August 18, 2026. After this date, the API will stop functioning entirely, and any integrations still using it will break. This deadline is non-negotiable and affects all developers and platforms using Content API endpoints.

What happens if I do not migrate by the deadline?

According to ALMcorp, campaigns relying on product data fed through the old API may stop serving after the cutoff dates. Your product listings will become stale, data pipelines will break, and Shopping campaigns will stop delivering. There is no grace period after August 18, 2026.

Do I need a new Google Cloud project for Merchant API v1?

No. You can use your existing Google Cloud project. However, you must perform a one-time GCP registration to link that project to your Merchant Center account. This step is required before any Merchant API v1 calls will work, according to the Google migration overview.

Can I use both Content API and Merchant API v1 during the migration?

Yes. Google supports running both APIs simultaneously during the transition period. According to the v1beta to v1 migration guide, you can migrate in stages, updating one API at a time. This allows you to test Merchant API v1 while keeping Content API as a fallback.

What is the difference between ProductInput and Product?

ProductInput is the write resource where you submit your raw product data. Product is the read-only resource that represents the final processed result after Google applies rules, policies, and supplemental data source merges. According to Google's add and manage products guide, it may take several minutes after writing a ProductInput before the processed Product can be retrieved.

How long does GCP registration take?

The API call itself completes in seconds. However, the overall process -- ensuring admin access, using the correct email type (Gmail or Google Workspace, not service account), and accepting any invitations -- can take longer. Plan for 30 minutes to an hour for the entire registration process, including verification.

How do rate limits work in Merchant API v1?

According to Google's quotas and limits documentation, you can update each product a maximum of 2 times per day and each sub-account a maximum of 1 time per day. The system dynamically adjusts overall call quotas based on your usage patterns. Each request counts once, regardless of its type.

Do I need to migrate if I use Feedonomics, DataFeedWatch, or GoDataFeed?

According to ALMcorp, if you use feed management platforms, contact their support teams. Many platforms are handling the migration on their end, but you should verify directly with your provider and understand their timeline to ensure coverage before the deadline.

How do I handle AI-generated product titles in Merchant API v1?

According to Google Merchant Center Help, titles created using generative AI must use the structured_title attribute with the digital_source_type set to trained_algorithmic_media. The same pattern applies to AI-generated descriptions using the structured_description attribute.

Where can I find official code examples?

Google maintains a Merchant API samples repository on GitHub with code examples in Java, Python, and PHP. The repository also includes migration assistance tools. For TypeScript/JavaScript examples, Ekamoira's Commerce Feed Optimizer implementation serves as a production reference.

What is the dataSource parameter and why is it required?

The dataSource parameter tells Merchant API v1 which data source (primary or supplemental) should receive your product data. According to Google's add and manage products guide, the productInputs.insert method requires you to provide the name of your data source. Content API did not have this concept -- it was an implicit single source.

How do I handle multi-client accounts (MCA)?

MCA setups require passing both the merchantId (sub-account) and aggregatorId (parent account) parameters. The API response structure also differs for MCA accounts. Test your MCA handling thoroughly during migration, as the parameter naming conventions have changed from Content API.

What happens to the channel field?

According to the v1beta to v1 migration guide, the channel field has been removed from Merchant API v1. It is replaced by a legacyLocal boolean for products sold in physical stores. Online-only products do not need this field at all.

Can I roll back to Content API if migration fails?

Yes, during the transition period (before August 18, 2026). Keep your Content API integration code and data pipelines intact until Merchant API v1 is verified in production. Define specific rollback triggers such as disapproval rate spikes or processing timeout patterns. After the August deadline, rollback is no longer possible.

How does Ekamoira's Commerce Feed Optimizer use Merchant API v1?

Ekamoira's Commerce Feed Optimizer is a production system built entirely on Merchant API v1. It uses supplemental data sources for non-destructive AI enrichments, productInputs.patch for merchant-initiated updates, and automated itemLevelIssues monitoring to prevent policy violations. The optimizer completed the full migration and serves as a battle-tested reference implementation.

Sources

  1. Search Engine Land (2025). "Google replaces Content API for Shopping with new Merchant API." https://searchengineland.com/google-content-api-shopping-new-merchant-api-460937

  2. Google for Developers (2025). "Migrate from Content API for Shopping to Merchant API." https://developers.google.com/merchant/api/guides/compatibility/overview

  3. Google for Developers (2025). "Latest updates | Merchant API." https://developers.google.com/merchant/api/latest-updates

  4. Google for Developers (2025). "Migrate from v1beta to v1 | Merchant API." https://developers.google.com/merchant/api/guides/compatibility/migrate-v1beta-v1

  5. Google for Developers (2025). "Register GCP | Merchant API." https://developers.google.com/merchant/api/samples/register-gcp

  6. Google for Developers (2026). "Add and manage products | Merchant API." https://developers.google.com/merchant/api/guides/products/add-manage

  7. Google for Developers (2025). "Make frequent updates to your products | Merchant API." https://developers.google.com/merchant/api/guides/products/frequent-updates

  8. Google for Developers (2026). "Quotas and limits | Merchant API." https://developers.google.com/merchant/api/guides/quotas-limits

  9. Dataslayer.ai (2025). "Google Merchant API Migration: Key Changes, Deadlines, and How to Prepare." https://www.dataslayer.ai/blog/new-google-merchant-api

  10. ALMcorp (2026). "Google Shopping API Migration Deadline: February 28 & August 18, 2026 Guide." https://almcorp.com/blog/google-shopping-api-migration-deadline-2026/

  11. Google for Developers (2025). "ProductAttributes | Merchant API." https://developers.google.com/merchant/api/reference/rest/products_v1/ProductAttributes

  12. Google Merchant Center Help (2025). "AI-generated content." https://support.google.com/merchants/answer/14743464

  13. Google for Developers (2025). "How to Use the Product Studio Text API." https://developers.google.com/product-studio/docs/onboarding

  14. Google (2025). "Merchant API Samples Repository." https://github.com/google/merchant-api-samples

  15. Google for Developers (2025). "List your products data and product issues | Merchant API." https://developers.google.com/merchant/api/guides/products/list-products-data-issues


Ready to optimize your product feeds on Merchant API v1?

Ekamoira's Commerce Feed Optimizer is built on Merchant API v1 with supplemental data sources, policy-first AI enrichments, and automated issue monitoring. Skip the migration pain -- we have already done it. Start Free

Once your Merchant API integration is live, explore our protocol comparison to decide whether to adopt UCP, MCP, or A2A for your agentic commerce strategy.

Share:

About the Author

Soumyadeep Mukherjee

Co-founder of Ekamoira. Building AI-powered SEO tools to help brands achieve visibility in the age of generative search.

AI SEO Weekly

Stay Ahead of AI Search

Join 2,400+ SEO professionals getting weekly insights on AI citations.

  • Weekly AI SEO insights
  • New citation opportunities
  • Platform algorithm updates
  • Exclusive case studies

No spam. Unsubscribe anytime.

Ekamoira Research Lab
88%

of brands invisible in AI

Our proprietary Query Fan-Out Formula predicts exactly which content AI will cite. Get visible in your topic cluster within 30 days.

Free 15-min strategy session · No commitment

Keep Reading

Related Articles