OnKustomValidation Hook
Kustom can be configured to call back to the merchant before completing a checkout. This is typically used for last-minute validations — verifying that stock is still available, that promotion conditions still hold, or any other business rule that should be re-checked once the customer is about to pay.
The Kustom app exposes the validate ingress for this callback, and emits the OnKustomValidation custom hook so that merchant rules (or other apps) can decide whether to allow the checkout to complete.
When It Fires
Fires when Kustom sends a POST /kustom/validate request to your Hantera instance. The Kustom app:
- Parses Kustom's order payload from the request body.
- Resolves the cart from
merchant_reference1(the cart ID). - Previews and queries the cart's resulting order (totals, lines, etc.).
- Triggers
OnKustomValidationwith the rendered order data. - Collects
validationErroreffects from the hook. - If any errors are present, responds to Kustom with the first one and
400 Bad Request. Otherwise responds with200 OK.
Hook Input
The hook input is the rendered order with hook added by the runtime:
{
hook: 'OnKustomValidation'
channelKey: text
currencyCode: text
locale: text | nothing
taxIncluded: bool
orderTotal: number
orderTaxTotal: number
orderLines: [{
productNumber: text
description: text | nothing
quantity: number
reservedQuantity: number
unitPrice: number
salesTotal: number
taxTotal: number
}]
}TIP
You only need to declare the fields your rule uses. Filtrera's type system automatically matches rules to the hook based on the declared input shape.
Returning a Validation Error
To block the checkout, a rule emits one or more validationError effects. Only the first error is forwarded to Kustom; all others are ignored.
from {
effect = 'validationError'
code = 'approval_failed'
message = 'One or more items are no longer available.'
}| Field | Required | Mapped to Kustom | Notes |
|---|---|---|---|
effect | yes | — | Must be 'validationError' |
code | yes | error_type | Kustom-defined error type. Must be one of the values below. |
message | no | error_text | Human-readable message shown to the customer. Falls back to code if omitted. |
Allowed code values
code is forwarded as-is to Kustom in the error_type field, and Kustom only recognizes a fixed set of values. Other values will not render correctly in the iframe.
code | When to use |
|---|---|
'address_error' | The customer-supplied address is invalid (malformed postal code, missing fields, etc.) |
'unsupported_shipping_address' | The address is valid but you don't ship to that location |
'approval_failed' | The order cannot be approved for any other reason (out of stock, fraud check, business rule) |
If no rule emits a validationError, the ingress responds with 200 OK and Kustom proceeds with the checkout.
Example: Stock Availability Rule
This rule blocks the checkout if any order line has more quantity than what's currently reserved:
param input: {
hook: 'OnKustomValidation'
orderLines: [{
productNumber: text
quantity: number
reservedQuantity: number
}]
}
import 'iterators'
let unavailable =
input.orderLines
where line => line.quantity > line.reservedQuantity
buffer
from unavailable count > 0 match
true |> {
effect = 'validationError'
code = 'approval_failed'
message =
let names = unavailable select line => line.productNumber join ', '
$'The following items are no longer available: {names}'
}When this rule emits the error, the customer sees the message inside the Kustom iframe and cannot complete the purchase.
Example: Order Total Threshold
This rule rejects orders below a minimum amount:
param input: {
hook: 'OnKustomValidation'
currencyCode: text
orderTotal: number
}
from input.orderTotal < 100 match
true |> {
effect = 'validationError'
code = 'approval_failed'
message = $'Minimum order total is 100 {input.currencyCode}.'
}Example: Unsupported Shipping Country
This rule rejects orders whose channel doesn't permit a given destination — useful when shipping eligibility is configured outside of Kustom:
param input: {
hook: 'OnKustomValidation'
channelKey: text
}
import 'iterators'
let allowedChannels = ['retail-se', 'retail-no']
from allowedChannels where c => c == input.channelKey count == 0 match
true |> {
effect = 'validationError'
code = 'unsupported_shipping_address'
message = 'We don''t ship to this destination yet.'
}Effect Handling
The validate ingress only processes validationError effects from the hook. Any other effects emitted by listening rules are silently ignored — this hook is intended purely for accepting or rejecting the checkout, not for triggering side effects.
See Also
- Kustom App Overview — Ingresses, jobs, and rules
- Commerce Integration — How Kustom integrates with the cart flow
- Custom Hooks — How
triggerHookworks - Rule Effects — Available effect types