Skip to content

The upsell callback contract

The request Kustom sends your upsell endpoint and the response it expects back — every field of upsell_request, upsell_service_response and upsell_line, and what decides whether the upsell widget is shown at all.

Kustom calls merchant_urls.upsell before the confirmation page loads, and again after every item the customer adds, and expects a list of products back each time. Each call is given 10 seconds and isn’t retried. Aim to answer in under three, because a customer is waiting on the confirmation page meanwhile. The endpoint isn’t called at all when your account has Portal-curated products for the order, because those take precedence. This page is the field-level contract for that exchange. Upselling on the confirmation page is where the decisions are — when to enable it, where recommendations come from and when your own system creates the order.

FieldTypeMeaning
upsell_possiblebooleanfalse when the payment method can’t support upsell. You’re still called
max_upsell_amountintegerAuthorization headroom in minor units: the original order total (at least 100 SEK, NOK or DKK, or 10 EUR or GBP), minus what has already been upsold. 0 when the payment method doesn’t support upsell. Pre-filter against it
order_linesarrayWhat the customer has already bought
selected_shipping_optionobjectTheir chosen delivery. Present whenever the order has one selected — from its own shipping_options or from the Shipping Assistant
billing_addressobjectFor tax and locale-aware filtering
shipping_addressobjectAs above
purchase_currencystringISO 4217
localestringBCP 47, such as en-SE
merchant_idstringYour merchant ID
session_idstringThe order identifier. Map it to your own order
FieldTypeRequiredMeaning
upsell_linesarrayYesProducts to display. Empty means no widget — return [] to signal “no recommendations”
last_upsell_timestringNoISO 8601 moment the widget stops accepting additions. Falls back to the account-level window. Doesn’t move the confirmation push, which always waits for the account-level window
notification_uristringNoWhere Kustom pushes when the order is updated with upsell items, used only when merchant_urls.upsell_notification isn’t set — useful as a re-read trigger if you create on redirect

Required:

FieldTypeMeaning
namestringProduct name, max 255 characters
quantityintegerThe quantity you’re offering, not the customer’s choice
unit_priceintegerMinor units, tax included
tax_rateintegerTwo implicit decimals — 2500 is 25%
total_amountintegerMinor units, tax and discount included. Must equal quantity × unit_price − total_discount_amount
total_tax_amountintegerMinor units
max_allowed_quantityintegerThe most the customer may add

Strongly recommended — without image_url in particular, the product card renders with no picture:

FieldMeaning
referenceYour SKU
image_urlCard image, max 1024 characters
product_urlProduct page, max 1024 characters
descriptionMax 1024 characters
product_identifiersGTIN, ISBN and similar
shipping_attributesWeight, dimensions and tags, for shipping compatibility
feedback_urlCalled when a customer adds this item — an item-level signal

quantity trips people up. It’s the default offer, not a selection: set it to 1 and bound the customer with max_allowed_quantity. Kustom recalculates the totals and re-validates the authorization whenever an item is added, so your arithmetic has to be right but it isn’t the last word.

{
"shipping_attributes": {
"weight": 500,
"dimensions": { "width": 100, "height": 150, "length": 200 },
"tags": ["standard", "non-fragile"]
}
}

Kustom only loads the upsell widget when the order qualifies: upsell is enabled for it, the payment method the customer used allows the authorization to be increased and there is something to recommend within the headroom. You don’t need to track which payment methods qualify. When the payment method doesn’t, upsell_possible is false, max_upsell_amount is 0, no widget appears and the push isn’t delayed. When there’s simply nothing to recommend, no widget appears either, but the push is still delayed for the full window.

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