Bulk Payloads

Overview

The Sync API is an add-on to the Admin API that allows you to perform multiple write operations (creating/updating and deleting) simultaneously. All entities that can be written via the Admin API can also be written via the Sync API.

The endpoint is located at

/api/v{version}/_action/sync

and expects payloads via POST and Content-Type: application/json.

Operations

In contrast to the Admin API, the Sync API does not differ between create and update operations, but always performs an upsert operation. During an upsert, the system checks whether the entity already exists in the system and updates it if an ID has been passed, otherwise a new entity is created with this ID.

A request always contains a list of operations. An operation defines the action to be executed (upsert or delete), the entity it is and the payload which is an array of multiple records (for upsert) or multiple IDs (for delete). Within a request, different entities can therefore be written in batch. For easier debugging, each operation can be given a key. The key is then used in the response to define which entities are written in which operation

Format of an operation

Field

Values

entity

Any entity in Shopware, e.g. categoryor customer

action

The type of operation - either upsert or delete

payload

A list, containing objects (upsert) OR a list of IDs (delete)

Writing entities

// POST /api/v3/_action/sync
{
"write-tax": {
"entity": "tax",
"action": "upsert",
"payload": [
{ "name": "tax-1", "taxRate": 16 },
{ "name": "tax-2", "taxRate": 15 }
]
},
"write-category": {
"entity": "category",
"action": "upsert",
"payload": [
{ "name": "category-1" },
{ "name": "category-2" }
]
},
"write-country": {
"entity": "country",
"action": "upsert",
"payload": [
{ "name": "country-1" },
{ "name": "country-2" }
]
}
}
{
"success": true,
"data": {
"write-tax": {
"result": [
{
"entities": {
"tax": ["bd59bcc0ceaa4acbbbb9e5e9d22b0312"]
}
},
{
"entities": {
"tax": ["38bfe5140d58429a840190c6ed43f0c4"]
}
}
]
},
"write-category": {
"result": [
{
"entities": {
"category": ["0a2275ff38a747069fce697bc2582bdc"],
"category_translation": [
{ "categoryId": "0a2275ff38a747069fce697bc2582bdc", "languageId": "2fbb5fe2e29a4d70aa5854ce7ce3e20b" }
]
}
},
{
"entities": {
"category": ["8df6114ba9c84116b6011d6b9ce1fa3a"],
"category_translation": [
{ "categoryId": "8df6114ba9c84116b6011d6b9ce1fa3a", "languageId": "2fbb5fe2e29a4d70aa5854ce7ce3e20b" }
]
}
}
]
},
"write-country": {
"result": [
{
"entities": {
"country": ["91738c2ee74a464e8ffe4f1d572449b3"],
"country_translation": [
{ "countryId": "91738c2ee74a464e8ffe4f1d572449b3", "languageId": "2fbb5fe2e29a4d70aa5854ce7ce3e20b" }
]
}
},
{
"entities": {
"country": ["69b2d17d04364620ad9ded6b01f471cd"],
"country_translation": [
{ "countryId": "69b2d17d04364620ad9ded6b01f471cd", "languageId": "2fbb5fe2e29a4d70aa5854ce7ce3e20b" }
]
}
}
]
}
}
}

Deleting entities

To delete entities, the payload of an operation contains the IDs. If the entity is a MappingEntityDefinition (e.g. product_category) the foreign keys, which are the primary key, must be passed:

// POST /api/v3/_action/sync
{
"delete-tax": {
"entity": "category",
"action": "delete",
"payload": [
{ "id": "1d0943f296a94b06b785dfb4b017c18b" },
{ "id": "046e9574bdae4478b854f49a8f22c275" },
{ "id": "0a5bff83cbdf45968d37d30c31beac69" }
]
},
"delete-product-category": {
"entity": "product_category",
"action": "delete",
"payload": [
{
"productId": "000bba26e2044b98a3ee4a84b03f9551",
"categoryId": "0446a1eb394c4e729178699a7bc2833f"
},
{
"productId": "5deed0c33b2a4866a6b2c88fa215561c",
"categoryId": "0446a1eb394c4e729178699a7bc2833f"
}
]
}
}

Deleting Relations

You can not delete relations by updating the owning entity. Instead you have to delete the relation on the relation entity MappingEntityDefinition (e.g. product_property). The corresponding entries in the main entity (here product) will be updated with an indexer that will immediately run after the delete (for details on indexers, see the next section).

// POST /api/v3/_action/sync
{
"delete-product-property": {
"entity": "product_property",
"action": "delete",
"payload": [
{ "productId": "000bba26e2044b98a3ee4a84b03f9551", "optionId": "0446a1eb394c4e729178699a7bc2833f" },
{ "productId": "5deed0c33b2a4866a6b2c88fa215561c", "optionId": "0446a1eb394c4e729178699a7bc2833f" }
]
}
}

Performance

When using the Sync API, by default each record is written individually. In addition, various indexing processes are also triggered in the background, depending on which data was written.

However, this leads to a high load on the server and can be a problem with large imports. Therefore, it is possible that all data is written in a single transaction and the indexing is moved to an asynchronous process in the background.

You can control the behaviour using the following headers:

Header

Value

Description

single-operation

0 (default)

Data will be written in separate transactions

1

Data will be written in a single transaction

indexing-behavior

null (default)

Data will be indexed synchronously

use-queue-indexing

Data will be indexed asynchronously

disable-indexing

Data indexing is completely disabled

// POST /api/v3/_action/sync
// --header 'single-operation: 1'
// --header 'indexing-behavior: use-queue-indexing'
{
"write-tax": {
"entity": "tax",
"action": "upsert",
"payload": [
{ "name": "tax-1", "taxRate": 16 },
{ "name": "tax-2", "taxRate": 15 }
]
},
"write-category": {
"entity": "category",
"action": "upsert",
"payload": [
{ "name": "category-1" },
{ "name": "category-2" }
]
},
"write-country": {
"entity": "country",
"action": "upsert",
"payload": [
{ "name": "country-1" },
{ "name": "country-2" }
]
}
}