Skip to content

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:

  1. Parses Kustom's order payload from the request body.
  2. Resolves the cart from merchant_reference1 (the cart ID).
  3. Previews and queries the cart's resulting order (totals, lines, etc.).
  4. Triggers OnKustomValidation with the rendered order data.
  5. Collects validationError effects from the hook.
  6. If any errors are present, responds to Kustom with the first one and 400 Bad Request. Otherwise responds with 200 OK.

Hook Input

The hook input is the rendered order with hook added by the runtime:

filtrera
{
  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.

filtrera
from {
  effect = 'validationError'
  code = 'approval_failed'
  message = 'One or more items are no longer available.'
}
FieldRequiredMapped to KustomNotes
effectyesMust be 'validationError'
codeyeserror_typeKustom-defined error type. Must be one of the values below.
messagenoerror_textHuman-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.

codeWhen 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:

filtrera
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:

filtrera
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:

filtrera
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

© 2024 Hantera AB. All rights reserved.