Skip to content

Answer the callbacks

Decide whether you need address_update, shipping_option_update or validation at all, and why an unanswered validation request completes the purchase in ten seconds by default.

Starting playground session…
  1. Build the payload
  2. Create order
  3. Render snippet
  4. Validate · optional
  5. Confirm & push

On this page you'll

  • Decide which of the three in-session callbacks your integration actually needs
  • State whether your integration is fail open or fail closed, and why
  • Answer the validation callback with the response shape Kustom expects
Validation and other callbacks
0 calls

Kustom can call your server three times while the customer is still looking at the checkout: once when the destination changes what something costs, once when the customer picks shipping inside the iframe and once for a last look before the purchase completes. Most integrations need none of them. This page tells you which apply to yours, then covers the one call that can’t be skipped once you register it — validation — and the ten-second window that decides whether an unanswered request passes the purchase or blocks it.

You need none of the three if your totals don’t change with the shipping address, you offer one shipping option or ship free and nothing about the order can become untrue between creating it and the customer pressing Pay order. A catalog with flat shipping and stock that never runs out has no reason to register any of them.

CallbackYou need it only if
address_updateTotals depend on the destination — shipping cost or tax that varies by address
shipping_option_updateThe customer picks a shipping option inside the checkout iframe, rather than on a page of yours
validationStock, an expiring price or a fraud check can invalidate the order between creation and purchase

Server-side callbacks owns how address_update and shipping_option_update work — what each one sends and what a valid response looks like — so register them there once you’ve decided you need them. The rest of this page is about the third one, because deciding to skip it is not the same as opting out of its effect.

Validation must answer within ten seconds. Past that, Kustom treats the order as valid and redirects the customer to confirmation anyway — so you’re fail open by default, whether or not you chose it. For most catalogs that default is the right one: a customer who already paid shouldn’t be blocked because your server had a slow ten seconds.

Set options.require_validate_callback_success: true on the order when that trade is reversed — an item that can oversell, a price that expires, a check required by law — where letting the wrong purchase through costs more than blocking a good one. The flag turns a timeout or any response other than a 2xx or a redirect into a block instead of a pass. Choose it deliberately, once your endpoint is reliable, rather than as the default you get by not deciding.

Register merchant_urls.validation and Kustom POSTs the full order — line items, addresses, amounts — to it while the order’s status is still checkout_incomplete. This is your last look before the purchase completes.

{
"merchant_urls": {
"validation": "https://shop.example/api/kustom/validate"
}
}

Reply within the ten-second window:

Your responseWhat happens
200The purchase proceeds
303 with a Location headerKustom sends the customer to that URL instead of confirmation — this is the rejection message the customer actually sees, so make the page explain why: out of stock, price changed, no longer available
Anything else, or no reply in timeFail open (the default): treated the same as 200. Fail closed (require_validate_callback_success: true): the customer gets a generic error and the purchase stops
FailureWhat happens
The handler takes longer than ten secondsFail open lets the purchase through. Fail closed shows the customer a generic error
The handler reads or updates the order through the API instead of reading the POST bodyYour own call can race the response you’re about to send — treat the callback body as the order, don’t refetch it
A response that is neither a 2xx nor a 3xx with LocationUnder fail open — the default — it is treated as an approval and the purchase completes, whatever the status was. It stops the purchase only with require_validate_callback_success: true. The exception either way is a 400 carrying error_type: address_error or approval_failed, which denies and shows the customer your error_text
The customer authenticates with 3D Secure before your answer landsYour 200 doesn’t by itself mean the purchase completed. Deny after that authentication and Kustom cancels the payment — refunding it if it had already been captured — so the reservation is released and you see no order

None of these fail loudly on your side — the customer sees a generic error page or an order that went through, and the reason lives in whichever response you actually sent.

These docs answer 200 to every validation call they receive, which is why a purchase made in this Playground session always completes. To see the other branch on your own integration, point merchant_urls.validation at an endpoint that returns 500, or one that simply never answers, then complete a purchase against it. The request Kustom made and the status code you returned appear in this session’s console exactly as they would in your own Developer Logs — the fastest way to confirm which side of fail open your endpoint actually lands on before a real customer finds out for you.

What you’re left with, once you’ve answered — or knowingly skipped — validation, is a purchase Kustom is allowed to complete. Confirmation & push is where that completion actually reaches you: the redirect, the push and reading the order back to find out what happened.

This page is also available as Markdown — append .md to its URL — and is indexed in llms.txt.