Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Google Merchant Api Laravel Package

moirei/laravel-google-merchant-api

Integrate Google Merchant Center into your Laravel app with this API wrapper. Manage merchant accounts, product listings, and feeds using a clean, expressive PHP interface, with Laravel-friendly configuration and service account authentication.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin Laravel-friendly wrapper around Google's Merchant (Content) API for managing Google Shopping product listings. Minimal setup:

composer require moirei/laravel-google-merchant-api
php artisan vendor:publish --tag=google-merchant-api-config

Then add your Google service account credentials and Merchant Center ID to .env:

GOOGLE_MERCHANT_ACCOUNT_ID=123456789
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json

Service accounts must be granted access in the Merchant Center UI (Users → add the service account email as a "Standard" or "Admin" user). Without that step, every API call returns 401 and it can look like a package misconfiguration.

First use case — pushing a single product. Resolve the client from the container and insert a product. Most developers start here to prove credentials work:

use Moirei\GoogleMerchantApi\Facades\Product;

Product::insert([
    'offerId' => 'SKU-001',
    'title' => 'Blue T-shirt',
    'description' => 'A cotton tee',
    'link' => 'https://shop.test/p/1',
    'imageLink' => 'https://shop.test/img/1.jpg',
    'contentLanguage' => 'en',
    'targetCountry' => 'US',
    'channel' => 'online',
    'condition' => 'new',
    'availability' => 'in stock',
    'price' => ['value' => '19.99', 'currency' => 'USD'],
]);

Look first at config/google-merchant-api.php to confirm the credential path and account ID are wired, then check the package's src/ for the facade/resource classes (Product, Products, or similar) — that's the real surface area you will be working with.

Implementation Patterns

Facade for quick scripts, DI for testable services. Use the facade in Artisan commands and one-off scripts. In services and controllers, inject the underlying client or product resource so you can mock it in tests.

Sync from an Eloquent model via observers or an explicit action. Keep the "push to Google" logic in a dedicated class rather than sprinkling it through controllers:

class SyncProductToGoogle
{
    public function __construct(private Products $products) {}

    public function handle(Product $product): void
    {
        $this->products->update([
            'offerId' => $product->sku,
            'title' => $product->name,
            'availability' => $product->stock > 0 ? 'in stock' : 'out of stock',
            'price' => [
                'value' => number_format($product->price, 2, '.', ''),
                'currency' => 'USD',
            ],
            // ...other fields
        ]);
    }
}

Wire it from a model observer's updated event or a queued job so HTTP requests to Google don't block your checkout or admin save.

Bulk operations belong in queues. Google's API is slow and rate-limited. Batch products into a job, chunk with ->chunk(50, ...), and dispatch with a rate limiter (Redis::throttle('merchant-api')->allow(10)->every(1)). Don't loop inside a synchronous controller.

Map to your catalog domain, not Google's schema. Build a toGoogleProduct() mapper per product type (physical, variant, digital). Google's schema is verbose and strict; keeping a single translation seam makes validation errors readable.

Feed-style reconciliation. For large catalogs, use list to pull existing products, diff against local DB, and issue insert / update / delete only where needed. A last_synced_at column on your product model plus a google_status field makes this a cheap check.

Testing. Fake the client by binding a mock of the resource interface into the container in your test's setUp. Assert on the payloads passed to insert/update rather than hitting Google. Keep a small fixture file for response snapshots.

Gotchas and Tips

  • Credential path resolution. A relative GOOGLE_APPLICATION_CREDENTIALS is resolved from the process working directory — which is base_path() under Artisan/web but may differ under Octane, Sail, or containerized workers. Use absolute paths or base_path() inside config.
  • Product IDs are compound. Google identifies products as contentLanguage~targetCountry~offerId. When you update or delete, you need to reconstruct this — the package usually handles it, but keep contentLanguage and targetCountry stable or you'll orphan products.
  • Account ID vs. sub-account. merchantId at the top level targets the multi-client account. Most single-store setups need the sub-account ID. Verify in Merchant Center → Settings.
  • Field validation is server-side and strict. Errors surface as Google\Service\Exception (or GuzzleHttp\Exception\RequestException). Log $e->getMessage() and the decoded body — Google returns field-level paths (item[0].price.value) that tell you exactly what's wrong.
  • Onerous required fields. channel, contentLanguage, targetCountry, condition, availability, price, shipping, tax — miss one and the product is silently "pending" or rejected. Enable Google Merchant Center diagnostics in the UI alongside API responses.
  • Auth token caching. The google/apiclient dependency caches OAuth tokens in memory per request. In long-running workers (Horizon, Octane), recreate the client occasionally or inject a fresh one per job to avoid stale token errors.
  • Rate limits. Default quotas are ~15 QPS per method with burst limits; large syncs will hit 403 rateLimitExceeded. Back off with exponential retry (retry(5) on the job) and throttle the dispatch.
  • Debugging HTTP. Add logging to the config (or enable Guzzle debug via handler) to dump request/response bodies; Google's errors are opaque without the raw payload.
  • Extension points. The package typically exposes the underlying Google\Client and service resources via the container. Override the binding in a service provider to swap in a custom Client — useful for proxies, retries, or stubbing in tests.
  • Don't commit the service account JSON. Add it to .gitignore, store in a secret manager, and reference via env. Rotating the key requires clearing any cached tokens.
  • Zero dependents score is a signal. With few users, expect thinner docs and fewer StackOverflow answers. Read src/ and the package tests; treat the vendor code as the source of truth for method signatures rather than blog posts.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums