Show delivery options at checkout

Updated June 11, 20264 min read

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:

ConditionEvaluated against
Customer geographycustomer.country, state, city, area
Order value rangepayment.order_total
Weight rangeSum of line_items[].weight.value (converted to kg)
Payment typeCASH_ON_DELIVERY if payment.payment_on_delivery > 0, else PRE_PAID
Working days / blackout daysCurrent time; timezone from customer.country
Fulfillment locationfulfillment_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 (requires customer.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.coords is optional but unlocks distance. Without it, COLLECTION options 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_items with weights has no filtering effect — the data is accepted but not evaluated.
  • Currency must be consistent. The payment.currency should 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.