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

Shopware Sdk Laravel Package

vin-sw/shopware-sdk

A PHP SDK for Shopware 6 APIs, offering object-oriented access to the Admin API (CRUD, Sync, User Config, Notification, Search) plus webhook registration, authentication, and receiver helpers. Compatible with Shopware 6.5+ on SDK 2.x.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin the right major version first. The SDK major version tracks the Shopware schema, not the SDK's own feature set:

composer require vin-sw/shopware-sdk
SDK Shopware
2.x >= 6.5 (2.2.0 adds 6.6.10 compatibility)
1.x 6.4

Requirements are ext-curl and PHP >= 7.4. For a Laravel app on Shopware 6.5/6.6, use 2.x and pin with a caret constraint in composer.json — the DAL entity classes are generated from the Shopware schema, so a minor bump can change property names.

There is no Laravel service provider. You wire it yourself. Add a config/shopware.php with url, client_id, client_secret, and register a scoped binding in AppServiceProvider:

$this->app->scoped(Context::class, function () {
    $grant = new ClientCredentialsGrantType(
        config('shopware.client_id'),
        config('shopware.client_secret'),
    );

    $token = (new AdminAuthenticator($grant, config('shopware.url')))->fetchAccessToken();

    return new Context(config('shopware.url'), $token);
});

Where to look first: the examples/ folder is the real documentation — authentication.php, entity-repository.php, sync-service.php, info-service.php, custom-entity.php. Then src/Data/Entity (one Definition/Entity/Collection trio per Shopware entity) and src/Service. The README's screenshots are just these examples rendered.

First use case — read a product:

$repo = RepositoryFactory::create(ProductDefinition::ENTITY_NAME);

$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('shippingFree', true));
$criteria->addAssociation('manufacturer');
$criteria->setLimit(50);

$products = $repo->search($criteria, $context);

If you already know Shopware's DAL from writing admin plugins, the API is deliberately identical — that's the whole value proposition. If you don't, budget an afternoon reading Shopware's DAL docs; the SDK mirrors them rather than inventing its own abstraction.

Implementation Patterns

Token handling is your job, not the SDK's. fetchAccessToken() hits the network every call. Store the token per shop (cache or DB column with expires_in) and only re-auth on expiry or 401. This is the single biggest performance and reliability decision in the integration.

Multi-tenant: one Context per shop. In a Laravel app connecting to several Shopware instances, resolve the context from a Shop model rather than a global singleton:

final class ShopwareContextFactory
{
    public function forShop(Shop $shop): Context
    {
        $token = Cache::remember("sw:token:{$shop->id}", 540, fn () => (new AdminAuthenticator(
            new ClientCredentialsGrantType($shop->client_id, $shop->client_secret),
            $shop->url,
        ))->fetchAccessToken());

        return new Context($shop->url, $token);
    }
}

Repositories cover the whole CRUD surface: get, search, searchIds, create, update, delete, syncDeleted, createVersion, mergeVersion, deleteVersion, clone, schema, plus aggregate (2.2.0). searchIds is the cheap path when you only need IDs — pair it with a batched get.

Use partial loading on wide entities. Products and orders have huge payloads; Criteria::addFields() (2.2.0) plus explicit addAssociation() keeps responses small and avoids the memory blowups that show up in the issue tracker on large searches.

Bulk work goes through SyncService, not loops of create. Build a SyncPayload per entity and send in batches. Since 2.2.0 the payload accepts criteria, and syncDeleted uses the same HTTP client as the repository, so a custom client or middleware applies uniformly.

Services are the day-to-day shortcuts — each takes Context as its first argument:

  • InfoService — cheapest possible health check; wire it into a scheduled Artisan command to detect dead shops before a queue fills with failures.
  • StateMachineService — order state transitions without hand-rolling /state-machine/state/transition.
  • MediaService — product image uploads.
  • NotificationService — push admin toasts after an external job finishes.
  • AdminSearchService — one request across multiple entities, ideal for a global admin search box.
  • AdminActionService — the escape hatch. Any endpoint without a concrete class goes through here; wrap it in your own typed client so call sites stay readable.

Webhooks slot into two Laravel routes. Registration returns an object you persist; confirmation verifies the secret against the raw request body:

public function confirm(Request $request, ShopRepository $shops): Response
{
    $shop = $shops->findByShopId($request->input('shopId'));

    if (! WebhookAuthenticator::authenticatePostRequest($shop->secret)) {
        return response(null, 401);
    }

    $shops->updateAccessKeys($shop->id, $request->input('apiKey'), $request->input('secretKey'));

    return response()->noContent();
}

Action-button endpoints return PSR-7 responses (EmptyResponse, ReloadDataResponse, NotificationResponse, OpenModalResponse). Bridge them to Laravel with symfony/psr-http-message-bridge, or read the status/headers off the object and build a response() manually — the latter is less machinery for four classes.

Queue everything that writes. Sync payloads, media uploads, and notification pushes are network-bound and belong in jobs with retries and backoff, so a Shopware hiccup doesn't take down a user request.

Gotchas and Tips

  • Criteria::getPage() returns null when unset. This was a bug fix in 2.4.0, so code written against 2.3 may assume an int. Type-hint accordingly.
  • Searching is not streaming. Every search() materialises a collection. For exports, page with setPage()/setLimit() and process in chunks; the "Allowed memory size exhausted" issue fixed in 2.2.0 shows what happens otherwise.
  • Associations are opt-in and per-type. An entity property returning null usually means a missing addAssociation(), not missing data. Entities with two associations of the same type were broken until 2.2.0 — upgrade if you hit it.
  • ShopUnreachableException exists (2.2.0) but nothing retries for you. Catch it at the job level and back off; a timeout on a 5-second default will happen in production.
  • searchIds can throw ShopwareSearchResponseException (fixed in 1.7.2 for not throwing). Catch it and log the Shopware error payload — API-level errors are frequently field-level validation on filters, not outages.
  • Custom entities need registration. You provide your own Definition/Entity/Collection and follow examples/custom-entity.php. A CustomDefinition not found error means the definition wasn't registered; fixed structurally in 2.2.0 but still requires your class.
  • Webhook signatures need the raw body. $request->all() after Laravel has parsed the JSON will not verify. Read $request->getContent() and don't add middleware that consumes the stream before your route.
  • Version compatibility is a hard dependency, not a suggestion. Shopware 6.6 renamed and added fields; running 1.x against 6.5 "works" but silently drops new schema. Match major versions explicitly and treat a Shopware upgrade as an SDK upgrade task.
  • Extension points: swap the HTTP client via the repository/AdminAuthenticator constructors to inject logging or metrics; use RepositoryFactory with custom definitions for bespoke entities; use AdminActionService for endpoints the SDK hasn't covered yet (the README has an open TODO list).
  • Vendor risk is real. 119 stars, zero dependents, single maintainer, and the Laravel adapter (Shape-and-Shift/shopware-laravel-sdk) targets Laravel 8. Keep the SDK behind your own thin repository/service interfaces so a fork or raw-HTTP fallback is a contained change, not a rewrite.
  • Debugging: log the raw response body before the SDK hydrates entities. Type errors from Data/Entity classes almost always trace back to a schema mismatch between your SDK version and the shop's Shopware version, not to bad data.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core