OnNShiftCheckoutVariables Hook
nShift Checkout configurations are driven by an open set of variables — provider-specific key/value pairs interpreted by your checkout configuration on nShift's side. Every nShift account uses a different set: fromwarehouse, vipCustomer, isSplit, and so on.
Rather than hard-coding any of this, the nShift Checkout app fires the OnNShiftCheckoutVariables hook every time it builds a request to nShift. Add merchant rules to that hook to feed in whatever variables your configuration expects.
The hook fires on every shipping-product lookup the app makes for a delivery — including the Select shipping product action in the order view. Write your rules once and they apply to every lookup.
The resolved variables are stored on the nShiftCheckoutSession ticket actor that backs the lookup, so you can inspect "what variables were in play when this session was created" from the portal — useful for debugging merchant-rule behaviour.
Listening to the hook
Declare a rule with a param input that matches OnNShiftCheckoutVariables. The hook is fired with a delivery-rooted outline of the data the app already loaded — delivery + its order + its order lines, with dynamic on each. Only declare the fields your rule reads; Filtrera's type system narrows hook matching to rules whose declared shape is satisfied.
param input: {
hook: 'OnNShiftCheckoutVariables'
delivery: {
deliveryId: uuid | nothing
deliveryAddress: {
name: text | nothing
careOf: text | nothing
attention: text | nothing
addressLine1: text | nothing
addressLine2: text | nothing
city: text | nothing
state: text | nothing
postalCode: text | nothing
countryCode: text | nothing
email: text | nothing
phone: text | nothing
}
dynamic: { text -> value }
lines: [{
orderLineId: uuid | nothing
productNumber: text | nothing
quantity: number
dynamic: { text -> value }
taxFactor: number | nothing
}]
order: {
orderId: uuid | nothing
channelKey: text
currencyCode: text
locale: text | nothing
dynamic: { text -> value }
}
}
}| Field | Description |
|---|---|
delivery.deliveryId | The delivery being quoted, or nothing in a cart-rooted (pre-order) flow. |
delivery.deliveryAddress | The destination address (graph Address shape). |
delivery.dynamic | Dynamic fields on the delivery (e.g. inventoryKey, route tags). Read whatever your apps have stored there. |
delivery.lines | The delivery's order lines, carrying Hantera-native system fields only. Read product attributes (weight, dimensions, item class) from line.dynamic after their owning app has projected them there. |
delivery.lines[].taxFactor | The line's tax factor (e.g. 0.25), when known. Drives the default shipping-tax behaviour — see OnNShiftCheckoutShippingOptionTax. |
delivery.order.orderId | The order the delivery belongs to, or nothing in a cart-rooted (pre-order) flow. |
delivery.order.channelKey | Channel of the order. |
delivery.order.currencyCode | Currency of the order. |
delivery.order.locale | Locale of the order (may be nothing). |
delivery.order.dynamic | Dynamic fields on the order. |
Ids can be nothing
Both delivery.deliveryId and delivery.order.orderId are uuid | nothing. A portal-rooted lookup (the Select shipping product action) has both ids; a cart-rooted (pre-order) lookup has neither, because no delivery or order exists yet. Guard for nothing before querying the graph from these ids.
Emitting a variable
A rule contributes one variable per custom/variable effect it emits:
from {
effect = 'custom'
type = 'variable'
key = 'fromwarehouse'
value = 'HQ'
}| Field | Description |
|---|---|
effect | Must be 'custom'. |
type | Must be 'variable'. The hook helper only collects variables; other effects are ignored. |
key | Variable key as defined by your nShift checkout configuration. |
value | Variable value. Usually text, but any JSON-serializable Filtrera value works. |
If multiple rules contribute the same key, the last effect emitted wins. This makes it easy to layer a default rule with a more specific override. The app also pre-seeds channelKey from the order, which your rules can override.
Example: per-channel warehouse
A merchant operating two storefronts wants nShift to ship from a different warehouse per channel.
param input: {
hook: 'OnNShiftCheckoutVariables'
delivery: {
order: { channelKey: text }
}
}
let warehouseByChannel = {
'retail-se' -> 'WH-SE'
'retail-no' -> 'WH-NO'
}
from warehouseByChannel->input.delivery.order.channelKey match
(warehouse: text) |> {
effect = 'custom'
type = 'variable'
key = 'fromwarehouse'
value = warehouse
}Example: VIP customers get free-shipping variants
Assume the tenant has added a custom customer edge from order (a common pattern). Read the customer's segment and set a vipCustomer variable that your nShift configuration uses to switch on free-shipping carrier products.
param input: {
hook: 'OnNShiftCheckoutVariables'
delivery: {
order: { orderId: uuid | nothing }
}
}
from input.delivery.order.orderId match
(orderId: uuid) |>
let q =
query orders(orderId)
navigate customer(customerSegment)
filter $'orderId == {orderId}'
let segment = q first match
{ customer: { customerSegment: text } } |> q first.customer.customerSegment
from segment match
'vip' |> {
effect = 'custom'
type = 'variable'
key = 'vipCustomer'
value = '1'
}Example: warehouse from inventory routing
When the inventory-routing app splits an order across warehouses, the delivery's inventoryKey dynamic field carries the actual fulfillment warehouse. Forward it to nShift as fromwarehouse — no graph query needed since delivery.dynamic is already in the hook input.
param input: {
hook: 'OnNShiftCheckoutVariables'
delivery: {
dynamic: { text -> value }
}
}
from input.delivery.dynamic->'inventoryKey' match
(k: text) |> {
effect = 'custom'
type = 'variable'
key = 'fromwarehouse'
value = k
}See Also
- nShift Checkout overview — Set up the app and configure channels.
- Shipping Module reference —
getOptions, the request shape, and thecontextparameter. OnNShiftCheckoutShippingOptionTaxHook — Compute per-option shipping tax from the same context.- Custom Hooks — How custom hooks work.