Configuration
The per-delivery routing app is configured almost entirely through one piece of data: an ordered list of warehouse keys per (channel, country). Everything else — when to route, when to reserve, when to back-order — is automatic.
Concepts to align on
Terminology check
Before configuring, make sure these three concepts are clear in your tenant:
- Channel — a market, sales surface, or external-integration scope (e.g. Sverige, Hantera.io Webshop, Germany B2B, ERP-Import). Channels are part of Globalization.
- Country — the ISO-3166-1 alpha-2 code on a delivery address (e.g.
SE,DE). - Inventory — a configured warehouse / 3PL location with a unique key (e.g.
warehouse-stockholm,3PL_DE_1).
A given delivery is routed based on its channel and the country on its delivery address. So a Swedish channel selling to a German customer uses the priorities under "DE" in the Swedish channel's config — even if you also have a separate German channel with different priorities.
Where the priority list lives
Channel-country inventory priorities live in the channel registry, under each country entry:
/channels/<channelKey>
└── countries
└── <countryCode>
└── inventoryRouting_inventories: text[] ← ordered priority list| Field | Type | Description |
|---|---|---|
inventoryRouting_inventories | text[] | Inventory keys in priority order. The first entry is the country's primary warehouse (also used as back-order home). |
The keys in the list must exist in the inventories enum (i.e. be configured warehouses in your tenant). The app does not verify this — typos silently de-prioritise that slot.
Where to configure it
The app contributes a drag-and-drop UI to the channel editor in the portal. To configure:
- Open Settings → Channels in the portal.
- Pick a channel.
- Expand the Countries section.
- For each country you want to auto-route, drag inventories into the priority list in your desired order.
- Save.
The country must already be enabled on the channel
The app's priority editor renders inside an existing country row. If a country isn't listed for the channel, add it first via the standard country editor in the channel.
Worked example
Imagine an outdoor-apparel retailer with two channels and three warehouses:
| Channel key | Description | Country | Priority order |
|---|---|---|---|
se | Swedish webshop | SE | warehouse-stockholm, 3PL_central, warehouse-overflow |
se | Swedish webshop | DE | 3PL_DE_1, warehouse-stockholm |
se | Swedish webshop | NO | warehouse-stockholm, 3PL_central |
de-b2b | German B2B portal | DE | warehouse-overflow, 3PL_DE_1 |
Reading this table:
- A consumer in Stockholm checks out through the Swedish webshop — order goes to
warehouse-stockholmfirst, falls back to3PL_central, thenwarehouse-overflowif needed. - The same Swedish webshop ships to Berlin — the local 3PL
3PL_DE_1is preferred over the home warehouse to save customs costs and shipping time. - The B2B German portal has a completely different priority for
DE— it prefers the lower-costwarehouse-overflowover3PL_DE_1, presumably because B2B customers tolerate longer delivery times.
This level of decoupling is the whole point of the channel-keyed config: marketing, fulfilment, and customer experience can each be tuned independently.
How the country code is determined
The app reads delivery.deliveryAddress.countryCode. Specifically:
- It must be a non-empty ISO 3166-1 alpha-2 code (e.g.
SE, notSweden). - It is case-sensitive in the registry lookup — the country code on the address must exactly match the key under
channels.<channelKey>.countries.<countryCode>.
Empty country code is the silent failure
If countryCode is empty (e.g. on a partially-imported order), the app cannot look up a priority list and skips routing entirely. The delivery stays in auto_assign and never gets a real warehouse assigned. If you see this happening, check the delivery address on the affected order.
Seeding from your ERP
The registry is just YAML-shaped JSON, so seeding from an ERP or CSV is a one-time job. A minimal seed for the table above looks like this:
# manifests/channels-seed.yaml
uri: /registry/channels/se
spec:
value:
countries:
SE:
inventoryRouting_inventories:
- warehouse-stockholm
- 3PL_central
- warehouse-overflow
DE:
inventoryRouting_inventories:
- 3PL_DE_1
- warehouse-stockholm
NO:
inventoryRouting_inventories:
- warehouse-stockholm
- 3PL_central
---
uri: /registry/channels/de-b2b
spec:
value:
countries:
DE:
inventoryRouting_inventories:
- warehouse-overflow
- 3PL_DE_1Push this manifest through your normal deployment pipeline (e.g. the Hantera CLI apply command), or have your ERP integration write directly via the standard registry API.
Defaulting inventoryKey and inventoryDate
For the routing app to act on a delivery, that delivery must have inventoryKey: "auto_assign" set and an appropriate inventoryDate. There are three ways to make sure this happens:
| Option | When it's a good fit |
|---|---|
Have the order source set the fields explicitly. Your HTTP ingress, ERP integration, or import script writes inventoryKey: "auto_assign" (and an inventoryDate) at order-creation time. | Anywhere the order source is something you control directly. |
| Write a small defaulting rule. A one-line rule fired when an order is created can set the dynamic fields on any delivery that doesn't already have them. | When multiple order sources feed the same tenant and you want a single, central place to enforce defaults. |
Use the optional companion rule that ships with this app. OnCommerceCartToOrder.hrl sets inventoryKey: "auto_assign" and inventoryDate: today on deliveries created by the Commerce app. | When the Commerce app is one of your order sources and you want the routing to "just work" without writing anything yourself. |
The companion rule only fires for Commerce-created orders and has no effect elsewhere; see the per-delivery/ overview for details.
See also
- Auto-Assignment — what the app actually does with this configuration.
- Back-Orders — what happens when none of the priority warehouses can cover the demand.
- Stock Reservations — how the routed deliveries become real reservations against the SKU actor.