Show delivery options at checkout
POST /checkout/delivery-options returns the delivery choices your customer can pick from
at checkout. You supply the cart details and the customer's location; Carriyo evaluates
each merchant-configured option against its eligibility conditions and returns the ones
that match — complete with shipping fee and estimated arrival window.
Both home-delivery (DELIVERY) and click-and-collect (COLLECTION) options come back in
the same response. This recipe walks through the standard call, explains the response
shape for each delivery method, and shows how to scope results when your UI separates the
two.
Scenario
A customer in Dubai is checking out a cart worth AED 285 containing two items. Your storefront calls Carriyo with the customer's address and the basket. Carriyo returns three options: Standard Delivery, Next Day Delivery, and a free store-pickup option with two nearby collection points sorted by distance.
Prerequisites
- API credentials: see Getting started for the one-time setup.
- At least one delivery option configured for the merchant in the Dashboard. Options must have eligibility conditions that match the scenario (e.g. customer geography covers Dubai, order value falls within the configured band).
Step 1, call the endpoint with cart and customer details
The minimum required field is merchant. In practice you'll also send payment (for
order-value conditions), line_items (for weight conditions), and customer (for
geography conditions and estimated-arrival computation).
curl -X POST 'https://api.carriyo.com/checkout/delivery-options' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'tenant-id: YOUR_TENANT_ID' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"merchant": "ACME",
"payment": {
"currency": "AED",
"order_total": 285
},
"customer": {
"country": "AE",
"state": "DUBAI",
"city": "DUBAI",
"area": "DOWNTOWN-DUBAI",
"coords": [25.197, 55.274]
},
"line_items": [
{
"id": "line-1",
"sku": "TSHIRT-BLK-M",
"quantity": 2,
"weight": { "value": 0.25, "unit": "kg" }
},
{
"id": "line-2",
"sku": "JEANS-W32-L32",
"quantity": 1,
"weight": { "value": 0.6, "unit": "kg" }
}
]
}'
Carriyo evaluates each option's configured conditions against this data:
| Condition | Evaluated against |
|---|---|
| Customer geography | customer.country, state, city, area |
| Order value range | payment.order_total |
| Weight range | Sum of line_items[].weight.value (converted to kg) |
| Payment type | CASH_ON_DELIVERY if payment.payment_on_delivery > 0, else PRE_PAID |
| Working days / blackout days | Current time; timezone from customer.country |
| Fulfillment location | fulfillment_locations[] (omitted here — see Step 4) |
Options that fail any configured condition are excluded from the response.
Step 2, read the response
The response is an array of matching options. Both DELIVERY and COLLECTION options
appear together:
[
{
"id": "a1b2c3d4-1234-5678-abcd-111111111111",
"delivery_method": "DELIVERY",
"code": "STD",
"name": "Standard Delivery",
"description": "Delivered in 2–4 working days",
"carrier_account_id": "e7f8a9b0-1234-4c5d-8e6f-7a8b9c0d1e2f",
"shipping_fee": { "amount": 15, "currency": "AED" },
"estimated_arrival_from": "2026-05-07T09:00:00.000Z",
"estimated_arrival_to": "2026-05-09T18:00:00.000Z"
},
{
"id": "a1b2c3d4-1234-5678-abcd-222222222222",
"delivery_method": "DELIVERY",
"code": "NEXT_DAY",
"name": "Next Day Delivery",
"description": "Order before 6pm for next working day",
"carrier_account_id": "d6e7f8a9-5678-4b0c-9d1e-2f3a4b5c6d7e",
"shipping_fee": { "amount": 25, "currency": "AED" },
"estimated_arrival_from": "2026-05-06T09:00:00.000Z",
"estimated_arrival_to": "2026-05-06T18:00:00.000Z"
},
{
"id": "a1b2c3d4-1234-5678-abcd-333333333333",
"delivery_method": "COLLECTION",
"code": "STORE_PICKUP",
"name": "Collect From Store",
"description": "Free pickup from a participating store",
"shipping_fee": { "amount": 0, "currency": "AED" },
"estimated_arrival_from": "2026-05-06T10:00:00.000Z",
"estimated_arrival_to": "2026-05-06T22:00:00.000Z",
"customer_collection_locations": [
{
"location_id": "loc-dxb-downtown",
"location_code": "STORE-DXB-DOWNTOWN",
"location_name": "ACME Downtown Dubai",
"address1": "Boulevard Plaza, Tower 1",
"city": "DUBAI",
"state": "DUBAI",
"country": "AE",
"coords": [25.197, 55.274],
"distance": { "value": 0.4, "unit": "km" }
},
{
"location_id": "loc-dxb-marina",
"location_code": "STORE-DXB-MARINA",
"location_name": "ACME Marina Mall",
"address1": "Marina Mall, Ground Floor",
"city": "DUBAI",
"state": "DUBAI",
"country": "AE",
"coords": [25.078, 55.144],
"distance": { "value": 12.3, "unit": "km" }
}
]
}
]
Every option carries the same core fields:
code— the merchant-defined identifier you'll pass back when creating the order.shipping_fee— what to display to the customer.estimated_arrival_from/estimated_arrival_to— the delivery window.carrier_account_id— the carrier account that fulfills this option (a UUID). Present on options backed by a carrier account; absent on digital or unconfigured options.
Step 3, understand the COLLECTION response shape
COLLECTION options include customer_collection_locations — an array of pickup points
the customer can choose from. Each location carries address fields and, when customer.coords
was supplied in the request, a distance object showing how far it is from the customer.
Points are sorted nearest-first. You can cap results with two request fields:
max_collection_locations— limits how many points come back per option (default 10, max 50).max_collection_distance— only return points within this radius (requirescustomer.coords).
If the customer doesn't grant location access and you can't supply coords, the points
come back in the merchant's configured order with no distance field.
Step 4, scope to specific fulfillment locations
When your storefront knows which warehouses or stores can source the order (e.g. from a
prior inventory check), pass them in fulfillment_locations. Carriyo intersects them with
each option's configured location allowlist and only returns options that overlap:
curl -X POST 'https://api.carriyo.com/checkout/delivery-options' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
-H 'tenant-id: YOUR_TENANT_ID' \
-H 'x-api-key: YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"merchant": "ACME",
"payment": { "currency": "AED", "order_total": 450 },
"fulfillment_locations": [
{ "partner_location_code": "store-ad-marina-mall" },
{ "partner_location_code": "warehouse-dxb-01" }
],
"customer": {
"country": "AE",
"state": "ABU-DHABI",
"city": "ABU-DHABI"
},
"line_items": [
{ "id": "line-1", "sku": "WATCH-SS-42", "quantity": 1, "weight": { "value": 0.4, "unit": "kg" } }
]
}'
Use partner_location_code (your own identifier) rather than partner_location_id
(Carriyo's internal ID) — codes are stable across environments and don't require storing
Carriyo-specific IDs.
Step 5, filter by delivery method
If your UI shows home delivery and click-and-collect in separate tabs, use
delivery_methods to fetch only the relevant set:
// Home delivery tab only
{ "merchant": "ACME", "delivery_methods": ["DELIVERY"], ... }
// Click-and-collect tab only
{ "merchant": "ACME", "delivery_methods": ["COLLECTION"], ... }
Omit the field to get both in a single call.
Step 6, handle cash on delivery
For orders paid at the doorstep, set payment.payment_on_delivery to the amount the
courier should collect. Carriyo derives the payment type as CASH_ON_DELIVERY, which
activates payment-type conditions — options restricted to prepaid orders drop out:
{
"merchant": "ACME",
"payment": {
"currency": "AED",
"order_total": 199,
"payment_on_delivery": 199
},
...
}
What to do with the chosen option
Once the customer picks an option, persist its code on the order you send to Carriyo.
This lets the allocation engine know which delivery promise was sold and constrains
fulfillment to locations the option supports:
{
"merchant": "ACME",
"partner_order_reference": "YOUR_ORDER_REF",
"delivery_option": { "code": "STD" }
// ...rest of the order payload
}
For the full order-creation flow, see Place an order with a delivery option.
Pitfalls
- Empty response means no match. The array is empty (
[]) when no configured option passes the conditions for the supplied cart. Check the customer address fields and order value match at least one option's eligibility rules. customer.coordsis optional but unlocks distance. Without it,COLLECTIONoptions still return but you get no distance sorting or distance cap enforcement.- Conditions only fire when configured. If the merchant hasn't configured a weight
condition on any option, sending
line_itemswith weights has no filtering effect — the data is accepted but not evaluated. - Currency must be consistent. The
payment.currencyshould match the currency the merchant's options are configured in. - This endpoint is stateless. No shipment or order is created. Call it as many times as you need (cart changes, address updates) without side effects.