# Core Concepts

## Sales Channels

Sales channels represent connections to external platforms. Every shop app creates one **Sales Channel Backend** (represents the integration itself, e.g. "Shopware 6") and one or more **Sales Channels** (one per connected shop/store). A single app can manage multiple channels — for example, connecting to three different Shopware stores.

Backends and channels are created during the app migration. Register `sales_channel.create` and `sales_channel.delete` webhooks to react when channels are added or removed. In the create handler, initialise default parameters and register per-channel webhooks.

Each article in the ERP can have **listings** — one per sales channel. A listing stores channel-specific data like the external platform ID. Use `article.shopListing` in VQL queries and filter by `listings.salesChannel.id`.

## Webhooks

Shop apps use two types of webhooks:

### ERP Webhooks

Triggered by data changes in the ERP. Each event creates a queue entry for outbound processing.

| Event                                                   | Trigger                     | Queue Topic            |
| ------------------------------------------------------- | --------------------------- | ---------------------- |
| `article(sales-channel-id=<id>).update`                 | Article master data changes | `upsert.article`       |
| `article-price.update`                                  | Price changes               | `update.article-price` |
| `sales_channel.stockChange`                             | Stock level changes         | `update.article-stock` |
| `article(sales-channel-id=<id>)-shelf.update`           | Media changes               | `upsert.article-media` |
| `document.customer_delivery_document.order_to_delivery` | Delivery note created       | `update.orderStatus`   |
| `sales_channel.create`                                  | New channel added           | — (initialise config)  |
| `sales_channel.delete`                                  | Channel removed             | — (clean up)           |

Article and media webhooks use a `sales-channel-id` filter so only changes relevant to your channel trigger the webhook. Use `x-vario-suppress-own-webhooks: true` when writing back to the ERP to prevent infinite loops.

### Cron Webhooks

Triggered on a schedule. Used for periodic tasks like importing orders or processing the outbound queue.

| Webhook          | Purpose                                |
| ---------------- | -------------------------------------- |
| `ORDER_IMPORT`   | Fetches new orders from the platform   |
| `PROCESS_QUEUES` | Processes queued outbound sync entries |

## Data Flow

### Outbound (ERP → Platform)

```
ERP Webhook → Queue Entry → PROCESS_QUEUES Cron → Fetch via VQL → Transform → Push to Platform
```

When an ERP webhook fires (e.g. article update), the handler creates a queue entry. The `PROCESS_QUEUES` cron picks up queued entries, fetches the full data from the ERP via VQL, transforms it to the platform's API format, and pushes it.

### Inbound (Platform → ERP)

```
ORDER_IMPORT Cron → Fetch from Platform → Transform → MultiPart Import → ERP
```

The cron webhook triggers a fetch of new data from the platform (e.g. orders since the last import timestamp). The data is transformed into the VARIO import format and uploaded via the MultiPart Import API.

## Queue

Outbound sync uses a queue to batch, deduplicate, and retry operations. Queue entries are stored within the app itself.

### Lifecycle

```
QUEUED → PROCESSING → COMPLETED
                    → FAILED (retried on next run)
```

1. ERP webhook fires → handler creates entry with state `QUEUED`
2. `PROCESS_QUEUES` cron fires → picks up queued entries in batches
3. Entries move to `PROCESSING`, attempt count increments
4. On success → `COMPLETED`. On error → `FAILED` with error details

To avoid duplicates, check for existing `QUEUED` or `PROCESSING` entries before inserting. The batch size is controlled by the `QUEUE_BLOCK_SIZE` parameter (default: 10).
