Skip to content

API reference

Integrations can use the Shopware Admin API to manage landing pages and generation rules, start generation runs and read their reports. This chapter describes the plugin's interfaces for Shopware 6.7.

Access and conventions

Create an integration with the required permissions under Settings → System → Integrations in Shopware. Exchange its access key ID and secret access key for an OAuth token:

http
POST /api/oauth/token
Content-Type: application/json
Accept: application/json

{
  "grant_type": "client_credentials",
  "client_id": "<access-key-id>",
  "client_secret": "<secret-access-key>"
}

Use access_token from the response as a bearer token and observe its validity in expires_in. See the Shopware authentication documentation for details.

The following headers apply to all subsequent Admin API requests. sw-language-id is optional and selects the language for translated fields:

http
Authorization: Bearer <access-token>
Content-Type: application/json
Accept: application/json
sw-language-id: <language-id>
  • All paths are relative to the shop's base URL, for example https://shop.example.com.
  • Replace placeholders in angle brackets and path parameters such as {id}. Entity IDs are UUIDs represented as 32 hexadecimal characters without hyphens.
  • The examples use Accept: application/json. Entity searches return a data list; detail requests return an object under data. With application/vnd.api+json, Shopware uses a different representation with attributes and relationships.
  • Plugin actions return their own JSON objects, such as {"run": {...}} or {"success": true}.
  • When writing translated fields, the system language must be populated. Additional languages can be written through translations, using the language ID as the key.

Permissions and add-ons

Entity access requires the corresponding permissions in the form entity:read, entity:create, entity:update or entity:delete. Technical entity names contain underscores; URL paths contain hyphens. Reading and writing associations also requires permissions for the entities involved, such as translations, categories, properties and sales channels.

The landing page Viewer, Editor, Creator and Deleter roles bundle these permissions in the administration. The following additional ACL permissions are declared on the plugin's action endpoints:

ActionACL permission
Start, start all or cancel generation runsrepertus_landingpage_generation_rule:update
Read worker configurationrepertus_landingpage_generation_run:read
Read available facet valuesrepertus_seo_filter_landingpage.viewer
Regenerate request URLs (generate, generateAll)api_action_cache_index

IAP status, conversion, navigation warnings and category filters currently have no additional _acl permission on their routes. They still require Admin API authentication. The IAP and data checks described below apply independently.

The Landing page generator add-on is required to create or edit generation rules and their child entities, and to start new runs. Reading, cancelling, detaching and deleting remain available without it. Converting to per_sales_channel and editing such landing pages requires the separate Per sales channel configuration add-on. Returning to shared remains possible. See Generator and Per sales channel configuration.

Entity endpoints

The plugin uses Shopware's generic entity endpoints:

DataTechnical entity namePath under /api/
Landing pages including sales channel variantsrepertus_seo_filter_landingpagerepertus-seo-filter-landingpage
Landing page parametersrepertus_seo_filter_landingpage_parameterrepertus-seo-filter-landingpage-parameter
Generation rulesrepertus_landingpage_generation_rulerepertus-landingpage-generation-rule
Facetsrepertus_landingpage_generation_rule_facetrepertus-landingpage-generation-rule-facet
Combination patternsrepertus_landingpage_generation_rule_patternrepertus-landingpage-generation-rule-pattern
Price rangesrepertus_landingpage_generation_rule_price_rangerepertus-landingpage-generation-rule-price-range
Generation runs, read onlyrepertus_landingpage_generation_runrepertus-landingpage-generation-run
Method and pathUsage
POST /api/search/{entity-path}Search with filters, sorting, pagination and associations
GET /api/{entity-path}/{id}Read a single record
POST /api/{entity-path}Create a record
PATCH /api/{entity-path}/{id}Write only the fields to change
DELETE /api/{entity-path}/{id}Delete a record

Successful writes return 204 No Content by default. For POST and PATCH, append ?_response=detail to request the saved record. Shopware explains the basics and association behaviour under Writing entities.

An authenticated GET /api/_info/entity-schema.json returns the full field definitions for the installed plugin. The table above lists the main entities; translation and mapping entities are also included in the schema. The generated Shopware reference provides the general API contract.

Reading and writing landing pages

Search master landing pages

Filtering by parentId: null returns master landing pages only. Without this filter, sales channel variants may appear as separate results. To select only manual or detached pages, add an equals filter for generationRuleId: null.

http
POST /api/search/repertus-seo-filter-landingpage

{
  "page": 1,
  "limit": 25,
  "total-count-mode": 1,
  "filter": [{ "type": "equals", "field": "parentId", "value": null }],
  "sort": [{ "field": "createdAt", "order": "DESC" }],
  "associations": {
    "translations": {},
    "salesChannels": {},
    "properties": {},
    "manufacturers": {},
    "parameters": {},
    "children": {
      "associations": {
        "salesChannel": {},
        "properties": {},
        "manufacturers": {},
        "parameters": {}
      }
    }
  }
}

Create a manual landing page

This example creates an active master landing page in shared configuration mode. Use existing category, property option and sales channel IDs, and a new ID for the landing page. Write this example in the system language; use translations for additional languages.

http
POST /api/repertus-seo-filter-landingpage

{
  "id": "<new-landing-page-id>",
  "name": "Tableware in cream",
  "configurationMode": "shared",
  "enabled": true,
  "robotType": "follow, index",
  "title": "Tableware in cream",
  "metaTitle": "Buy tableware in cream",
  "categoryId": "<category-id>",
  "canonicalForeignKey": "<new-landing-page-id>",
  "salesChannels": [{ "id": "<sales-channel-id>" }],
  "properties": [{ "id": "<property-option-id>" }],
  "parameters": [{ "type": "min-price", "value": "10" }]
}
FieldMeaning
name, robotType, title, metaTitleRequired when creating a master landing page; title and metaTitle are translatable.
categoryId, properties, manufacturers, parametersCategory and complete filter combination. properties references property options; manufacturers references product manufacturers. Parameters consist of type and a string in value, such as max-price / 30 or shipping-free / 1.
salesChannelsSales channel visibility in shared mode.
parentId, salesChannelId, childrenParent-child relationship in per_sales_channel mode; visibility is derived from the sales channel variants.
enabledActivation on the master, also applies to its sales channel variants.
cmsPageId, slotConfigShopping Experience layout and translatable slot configuration.
metaDescription, keywords, description, breadcrumb, ogTitle, ogDescriptionAdditional translatable content.
openGraphMediaId, sitemapPrio, changeFreq, sitemapExclude, useScNavOpen Graph image, sitemap and navigation settings.
canonicalForeignKeyID of the canonical target (seo_url.foreign_key), neither a URL nor a seo_url.id. For a self-reference, use the ID of the landing page carrying the identity.
generationRuleId, generationKeyAssignment of a generated landing page. The generator creates this assignment.

Updates add associations or update the records they contain. Empty properties, salesChannels or parameters arrays do not remove existing assignments. Explicitly delete removed assignments or parameters through the corresponding entity/association endpoints. Include a parameter's existing id when changing it to update that record.

Sales channel variants carry their own complete category and filter combination. categoryId is required, and useScNav: true is not allowed. By default, the Admin API reads raw values without resolving inheritance; empty variant fields therefore do not necessarily mean empty storefront content. Use the conversion actions below for an existing master.

Detach a generated landing page

While generationRuleId is set, content changes through the landing page entity endpoint are blocked. Detaching is a separate write containing only this field:

http
PATCH /api/repertus-seo-filter-landingpage/{id}

{ "generationRuleId": null }

You can then change content in a subsequent request. Detaching preserves the URL, content and generationKey; the generator skips the filter combination while it remains occupied. A DELETE removes the page but does not prevent the rule from creating it again later.

Generation rules

Rules are created and updated through repertus-landingpage-generation-rule. Their main fields and associations are:

FieldContent
name, activeName and activation; inactive rules cannot be started.
minProductCount, maxLandingpageCountMinimum product count and page limit, each at least 1; defaults are 1 and 1000.
salesChannels, languages, categoriesLists of {"id": "…"}. Categories are explicitly assigned; subcategories are not included automatically.
facetstype: manufacturer, property_group or price_range; plus variableName and valueMode (all or explicit). Property facets use propertyGroupId and optionally options; manufacturer facets optionally use manufacturers; price facets use priceRanges.
priceRanges on a facetEach has min, max and a translatable name. At least one bound is required; bounds are non-negative and, when both are present, min < max.
patternsAt least one reference under facets; required translatable fields titleTemplate and metaTitleTemplate, optional metaDescriptionTemplate, breadcrumbTemplate and urlTemplate.
Page settingsOn rules and patterns, including cmsPageId, robotType, sitemapPrio, changeFreq, sitemapExclude, useScNav, openGraphMediaId and translated content with slotConfig. See Generator for inheritance rules.
lastRunId, lastRun, runsLatest run and history; read only. lastRun is an association and must be explicitly requested when reading.

Variable names must be unique within a rule. A pattern may reference only facets from its own rule; two patterns must not use the same set of facets. The generator guide explains configuration and Twig templates.

http
POST /api/search/repertus-landingpage-generation-rule

{
  "ids": ["<rule-id>"],
  "associations": {
    "salesChannels": {},
    "languages": {},
    "categories": {},
    "facets": {
      "associations": {
        "options": {},
        "manufacturers": {},
        "priceRanges": { "associations": { "translations": {} } }
      }
    },
    "patterns": { "associations": { "facets": {}, "translations": {} } },
    "lastRun": {}
  }
}

DELETE /api/repertus-landingpage-generation-rule/{id} deletes the rule and detaches its landing pages. To delete the pages as well, delete the landing pages found by generationRuleId before deleting the rule. End any open runs first. Run history remains without a rule reference until retention cleanup removes it.

Available facet values

http
POST /api/_action/repertus/landingpage-generation-rule/facet-values

{
  "categoryIds": ["<category-id>"],
  "salesChannelIds": ["<sales-channel-id>"]
}

The response contains the union of values occurring in listings across the requested categories and sales channels. Names use the request language and each list is sorted by name:

json
{
  "manufacturers": [{ "id": "<manufacturer-id>", "name": "Example manufacturer" }],
  "propertyGroups": {
    "<property-group-id>": [{ "id": "<property-option-id>", "name": "Cream" }]
  }
}

Lists are empty if no matching values exist; empty propertyGroups is serialised as []. Both input lists contain UUIDs; duplicate IDs are removed. Invalid UUIDs return 400 with TONUR_SEO_FILTER_LANDINGPAGE__INVALID_ID_LIST.

Generation runs

Starting and cancelling

Method and pathBodySuccess
POST /api/_action/repertus/landingpage-generation-rule/{id}/start{} or {"onConflict":"reject"}, {"onConflict":"queue"}, {"onConflict":"restart"}202, run object
POST /api/_action/repertus/landingpage-generation-rule/start-all{}202, created and skipped lists
POST /api/_action/repertus/landingpage-generation-run/{id}/cancel{}200, run object
GET /api/_action/repertus/landingpage-generation-run/worker-confignone200, {"enableAdminWorker":true} or false

A start confirms that the run was queued, not completed. At most one generation run is active globally; others wait in creation order. Processing requires workers.

If a run for the same rule is already pending or running, the default reject returns a conflict. Example, shortened to the relevant fields:

json
{
  "errors": [{ "code": "TONUR_GENERATION_RUN_CONFLICT", "detail": "…" }],
  "run": { "id": "<existing-run-id>", "status": "running" }
}

The response status is 409. queue queues another run; restart requests cancellation of all open runs for this rule and queues a replacement. With start-all, created contains new run objects; each skipped entry contains generationRuleId and the existing run. Rules with an open run are skipped.

Cancelling a queued run immediately changes it to cancelled. An active run may finish its current category before processing cancellation. Pages already written remain; final cleanup is skipped. Cancelling a finished run again does not change its result.

Reading status and history

http
POST /api/search/repertus-landingpage-generation-run

{
  "page": 1,
  "limit": 25,
  "total-count-mode": 1,
  "filter": [{ "type": "equals", "field": "generationRuleId", "value": "<rule-id>" }],
  "sort": [{ "field": "createdAt", "order": "DESC" }]
}

Read an individual run with GET /api/repertus-landingpage-generation-run/{id}. For example, poll every five seconds while its status is pending or running.

FieldMeaning
id, generationRuleIdRun ID and rule reference; the rule reference may become null after deletion.
trigger, userIdmanual for the Admin API, cli for the console, scheduled for the daily task. userId is empty for integrations, CLI and scheduled runs; an admin user is assigned when they start a run manually.
statuspending, running, completed, limit_reached, failed or cancelled. The last four are final statuses.
createdAt, startedAt, finishedAtQueued, started and finished timestamps; start and finish may still be null. createdAt appears in entity read results, not in action run objects.
categoriesProcessed, categoriesTotal, categoriesOpenCategory progress, updated after categories are acknowledged.
minProductCountMinimum product count for this run.
created, updated, deactivated, deleted, skippedFive counters directly on the run, without a nested counters object. Reactivations count as updated.
reasons, reasonsDropped, errorUp to 500 reasons, the number of additional reasons, and an error or cancellation message.
cancelRequestedOnly in run objects returned by start/cancel actions and conflict responses; not a field of the entity endpoint.

reasons distinguishes types including collision, url_collision, no_products, below_threshold and pattern_skipped. Even a completed run may contain skipped combinations. executionState is internal continuation state and is not a stable integration format.

Generation runs are read only: creating, updating, deleting and cloning through the Admin API is blocked, as are writes through the Sync API. A cloned rule starts without run history. Finished runs are removed according to generator log retention; open runs and the latest run of each existing rule are retained.

Additional landing page actions

All paths below start with /api/_action/repertus/seo-filter-landingpage:

Method and path after the prefixInputSuccessful response
GET /iap/statusnone200, boolean fields perSalesChannelEnabled, generatorEnabled, devOverrideActive
POST /{id}/convert-to-per-sales-channelMaster ID; body {}200, {"success":true}; also alreadyConverted: true if the master was already converted
POST /{id}/convert-to-sharedMaster ID; {"chosenVariantId":"<variant-id>"}200, {"success":true}
GET /{id}/nav-tree-warningsMaster ID200, {"warnings":[...]}
POST /generate{"landingpageId":"<landing-page-id>"}200, {"success":true}
POST /generateAll{}204, empty body

Conversion and navigation warnings

convert-to-per-sales-channel copies the identity into one sales channel variant per assigned channel and transfers request URLs. convert-to-shared adopts the chosen variant's identity and removes all variants; channels previously visible through variants become the salesChannels assignments. Use these actions so that URLs and canonical references are transferred as well. Changing only the configurationMode field does not perform these steps.

chosenVariantId must belong to the specified master. Repeating conversion back to shared mode returns 422 because the chosen variant no longer exists. Conversion back does not require an active per sales channel add-on.

Navigation warnings are advisory notices about categories outside a sales channel's navigation tree. Each entry contains variantId, salesChannelId, salesChannelName, categoryId, categoryPath and suggestion. When there are no warnings, warnings is empty.

Request URLs and category filters

generate triggers SEO URL indexing for an existing landing page. generateAll queues an indexing message for all landing pages. These actions do not create new landing pages from generation rules; use the generator's start actions for that.

Handling errors

Errors usually appear in an errors list with code and detail; Shopware may also return status, title and source.pointer identifying an invalid field.

HTTP statusTypical cause
400Invalid UUID, missing chosenVariantId, invalid onConflict, inactive rule or invalid fields/facets/templates.
401Missing, invalid or expired admin token.
403Missing permissions, inactive required IAP or a generated landing page being read only.
404Landing page/master, generation rule or generation run not found.
409An open generation run already exists; inspect the included run in the start action response.
422Invalid sales channel variant or the chosen variant does not belong to the master.