Delivery options
A Delivery Option is a named, merchant-configured choice presented to the customer at checkout. Each option declares its own pricing, estimated delivery time, the customer geographies it supports, the fulfillment locations it can ship from, and the delivery method (home delivery or customer collection).
The merchant builds this list once in the Dashboard. At checkout, the merchant calls Carriyo with the basket details and customer context. Carriyo returns the subset of options eligible for that specific checkout.
To compare raw carrier rates across carrier accounts (an internal, operator-facing task), see Shipping rates.
What a delivery option carries
A delivery option is configured per merchant and includes:
- Name and description. What the customer sees.
- Delivery method.
DELIVERY(home delivery) orCOLLECTION(customer collection). - Carrier account. The underlying account that fulfills the option once it's selected.
- Shipping fee. Flat, tiered, or free. The merchant controls the pricing model independently of the underlying carrier rate.
- Estimated delivery time. Used to compute the date shown to the customer at checkout.
- Fulfillment locations. The locations the option can ship from. For collection options, the customer collection locations the option can be picked up from.
- Eligibility criteria. Used to filter which options are returned for a given checkout. Examples include customer geography, order value bands, weight thresholds, and payment type.
The exact criteria available are managed in the Dashboard and evolve over time.
How the shipping fee is resolved
Each option prices itself, and the pricing strategy it was configured with decides how.
FREE_OF_COST. Always0. The currency is the option's default currency when one is set, and absent when it isn't. A free option often arrives carrying no currency at all.PAID. Carriyo takes the pricing entry matching the request currency, then the option's default currency, then the first entry configured. A tiered fee returns the first tier whose range contains the order total.PASS_THROUGH. A live rate quoted by the carrier. An option saved asPASS_THROUGHwithout a carrier account is downgraded toFREE_OF_COSTat save time. It never reaches checkout as a quote nobody can honor.
When a tiered fee ends in a free tier with no upper bound, that
tier's min_value comes back as free_shipping_threshold. It's
read off the pricing configuration rather than the cart, so it's
there whatever the basket is currently worth. That's what powers
an "add more for free shipping" nudge.
An empty shipping_fee ({}) means no price could be resolved:
no tier contained the order total, or no pricing entry matched
the currency. Never render it as free shipping. Read amount
and currency independently: 0 is a real price, and absent is
not.
That is different from a fee lookup that fails outright, which drops the option from the response rather than returning it unpriced. A failure after the fee has resolved goes the other way. The option is still returned, with its fee, but with no arrival estimate.
Two delivery methods, one model
Each delivery option declares whether it's DELIVERY (home
delivery to the customer's address) or COLLECTION (customer
picks up at a configured location). A single checkout call can
return both kinds in the same response, and the customer picks
either one. See
Click and collect for
the specifics of the COLLECTION variant.
How collection points are chosen
A COLLECTION option resolves its own list of pickup points at
request time. Which points you get depends on how the option was
configured.
An explicit list. The option offers exactly those locations, as long as each is active and enabled for collection. The list is honored as configured and is not filtered by the customer's country, so a merchant can deliberately offer a cross-border pickup point.
An empty or omitted list. The option resolves to every active, collection-enabled location the merchant can use in the customer's country. With no customer country in the request, it resolves to nothing.
fulfillment_locations reads the opposite way. An empty list
there means any fulfillment location, whatever country it sits
in.
Send customer.coords and Carriyo returns a distance per point
and orders the list nearest-first. Two limits can narrow it:
max_collection_distance on the request and
customer_collection_max_distance on the option. When both are
set the smaller one wins, and neither is enforced without the
customer's coordinates. The list is then capped at
max_collection_locations, which defaults to 10 and is never
allowed above 50.
What the merchant sends at checkout
A typical request carries:
- Merchant. Which merchant's configured options to evaluate.
- Line items. The basket.
- Customer address. Used to evaluate geographic eligibility.
- Fulfillment locations. The locations the merchant has inventory for this basket. Carriyo intersects these with each option's configured fulfillment locations to decide which options can be honored.
- Delivery methods (optional). Restrict the response to
DELIVERYonly,COLLECTIONonly, or both.
The response contains the eligible options, each with the computed shipping fee and estimated delivery date for this specific checkout.
Inventory-aware delivery options
By default, delivery options are filtered on the merchant's configured eligibility: geography, value bands, and the option's fulfillment locations. When inventory management is enabled, Carriyo adds a real-time stock check on top. An option is offered only if the basket can actually be fulfilled from the locations that option ships from, so the customer never picks a delivery choice that can't be honored. Each returned entry reports what it can provide of every basket line, and where that stock sits.
In the Dashboard: turn on inventory management and keep stock positions current. See Inventory.
Via the API: set inventory_check to true and identify the
products on each line, by product_id or product_ref. Three
things have to hold before the check runs. The flag is true,
inventory management is enabled for the tenant, and the line
resolves to a catalog product. Miss any one of them and no stock
is read. Every option that passes the standard eligibility
checks comes back unmarked. The flag is opt-in by design, so
existing integrations keep working untouched.
One trap sits under all of this. Stock is read by the product's
inventory_key, so a catalog product without one has no stock to
find. The line still counts as evaluated, so it reads as out of
stock rather than as unevaluated. Options then get filtered out
on a check that never really ran. See
Products for how the three identifiers
resolve.
This is what makes the order-allocation bridge below precise. The locations reported on the chosen option are the ones that genuinely held stock. When allocation later constrains booking to them, it constrains to a set that can actually fulfill, not just a configured list.
The exact request and response fields, the activation conditions, and the fallback contract are in the Delivery options API reference. For a full walkthrough that sends product references and uses the stock-filtered response, see the Filter delivery options by stock recipe. For reading availability marks, asking for variations, and requoting a split basket, see Handle partial availability at checkout.
What one entry means
Every returned entry is a single-delivery answer. Everything the entry marks as available ships together, in one delivery, from any one of the fulfillment locations it lists, at that entry's fee. The response never quietly promises a split.
Set include_variations and Carriyo returns each maximal
single-location variation as its own entry. A storefront that
wants to offer several deliveries composes them from those
entries, then requotes each subset so every delivery carries its
own real fee.
Reading availability
Three answers, and the difference between them matters:
- Absent. The line was never evaluated. This is not a "no".
UNKNOWN. The check ran and couldn't answer, typically because an inventory read failed.FULL,PARTIAL,NONE. A real verdict on what the entry can provide.
An option that can't provide anything is left out of the
response. A failed inventory read is the exception: the option
comes back marked UNKNOWN instead of disappearing, so you
decide whether to show it.
Scoping an option to some items only
An option's item_product_categories condition scopes which
items it can deliver. It doesn't hide the option. Items outside
the condition come back as NONE with fulfillable_quantity: 0
in every entry, even when no stock was read for them. They still
count toward the entry's verdict. An option that excludes
every item in the cart isn't returned at all.
A chilled-goods option is the everyday case. The option is
offered, the chilled lines are available on it, and the rest of
the basket is marked NONE.
The bridge to order allocation
When the customer picks a delivery option, send the chosen
option's code on the order. Use the code rather than the
id: the code is yours to keep stable, while the id changes if
the option is deleted and recreated. When the order is sent
to Carriyo:
- The chosen option is recorded on each fulfillment order the
order produces, not on the order itself. Read it from
fulfillment_orders[].delivery_option. - If the merchant is using Carriyo's Order management with allocation, allocation restricts to the fulfillment locations attached to the option. The customer can't end up with a shipment booked from a location the option doesn't support.
The option's estimated delivery date is only achievable when the shipment ships from a location the option was configured for. Constraining allocation to those locations keeps the customer-facing promise intact.
The estimated delivery date becomes a promise
The estimated delivery date returned per option is what the customer sees at checkout as their expected delivery. When the order is placed, the date for the chosen option becomes the customer promise on the resulting shipment. Tracking against that promise is handled by Service levels once the shipment exists.
How it fits with other modules
- Storefront. The parent page.
- Shipping rates. The internal carrier rate-shop (operator-facing, not shopper-facing).
- Orders → allocation engine. Where the chosen option constrains location selection.
- Locations. Fulfillment locations and customer collection locations are configured here.
- Carrier configuration. The underlying carrier accounts the option points at.