Skip to content

Multi-Repricer — User Guide

This guide explains the Multi Repricer UI (/multi-repricer) from a user perspective: what each tab does, how prices are decided, what gets skipped automatically, and how to interpret statuses and errors.

For API details, see the endpoint reference. Cron “what happens for this SKU?” scenarios: Cron walkthrough examples. Latest FBM/FBA / force-recalc behavior: Patch 1.10.4.


Open Services → Multi Repricer in the sidebar.

Tab Purpose
Overview Short feature summary (Otto & Kaufland focused)
Base Articles Master data from Plenty: SKU, buy price, stock, package, UVP, platform chips
Otto Otto.de scraping, repricing, category provision, proxies
Kaufland Kaufland API sync, min/max export per storefront
Shopify Recalculate + export to Shopify (via Plenty)
FBM Amazon FBM via Sellerlogic + SP-API fees
FBA Amazon FBA via Sellerlogic + SP-API fees, multi-marketplace

Background jobs (top-right on every tab): colored dots per platform for sync, recalc, and export. Hover for details. Long tasks also push live updates over WebSocket.

Deep links: URL ?platform=otto&sku=YOUR-SKU (or kaufland, shopify, fbm, fba, base) opens the right tab with SKU pre-filled. Platform chips on Base Articles jump to the matching channel.


Core concepts

Base article vs channel details

Every product starts as a base article (Plenty SKU, name, stock, buy price, package type/cost, weight).

Each marketplace adds a channel detail record:

Chip Channel Detail stores
S Shopify Price, expected profit, margin rule
K Kaufland Min/max, listing price, storefront, fees
O Otto Min/max, site price, provision %, buybox
F FBM Seller SKU, international min/max (DE + more)
A FBA Seller SKU, ASIN, international min/max per country

Grey chip = channel not configured. Colored chip = configured — click to open that channel with the SKU filter.

Buy price (EK)

The buy price on the base article comes from the latest shopping table row (preis_pro_einheit_b), matched by:

  1. Base SKU, or
  2. FBA ASIN if SKU does not match

If no row exists and no buy price was ever set → all channels go to Error (shopping_table entry missing).

Package cost

Derived from Package Mappings (CSV by GTIN first, else weight → package type + cost). Types: XS, S, M, L1, L2, L3, L5, XL. 1:1 bundles share one package (any peer EAN for CSV, else max peer weight). CSV NO-BOX is ignored (falls through to weight / default S). Configure under Base Articles → Package Mappings (Cost mappings / CSV upload / SFTP). See Patch 1.8.20 and Patch 1.11.0.

Margin rules

Shared across Otto, Kaufland, Shopify, FBM, and FBA (Configuration sub-tab on each channel).

Rules are tiered by buy price:

  • At each buy-price breakpoint you set min margin %, max margin %, min profit (min bound), min profit (max bound).
  • Between breakpoints values are interpolated linearly.
  • Below the lowest / above the highest buy price, the nearest rule applies.

The repricer uses these targets plus Amazon/Otto/Kaufland fee data to compute min and max selling prices.

UVP (fixed price bounds)

Set per SKU from Base Articles → UVP icon:

  • Min UVP / Max UVP override dynamic min/max on selected channels.
  • UVP stays until you Remove UVP.
  • UVP articles are excluded from buy-price force recalc (buy price still updates; classification penner/renner is preserved).
  • UVP copies only to 1:1 bundle peers (parent child_skus ↔ alias bundle_packages qty 1). Gift sets and value packs are not updated. See Patch 1.11.2.

Article type (Penner / Renner / Neutral)

Classification on the base article. Buy-price force recalc clears article_type so the article is treated as unclassified again (except UVP articles).

See Example A — Penner, new buy price today.

Sales & profit statistics

On Base Articles and each marketplace articles tab, open the chart icon in the row Actions column. A dialog loads fee-aware KPIs for that SKU only (default last 7 days; switch to 14 / 30 inside the dialog).

In dialog Meaning
KPI cards Sales qty, retour rate, period profit, gross revenue, avg sell/buy
Bar charts Sales vs returns (quantity and gross €)
Pie / bar (Base) Breakdown by channel when viewing all channels

How numbers are built (short):

  1. Load order/retour lines in the Berlin date window from Omni tables (plenty_orders, plenty_retours, amazon_orders, amazon_returns).
  2. Map Plenty origin → channel (otto / kaufland / shopify / fbm / other); Amazon SP-API rows → always fba.
  3. For each sale line, prefer stored profit / brutto_buy_price from Omni enrich; else compute unit profit with that channel’s fee stack × quantity.
  4. For each return line, reverse estimated sale profit and add return-handling costs; Otto SPA ads may reduce period profit on Otto/Base.
  5. Aggregate KPIs; Base also returns by_channel. On Analysis, expand Main rows for consumer-bundle breakdown.

Full formulas, field definitions, matching rules, and caveats: Article sales & profit statistics.
Import pipeline (buy/fee/profit): Profit imports.


Article statuses

Shown as colored chips in every channel table (filter: ACTIVE, UPDATE_NEEDED, ERROR, OOS, PAUSED).

Status Color (typical) Meaning
ACTIVE Green Healthy; prices current or manually held
UPDATE_NEEDED Orange New prices calculated; export pending
ERROR Red Calculation or export blocked — read error message in expanded row
OOS Grey Out of stock — most automated repricing/monitoring skipped
PAUSED Blue Otto only — excluded from automatic price monitoring

How stock affects status

  • Stock = 0 → channel details move to OOS (unless Paused on Otto).
  • Stock > 0 and was OOS → usually becomes Active again.
  • UPDATE_NEEDED is preserved when stock changes (export still pending).
  • Base cron may reset Error to Active on “perfect” SKUs that synced cleanly (stock > 0).

Scheduled jobs (cron)

Cron is configured inside each channel’s Articles tab, not in global Settings.

Location Default schedule What it runs
Base Articles Often 0 8 * * * (08:00 Berlin) Full sync → recalc all channels → export (optional)
Otto Articles Configurable Optional Otto API sync → recalc → price monitor (scrape + push)
Kaufland Articles Configurable Kaufland sync → recalc → send min/max
Shopify Articles Configurable Recalc → export
FBM / FBA No cron UI Covered by Base Articles cron

Base cron options

  • Update Prices on Remote Platforms — when checked, export runs after recalc (Shopify, Kaufland, FBM, FBA). When unchecked, recalc still runs but prices are not pushed.
  • Discord webhook (optional) — summary after base job completes.

FBM / FBA recalc (since 1.10.4): the base cron runs full SP-API min/max for rules-on Amazon rows every night. Wave/manual stays profit-only on that pass. When shopping-table buy price (or package) changes, a second force pass includes penner/renner and rewrites FBM/FBA bounds via SP-API; UVP stays excluded. Expect longer SP-API traffic on force nights.

See Cron walkthrough examples below for step-by-step scenarios.

Otto cron options

  • Sync with Otto API before monitoring — refresh Otto metadata before scrape pass.
  • Discord webhook — monitoring summary.

Active cron shows Cron: ON (expression) and Next: run time.


Cron walkthrough examples

These assume the Base Articles cron runs once (typical morning job) with optional “Update prices” export at the end.

Example A — Penner, new buy price today

Setup: SKU is article_type=penner, channel use_min_max_rules=False (wave bounds from n8n), no UVP. Shopping table has a newer EK than brutto_buy_price.

Step What happens
1. Sync Plenty / channel / bundle sync as usual
2. Buy-price sync New EK written to the article; SKU marked changed
3. Force-SKU pick Penner is included (UVP would be skipped). article_type cleared → null
4. Main recalc Shopify / Kaufland / Otto / FBM / FBA without force_min_max. Wave → profit-only (penner min/max kept). Rules-on FBM/FBA → full SP-API
5. Force pass force_min_max=True on all channels. Shopify / Kaufland / Otto rewrite min/max (Otto may push max as sale). FBM / FBA full SP-API rewrites wave bounds
6. Export If enabled, pushes UPDATE_NEEDED rows

Net: new EK applied → type cleared → force rewrites channel bounds (incl. Amazon) → optional export. n8n can re-tag penner/renner on a later wave.

Example B — Penner, buy price unchanged

Setup: Same penner/wave SKU; shopping-table EK matches brutto_buy_price.

Step What happens
Buy-price sync No change → SKU not in force list
Main recalc Wave → profit-only on all channels; FBM/FBA do not call SP-API for new min/max
Force pass Skipped for this SKU

Net: wave targets stay; only profit/margin refresh. No nightly wipe of penner bounds.

Example C — Rules-on FBM/FBA, no EK change

Setup: use_min_max_rules=True, no UVP, buy price unchanged.

Step What happens
Main recalc Full SP-API min/max every night (empty shells and existing targets)
Force pass Skipped

Net: Amazon rules-based bounds refresh every cron run even without an EK change.

Example D — UVP article, new buy price

Setup: min_uvp / max_uvp set; shopping table has a newer EK.

Step What happens
Buy-price sync EK still updates on the base article
Force-SKU pick Excluded (UVP). article_type (e.g. penner) preserved
Main recalc Profit-only with UVP-pinned bounds; no SP-API rewrite of min/max
Force pass Skipped

Net: buy price updates for reporting/costs; selling bounds stay at UVP until UVP is removed.

Example E — Renner + package cost change (no EK change)

Setup: Package mapping / weight change marks the SKU in package_changed (same force list as buy-price).

Same as Example A from step 3 onward: force pass runs with force_min_max=True, including FBM/FBA SP-API; article_type cleared if it was also in the buy-price changed set — package-only force still goes through force_recalc_channels_for_buy_price_change but does not by itself clear article_type unless the SKU was also buy-price-changed.

(Package-only SKUs are unioned into force_recalc_skus without going through _resolve_buy_price_force_recalc_skus, so article_type is only cleared on shopping-table EK changes.)


Health checks (verification)

To notice problems early (missing details, stale EK sync, suspected stuck exports), the multi-repricer service includes a lightweight audit.

What it checks

The audit focuses on buy-price (EK) freshness because EK changes are a common root cause for “min/max didn’t update” incidents:

  • Missing local: a shopping_table.asin_sku exists but there is no local base article with that SKU.
  • Buy price mismatch: shopping-table EK differs from brutto_buy_price even though the row is old enough that the last base cron should have synced it.
  • Pending next base run: EK row is newer than the last base cron run (expected until tomorrow because base cron runs once a day).
  • FBA stuck UPDATE_NEEDED (heuristic): if the last base run exported prices, but FBA is still UPDATE_NEEDED for “old” EK rows.

Schedule

A cron job called repricer_health_audit runs every 48 hours by default and stores a small JSON report.

Manual run (API)

POST /api/v1/multi/health/audit/buy-price?days=3&max_hours_after_base_run=48

Alerts (webhook)

The audit cron can optionally send a Discord webhook notification when findings are > 0. Configure this in the UI:

  • Base Articles → Health

This stores the webhook URL and audit window in the backend cron job (repricer_health_audit) so it keeps working after restarts.

See the endpoint docs: health.md.

Observability testing (Sentry / Prometheus)

For developers/operators verifying error tracking and metrics:

  • Open Debug → Observability (Sentry / Prometheus) in the sidebar (/debug/observability).
  • Backend tests require JWT (you must be logged in).
  • Sentry only reports when SENTRY_DSN / VITE_SENTRY_DSN are set in the environment.
  • Prometheus test counter: repricer_debug_test_total on GET /metrics.

See Prometheus infrastructure docs.


Base repricer flow (automatic)

When Sync All or the base cron runs:

flowchart LR A[Plenty base sync] --> B[Inbound dates] B --> C[Shopify + FBM prices] C --> D[FBA full Sellerlogic sync] D --> E[Otto sync] E --> F[Buy prices from shopping table] F --> G[Bundle sync] G --> H[Recalc all channels] H --> I{Update prices?} I -->|Yes| J[Export Shopify Kaufland FBM FBA] I -->|No| K[Done]

What “perfect SKU” cleanup does

If a SKU succeeded in base sync, buy-price sync, bundle sync, Shopify sync, and FBM sync and stock > 0:

  • Channel errors cleared → Active
  • UPDATE_NEEDED is not downgraded (export still needed)

SKUs with stock = 0 are not flipped to Active here (OOS kept).

Concrete “what does cron do for this SKU?” scenarios: Cron walkthrough examples.


Skip rules — quick reference

Condition Normal / base cron recalc Export Otto monitor (cron) Otto monitor (manual) Buy-price force recalc
OOS FBA/FBM skipped FBA/FBM: if not ignored Skipped Runs FBA: runs; FBM: skipped
Paused (Otto) Kaufland blocked Skipped* Runs Not blocked
UVP set Profit-only (UVP-pinned bounds); no SP-API rewrite on FBM/FBA Normal Normal Normal Skipped (shopping-table force)
Rules-on FBM/FBA Full SP-API min/max every night / manual recalc (1.10.4+) Full SP-API (same as normal)
Manual / penner / renner (Rules off) Profit refresh only; Recalculate All heals n8n wave min/max from pricing_history (no margin rewrite) Force min/max on all channels incl. FBM/FBA SP-API; clears article_type
Ignore = True (FBA/FBM region) Region still stored Region not exported

*Paused Otto is still monitored when pricing_history.otto has a recent wave entry (today/yesterday Berlin) — see 1.10.2.


Per-channel guide

Base Articles

Actions

Button Effect
Sync All Full pipeline (see flow above)
Update Prices (checkbox) Include export step during sync
Refresh Reload table
Cron Schedule automatic sync
Per row: Sync Sync one SKU
Per row: Recalculate Triggers sync for that SKU (same backend path as Sync All for one article)
UVP Set/remove fixed min/max overrides
Margin rules View rules (edit under channel Configuration)

Filters: SKU, name, platform presence, article type (Penner/Renner/Neutral), advanced numeric filters.


Otto

Workflow: Sync from OttoSync Ads (as needed) → Recalculate AllMonitor All (or cron with monitor).

Action Purpose
Sync from Otto Pull listing metadata from Otto API (+ SPA ads step)
Sync Ads Refresh SPA ad costs / ordered units only (1.8.19+)
Recalculate All Compute min/max from margin rules + provision. Penner/renner: keep n8n wave bounds and restore them from pricing_history if a previous recalc overwrote them.
Monitor All Scrape competitor prices and push to Otto
Monitor (per row) Force monitor for one SKU (bypasses OOS/Paused skips)

SPA ads (since 1.8.19): Otto Partner Connect Sponsored Product Ads spend is synced via the Market SPA reporting API into total_ad_costs / total_ad_sales on each article. Rows with both > 0 show a campaign icon next to the SKU. Open Sales statistics for ad KPIs and profit after attributed ad spend. Requires the Otto app’s advertising-services scope. See article sales stats and Patch 1.8.19.

Missing min/max (since 1.8.10): if either min_price or max_price is empty before recalc, the repricer:

  1. Calculates standard min/max from margin rules + category provision.
  2. Saves them and sets sale_price = max_price.
  3. Pushes max price to Otto and Plenty (Otto channel) immediately — no separate monitor pass needed for that initial listing.

Buy-price change (since 1.8.10): when the base cron detects a new EK in the shopping table (non-UVP SKUs), Otto force recalc:

  1. Recomputes min/max from the new buy price.
  2. Sets sale_price = max_price.
  3. Pushes the new max price to Otto and Plenty immediately.

This runs on the buy-price force-recalc pass — not when the EK is unchanged. UVP articles are excluded.

Requires Otto + Plenty credentials and Plenty article/variant IDs on the base article.

Otto-only statuses

  • Paused — no automatic monitoring until unpause date or low-profit reactivation.
  • Auto-pause: no pricing history for 3+ days → paused 5 days.

Common errors

Message Cause
Missing provision percentage Category not in provision XLSX
Missing buy price No shopping table / base buy price
Missing weight or package type Base article incomplete
HTTP 429 / rate limit Otto blocked scrape — status may stay unchanged, error message set (not always Error)

Configuration: Category Provision (XLSX), Margin Rules, Proxies (Webshare).


Kaufland

Workflow: Sync from KauflandRecalculate AllSend All Min Prices.

Action Purpose
Sync from Kaufland Refresh listing data from API
Send All Min Prices Push min/max to Kaufland + Plenty
Recalculate All Margin min/max for rules-on SKUs; penner/renner healed from pricing_history
Send min prices (row) One SKU / storefront

Storefront filter: DE, AT, SK, PL, CZ, BE, NL.

Export skips Paused articles and items without min/max or id_unit.


Shopify

Workflow: Recalculate AllExport All (no sync button in UI — prices come from Plenty during base sync).

Action Purpose
Recalculate All Compute price from margin rules. Penner/renner: restore n8n wave price from pricing_history.
Export All Push to Shopify via Plenty

Only UPDATE_NEEDED rows export. Plenty rate limits may defer export — status stays UPDATE_NEEDED with SHOPIFY_EXPORT_DEFERRED:…; automatic retry every hour.


FBM (Amazon FBM)

Credentials: Plenty, Amazon SP-API, Sellerlogic.

Workflow: Sync AllRecalculate AllExport All.

Action Purpose
Sync All Variation SKUs + Sellerlogic data
Recalculate All Rules-on: full SP-API min/max per country; penner/renner/UVP: profit-only (heal wave from history)
Export All Min/max to Sellerlogic (DE default)

Seller SKU

  • FBM recalc calls Amazon SP-API getMyFeesEstimatesForSku using FBMDetails.seller_sku (not the base Plenty SKU unless they match).
  • seller_sku is filled by FBM Sync All from Plenty variation SKUs on marketId 4 (Amazon DE), including additional SKUs when present.

Ignore column / switch

  • Per marketplace Ignore = True → dimmed row, region excluded from export.
  • Export All pushes every FBM row that is not ignored (ignore false/null) and has valid min/max — not only UPDATE_NEEDED.
  • Explicit Ignore = True is the only ignore skip (unless UVP force export).

OOS: Recalc skipped; Export All still includes non-ignored OOS rows that have min/max.

Stale errors after fix: A successful Sync, Recalculate, or Export clears both error_message and per-country error fields in international_pricing. If seller SKU changes on sync, old bounds/errors are dropped and status becomes UPDATE_NEEDED until you recalculate.

Error: No ASIN found for SKU: …

Where it appears

  • FBM table: status chip ERROR (red).
  • Expanded row → FBM ConfigError: full message, e.g.
    No ASIN found for SKU: EmporioArmaniPowerOfYouEdP30ml2er. Please make sure the SKU is valid.
  • International Pricing shows for all countries (min/max never calculated).
  • Use Min/Max Rules may still be Yes — the failure is Amazon lookup, not the margin-rule toggle.

What it means

Amazon SP-API could not map the seller SKU to a catalog ASIN. Fee estimation stops immediately (no retries). Typical causes:

Cause Explanation
No Amazon listing SKU exists in Plenty / the dashboard but there is no active FBM offer on Amazon for that seller SKU.
Wrong seller SKU seller_sku does not match Seller Central / Sellerlogic (e.g. base bundle SKU vs actual Amazon SKU).
Listing inactive Offer deleted, suppressed, or stuck in incomplete state — Amazon has no ASIN for that SKU.
Bundle parent SKU Plenty bundle parent SKU (bundle_type: bundle) is synced, but Amazon only lists a child or different variation SKU.
Stale sync Listing was created on Amazon after the last FBM sync; seller_sku still empty or outdated.
Parentheses SKU Seller Central has SKU(2) but SP-API was sent SKU%282%29 via force_safe_sku (fixed 1.10.4 — redeploy multi-repricer).

How to fix

  1. Seller Central — confirm an active FBM listing exists for the SKU shown in Seller SKU on the expanded row.
  2. Sellerlogic — search that SKU; product should appear with an ASIN. If missing, the listing is not in the repricer pipeline yet.
  3. FBM → Sync All — refresh seller_sku from Plenty (marketId 4). For bundles, check whether the Amazon SKU is an additional variation SKU, not the parent bundle SKU.
  4. If the correct Amazon SKU differs — update Plenty variation SKUs or edit Seller SKU on the FBM detail, then Recalculate All.
  5. If the listing does not exist — create the Amazon offer (SKU must resolve to ASIN), then sync + recalculate.
  6. After SP-API succeeds, status returns to ACTIVE or UPDATE_NEEDED and International Pricing populates.

Example: EmporioArmaniPowerOfYouEdP30ml2er — base article is a bundle (bundle_type: bundle), seller SKU equals the Plenty SKU, stock > 0, but Amazon has no ASIN for that SKU → ERROR until the real Amazon seller SKU is listed and synced.


FBA (Amazon FBA)

Credentials: Amazon SP-API, Sellerlogic.

Workflow: Sync AllRecalculate AllExport All.

Action Purpose
Sync All Full Sellerlogic product list, stock, dimensions, marketplaces
Sync Ledger Report Update last inbound date from Amazon inventory ledger
Recalculate All Rules-on: full SP-API min/max per marketplace; penner/renner/UVP: profit-only (heal wave from history)
Export All Push min/max to Sellerlogic per region

Marketplaces column — countries in international_pricing (DE, FR, ES, IT, NL, PL, SE, BE, UK, …).

New marketplace in Sellerlogic (on sync)

  • If Amazon marketplace ID is known → new country added with Sellerlogic’s current min/max, ignore: false.
  • Existing countries unchanged.
  • Unknown marketplace ID → logged, skipped until developers add mapping.
  • Marketplace removed in Sellerlogic → removed locally on next sync.

Ignore — same as FBM; only regions with Ignore = True are skipped. Export All includes all other regions with valid min/max (not only UPDATE_NEEDED).

OOS (since 1.8.10 / 1.10.4): Manual recalc without force still skips OOS. Base cron and buy-price force pass force_min_max=True, so rules-on OOS FBA rows are recalculated (and can export).

Sync Ledger Report dialog — optional ASIN, date range; explains inbound date from warehouse transfers (18-month Amazon limit).


How prices are calculated (simplified)

  1. Inputs: buy price (net), package cost, weight/dimensions, margin rule for current buy price, channel fees (API or stored).
  2. Min bound — target margin % + minimum profit from rule (lower tier).
  3. Max bound — target margin % + minimum profit from rule (upper tier).
  4. Amazon (FBA/FBM): SP-API product fees + FBA fulfillment + storage; per-country currency conversion.
  5. Otto: provision % from category table + competitor context on monitor pass.
  6. Kaufland: variable/fixed fees + VAT per storefront.
  7. Shopify: margin rule → single selling price + expected profit.

Manual override (Use Min/Max Rules = off): your entered min/max target prices stay fixed; only profit/margin numbers refresh when buy price changes — unless buy-price force recalc runs (then min/max recalculated and Otto max price is pushed to Otto + Plenty — 1.8.10+), or min/max were empty (then standard bounds are calculated and max is exported to Otto + Plenty — 1.8.10+).

FBA max prices are rounded to €X.90 style endings before export.


Error troubleshooting

Symptom Likely cause What to do
Status OOS Stock 0 Restock; or for FBA after EK change, run sync with Update Prices (1.8.10+)
Status UPDATE_NEEDED forever Export not run or failed Run channel Export; check credentials
Status ERROR See error_message in expanded row Fix missing buy price, margin rule, credentials, or provision
Buy price wrong / missing No shopping table row for SKU/ASIN Add row or fix asin_sku
FBA/FBM not in Sellerlogic Was not in DB Run base Sync All (full Sellerlogic import since 1.8.10)
Marketplace missing locally Unknown Amazon marketplace ID Contact dev to add region_map entry
Region not exported Ignore not explicitly False Edit FBA/FBM details, set Ignore off for that country
UVP didn’t force-recalc By design Remove UVP or edit bounds manually
Otto monitor does nothing OOS, Paused, or cron skip Use per-row Monitor to force, or fix stock/status
Otto has no min/max after sync New listing, bounds never set Run Recalculate All — auto-fills and pushes max sale price (1.8.10+)
Otto sale price stale after EK Buy price changed but no monitor run Run base Sync All — force recalc pushes new max to Otto + Plenty (1.8.10+)
FBM No ASIN found for SKU Amazon has no listing/ASIN for seller_sku Verify Seller Central + Sellerlogic; FBM Sync All; fix seller SKU (common on bundles); create listing if missing
Shopify export delayed Plenty rate limit Wait for auto-retry (~3 min)

Credentials checklist

Channel Required credentials
Base / Plenty Plenty (Base tab uses shared Plenty creds)
Otto Otto + Plenty
Kaufland Kaufland + Plenty
Shopify Plenty
FBM Plenty, Amazon, Sellerlogic
FBA Amazon, Sellerlogic

Test buttons on credential forms should succeed before relying on sync/export.