Platforms
Shopware integration with your ERP, PIM and warehouse
Shopware 6 puts no rate limit on its Admin API, limits token requests to 10 in 10 seconds, and retries a failed webhook 3 times in about 7 seconds. We build the integration to your ERP around those rules, your variants and your sales channels, then host and run it.
What Shopware is and who runs it
Shopware is a German e-commerce platform. This page is about Shopware 6. There is a free Community Edition and there are paid plans, with extra features in the Commercial plugin. Shopware runs on your own server or at a hosting partner, and can run headless: your own frontend on the Store API, the standard administration behind it.
Shopware ships often. On October 1, 2026 it released 6.7.15.0 and 6.6.10.28 on the same day; the 6.6 line still gets patches. For an integration the point is that the Admin API has the same structure in both lines, and that the server limits are yours: Shopware sets no request limit of its own on the Admin API.
| Feature | Core | With the Commercial plugin |
|---|---|---|
| Stock | one stock per product |
Multi-Inventory: per warehouse and warehouse group (Beyond plan) |
| Price per customer group or quantity | advanced prices with a rule | same |
| Price per customer | no field of its own | /api/_action/custom-price |
| B2B | customer groups | B2B Components: employees, quotes, order approval |
What connects to Shopware
Shopware owns orders and web customers. Products, prices and stock come from the ERP, the PIM or the warehouse. These are the flows we build as part of an e-commerce ERP integration:
| Flow | Direction | In Shopware |
|---|---|---|
| Products and variants | to Shopware | product through /api/_action/sync |
| Stock | to Shopware | product.stock |
| Prices and quantity breaks | to Shopware | price and advanced prices with a rule |
| Orders and customers | to the ERP | POST /api/search/order with a filter |
| Status and shipping | to Shopware | state transitions on order, transaction or delivery |
An order has three states side by side: the order itself, the payment (transaction) and the delivery. Each has its own state machine, and a transition that is not defined in it is refused. The integration marks a delivery as shipped by calling a transition, not by overwriting a field. Order status mapping covers how statuses translate between systems.
How Shopware exposes data
Admin API, Store API and authentication
The Store API under /store-api/ serves the customer side: cart, checkout, a headless frontend. The Admin API under /api/ serves everything an integration does: products, orders, customers, bulk writes. Access runs through an integration created under Settings, System, Integrations, which gives an Access key ID and a Secret access key. The integration requests a bearer token with the client_credentials grant:
POST /api/oauth/token
Content-Type: application/json
{ "grant_type": "client_credentials",
"client_id": "<Access key ID>",
"client_secret": "<Secret access key>" }
The response holds the token and its lifetime in expires_in.
The limit is on tokens, not on requests
Shopware's built-in rate limiters protect logins, password resets and forms. One of them matters for an integration:
| Limiter | Protects | Limit |
|---|---|---|
oauth |
Admin API tokens and administration login | 10 per 10 s, 15 per 30 s, 20 per 60 s |
login |
customer login on storefront and Store API | 10 per 10 s, 15 per 30 s, 20 per 60 s |
cart_add_line_item |
adding items to the cart | configurable, per 60 s |
An integration that requests a new token for every call hits the oauth limiter after 10 calls in 10 seconds, and the same limiter then blocks administrators trying to log in. The integration stores the token and reuses it until shortly before expires_in. Beyond that, your server sets the ceiling: the Admin API is as fast as the database and the indexing underneath.
The Sync API
/api/_action/sync takes a list of operations in one request, each with an entity, an action (upsert or delete) and a payload of many records. An upsert with a known id updates the record; without an id, Shopware creates a new one. The integration therefore keeps the Shopware ID per item, or uses a resolver such as {"resolver": "product.number", "value": "10482"} to find a product by its number. After every write Shopware updates its indexes, which is the heavy part of a large import. The header indexing-behavior: use-queue-indexing moves that indexing to the background queue.
Worked through for a full stock and price update of 12,000 variants in batches of 500, a size we tune per store: 12,000 / 500 = 24 requests. With indexing in the request, each batch waits for the index update; with queue indexing, the 24 requests return quickly and the storefront catches up from the queue. Integration throughput has the general arithmetic.
Webhooks
Shopware sends webhooks to apps: an app's manifest names a URL per event, such as checkout.order.placed or product.written. Shopware's own design document of April 14, 2026 describes how delivery works today:
| Today, default | Planned outbox transport |
|---|---|
| 3 retries after 1, 2 and 4 seconds, about 7 seconds in all | retries after 5 s, 30 s, 5 min, 30 min and 4 h |
shared queue with imports, mail and indexing; no ordering, so order.placed can arrive after order.paid |
first attempts in order per app; a retried message can still arrive after newer ones |
| disabled after 10 errors, re-enabled by hand | behind the WEBHOOKS_REWORK flag, off by default |
The error count is shared between webhooks with the same event and URL, so one failing endpoint can switch off webhooks for another app on the same URL. With the admin worker enabled, synchronous delivery has no retry and no log entry at all.
The integration treats a webhook as a signal, not as the source. A reconciliation run searches orders changed since the last successful run, so a missed webhook costs minutes, not an order. Webhooks are not a guarantee explains the pattern.
Where a Shopware integration gets stuck
Variants and inheritance
A variant in Shopware is a product with a parentId. Fields the variant does not set, such as the price, are inherited from the parent. A read without the header sw-inheritance: 1 returns null for those fields. An integration that takes that for empty writes a price on every variant, and from then on a price change on the parent no longer reaches the variants.
Color and size are options from a property group, with an ID per value and per installation: "Blue" has one ID on production and another on staging. Shopware separates options, which define a variant, from properties, which only describe it. An ERP color code that has no option in Shopware yet goes on a review list instead of failing the batch.
Net, gross and the default currency
A price has a net, a gross and linked per currency, and a product without a price in the system default currency is rejected. An ERP usually sends net only, so the integration computes gross: 89.50 net at 19 percent German VAT is 106.505, rounded 106.51; at 21 percent Dutch VAT it is 108.295, rounded 108.30. Which rate applies depends on the tax rule of the product. Money, tax and rounding covers rounding per line and per order.
Quantity breaks and customer group prices hang on a rule from the Rule Builder. For the cheapest price in listings and filters, Shopware considers at most 100 rules that match a customer. With more matching rules the product page still shows the right price, but sorting and the price filter in listings do not.
Visibility per sales channel
A product needs a visibilities entry per sales channel: 10 for link only, 20 for search, 30 for everywhere. Without it, the product exists in the administration and not in the store. The integration sets visibility when it creates a product and leaves it to you afterwards.
One stock number that Shopware also changes
product.stock is one number that Shopware keeps up to date itself: it goes down on an order and up on a cancellation. If the integration writes free stock from the ERP, that number has to account for Shopware orders the ERP has not received yet. The integration subtracts open Shopware orders that are not in the ERP before it writes. See which stock counts.
Systems we integrate with Shopware
Each system stores items, prices and stock in its own way. On the ERP side we connect Shopware to NetSuite, Business Central and Odoo; on the product data side to Akeneo. Other platforms with the same kind of setup: Magento, which also runs on your own server, and Shopify. All flows are listed on integrations.
We build the integration for a fixed price on your Shopware and your systems, then host, run and monitor it for a monthly fee. Before go-live it runs as a dry run: you see per product which price, stock and visibility it would set in Shopware, without changing anything. Tell us which Shopware version and systems you run.
Frequently asked questions
Does the integration work with a headless Shopware storefront?
Yes. A headless frontend runs on the Store API; the integration uses the Admin API. The two are separate, so products, stock and orders go through the same Admin API whether you run the standard storefront or your own frontend.
Which Shopware version does the integration need?
Shopware 6. On October 1, 2026 Shopware released 6.7.15.0 together with a patch for the 6.6 line, 6.6.10.28. The Admin API and the Sync API that the integration uses exist in both lines.
What do we set up in Shopware for the integration?
An integration under Settings, System, Integrations. Shopware shows an Access key ID and a Secret access key; the integration uses them with the client_credentials grant at /api/oauth/token. Give it only the permissions its flows need, and keep it separate from any app.
Can stock per warehouse go to Shopware?
In the core, a product has one stock value. Stock per warehouse and warehouse group comes with Multi-Inventory, part of the Commercial plugin on the Beyond plan. Without it the integration adds up the warehouses that count for the store into one number. See multi-location inventory.
Can customer prices from the ERP go to Shopware?
Prices per customer group and quantity breaks go in as advanced prices with a rule from the Rule Builder. Prices per individual customer go through /api/_action/custom-price in the Commercial plugin; Shopware's documentation says the price filter in product listings does not use those overridden prices. See customer-specific pricing.
Tell us what you need
Tell us which systems you use and what needs to work better. We reply personally within one working day. We help you define the work, then agree the price and timing before you commit.
- You know the price and the timeline before you commit to anything
- We work out the connection that takes the work off your hands
- We handle the build, hosting, monitoring and maintenance
- Your team has less information to retype and fewer discrepancies to chase