Sales channels

Overview
A sales channel is a point of sale outside the system — a marketplace or a shop. This area holds two directions together: listings and stock go out, orders come in.
The principle behind it: the system stays the truth. A channel receives an allocation of stock, not the stock itself — otherwise two channels would sell the same item.
Core tasks
Set up a channel. You create the channel, store the credentials and define which stock allocation and which customer apply to incoming orders.
Maintain listings. A listing connects a product with the channel. Title, description and price can be overridden per channel — whatever is not overridden comes from the product master data.
Trigger a sync. The sync sends listings and stock out and pulls orders in. It can be started manually; in normal operation it runs automatically.
Bundles and configurable articles. If the channel reports the chosen options (Shopware: nested line items, Shopify: bundles), the import takes over a configurable article with exactly this selection and does not book the parts on top. If the bundle is not a configurable article on your side, the individual parts remain the order — as without a bundle. WooCommerce does not deliver this information yet.
Delivery time to the channel. The article's delivery time goes out with the listing, and every channel gets it in its own form: Shopware the range 1:1 (minimum and maximum in days), Otto the upper bound as delivery time (parcel or freight forwarder is set by the channel setting Delivery type), Amazon and Kaufland the upper bound as handling time — the time until shipping, to which the marketplace adds the transit time itself. The upper bound, because the handling time is a shipping promise whose breach the marketplace counts; the delivery time already includes the transit time and is therefore a safe upper limit. Kaufland maintains it with the stock on the existing unit, Amazon only for merchant fulfilment. Without a delivery time on the article or with "on request" nothing goes out — the channel keeps its default. A changed delivery time resends the listing on the next sync.
Texts, manufacturer, properties, variants and images to the shop. Shopware and Shopify receive more than title and price:
| Detail | Shopware | Shopify |
|---|---|---|
| Name and description per language (from the translations; variants inherit the container's description) | as a translation — only for languages the shop has; own mapping via the channel setting languageCodes (e.g. {"en": "en-US"}) | as a registered translation; the shop's primary language (channel setting primaryLocale, default de) is the source text |
| Manufacturer with legal details (GPSR: company name, responsible person in the EU, address, e-mail, phone) | manufacturer with link, the mandatory details as custom fields octibiz_gpsr_* | manufacturer as vendor, the mandatory details as metafield octibiz.gpsr |
| Properties (e.g. colour: red) | properties with group | metafield octibiz.properties |
| Variants | variant below the container as parent product, with its axis values | all variants of a container as ONE product with variants (axes as product options, title and translation from the container) |
| Images (public address on the media item) | media, the first as cover | product images, fetched by the shop from the address |
Any change to these details resends the listing on the next sync. Amounts go out in the smallest unit of the channel currency as always.
Variants as real variants in the shop. In Octibiz every variant stays an article of its own with its own article number, price and stock. In the shop it becomes what the shop understands as an article with variants:
| Shop | Mapping |
|---|---|
| Shopware | parent product (article number of the container) with one variant each |
| Shopify | ONE product with all variants; the axes (e.g. colour, size) are the product options |
| WooCommerce | variable product (article number of the container) with one variation each; the axes are the variation attributes |
If one variant changes, Shopify and WooCommerce receive all variants of the same container — the shop product is set as a whole. Stock and price go per variant; an order from the shop hits exactly the variant via its article number. If a variant article is deleted or deactivated in Octibiz, it drops out of the Shopify product with the next transfer of its siblings. Variants that were transferred as single products before this change are created as a shared product by the first sync, which sets the old single products to draft once (Shopify DRAFT, WooCommerce draft) — nothing is deleted, orders and references in the shop stay intact. The sync result names per variant which old product was set to draft.
Withdraw a listing. Withdrawing removes it on the channel without touching the product.
Fields in detail
| Field | Required | Values / format | What it does |
|---|---|---|---|
Key channelKey | yes | text, max. 100 characters | The channel's technical identifier. Do not change it once orders run through it. |
Name name | yes | text, max. 160 characters | What the channel is called in lists and reports. |
Connector type connectorType | yes | an available connector, max. 60 characters | What is connected to — marketplace, shop, foreign system. |
Provider connection integrationProvider | no | a configured connection | Which login is used for access. |
Settings config | no | depending on the connector | Credentials and identifiers of the channel. |
Brand brandId | no | one of your brands | Which brand this channel's orders run under. |
Currency currency | no | ISO 4217 currency code, 3 characters | The currency this channel sells in. Empty = the accounting currency. If something else is set, the system converts prices once and reports amount and currency together; without a stored rate no price or listing run happens. Amounts are sent and read with the decimal places of the currency (yen none, euro two, Bahraini dinar three); imported orders carry the marketplace's currency. |
Warehouse warehouseId | no | an existing warehouse | Which stock serves the channel. |
Stock share (%) stockPercent | no | 1 to 100 | How much of the stock is reported to the channel. With several channels on one warehouse, the way not to sell the same goods twice. |
Stock buffer stockBuffer | no | 0 or more | How many pieces are held back. The most effective guard against overselling: the last item is not reported, so the gap in time between two sales hits nobody. |
Price customer priceCustomerUlid | no | an existing customer | Whose price finding is adopted. That way a marketplace gets its own prices without them being maintained twice. |
Fallback customer fallbackCustomerUlid | no | an existing customer | Who an order is assigned to when its buyer cannot be matched. Without them the order gets stuck. |
Acting user runAsUserUlid | no | an existing account | In whose name the channel acts. Their permissions apply — and this identity appears in the audit log. |
Confirm orders automatically autoConfirmOrders | no | yes/no | Whether incoming orders go into processing without review. |
Orders orders | no | list of incoming orders | The orders taken over from the channel. |
Interface and automation only
| Field | Values / format | What it does |
|---|---|---|
checkouts | one cart or a list, at most 100 | Reports started carts of the channel (POST …/channels/{ulid}/checkouts) — the path for shop webhooks such as Shopify checkouts/create. Every report with the same externalId updates the same cart; completedAt set means ordered. |
operation and force | operation type, yes/no | Triggers a sync — report stock, send prices, fetch orders. force bypasses the cooldown between runs; use with care, because marketplaces cap the number of requests. |
externalOrderId | foreign identifier | Which channel order is reported as shipped. This is how the marketplace recognises the shipment. |
orderUlid | one of your own orders | Which of your own orders the shipment comes from. |
carrier | text, max. 60 characters | The carrier — spelled the way the channel expects it. |
trackingNumber | text, max. 120 characters | The tracking number the buyer gets to see. |
trackingUrl | address, max. 500 characters | The tracking link for the shipment. |
shippedAt | timestamp | When it was shipped; empty = now. |
lines | list of item number and quantity | Reports a partial shipment. Empty means the whole order has gone out. The marketplace's line identifier is added by the system from the order import — there is nowhere else to get it. |
Settings & permissions
- View:
channels.channel.view - Set up a channel (allocation, credentials, customer):
channels.channel.manage - Listings:
channels.listing.manage - Trigger sync:
channels.sync.execute
Module flag: module.channels. The actual connection to a specific marketplace is supplied by its own channel plugin.
FAQ & troubleshooting
Stock on the channel differs. Check the allocation: the channel only sees its share, not the total stock.
An item without stock management shows a high quantity on the channel. That is intended: services, downloads and items without stock management count as available, not as sold out. The quantity comes from the setting channels.unmanaged_stock_qty (default 999); WooCommerce and Shopify get "not stock-managed" instead.
A partial shipment shows as a full delivery at the marketplace. Since 2026-09-21 every shipment reports exactly its lines and quantities; older reports stay as they were.
Where do market prices come from? The repricer lookup of competing offers exists for Amazon, eBay and Kaufland. Otto offers no interface for it; there the lookup reports "not supported".
An order arrived without a customer. Then the channel is missing the customer for incoming orders.
The sync reports an error. The channel's message is in the run journal — usually expired credentials or a field the marketplace rejected.