Place an order with a delivery option

Updated September 9, 20263 min read

This recipe covers the end-to-end flow that ties Carriyo's checkout-time delivery options to the order allocation engine. The shopper picks a delivery option on your storefront. You pass the chosen option's code back to Carriyo when creating the order. Carriyo's allocation engine uses the option to constrain which fulfillment locations are eligible.

Scenario

A customer in London is checking out two items in a £763.74 cart. After entering the delivery address, your storefront calls Carriyo to fetch the delivery options that match the cart and the address. The customer picks Express Delivery. You then create the order in Carriyo, passing the delivery_option.code so allocation knows which option was sold.

Prerequisites

  • API credentials: see Getting started for the one-time setup.
  • At least one delivery option configured for the merchant in the Dashboard, with associated fulfillment locations whose coverage includes the customer's address.
  • Automatic allocation enabled in the tenant's order management settings (enable_automatic_order_allocation); it is off until those settings are created. With inventory management enabled, stock at one or more of the option's fulfillment locations.

1. Fetch delivery options

Call Carriyo with the cart, the customer's address, and the set of fulfillment locations you want to consider. The locations passed in are the candidate pool; Carriyo intersects them with the locations configured on each delivery option.

curl -X POST 'https://api.carriyo.com/storefront/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",
    "delivery_methods": ["DELIVERY"],
    "payment": {
      "currency": "GBP",
      "order_total": 763.74
    },
    "line_items": [
      {
        "product_ref": "SKU-CAM-001",
        "quantity": 1,
        "weight": { "value": 0.5, "unit": "kg" }
      },
      {
        "product_ref": "SKU-LAP-002",
        "quantity": 1,
        "weight": { "value": 1.5, "unit": "kg" }
      }
    ],
    "customer": {
      "country": "GB",
      "city": "London",
      "address1": "45 Gloucester Place",
      "postcode": "W1U 8HU",
      "contact_name": "Oliver Bennett"
    },
    "fulfillment_locations": [
      { "partner_location_code": "WH-UK-01" },
      { "partner_location_code": "STORE-UK-LON-01" },
      { "partner_location_code": "STORE-UK-MAN-01" },
      { "partner_location_code": "STORE-UK-EDI-01" },
      { "partner_location_code": "STORE-UK-BHM-01" }
    ]
  }'

The response is a list of options that passed every condition the merchant configured (geographic, weight, value, etc.). Each entry also carries the fulfillment_locations that can serve it and per-item availability in items, omitted here. shipping_fee is an empty object when no price could be resolved, which is not the same as free, and estimated_arrival_to is absent when the option has no promise:

[
  {
    "id": "012694a1-04af-42fd-ba4d-beeaca2034ed",
    "delivery_method": "DELIVERY",
    "code": "EXPRESS_DELIVERY",
    "name": "Express Delivery",
    "carrier_account_id": "782b9b83-6d95-4468-8998-38f28b5a7c11",
    "description": "Next-day delivery across the UK.",
    "shipping_fee": { "amount": 4.99, "currency": "GBP" },
    "estimated_arrival_to": "2026-05-10T18:00:00.000Z"
  },
  {
    "id": "f29acd11-34c2-4874-96f6-4a2530a82886",
    "delivery_method": "DELIVERY",
    "code": "PREMIUM_LONDON",
    "name": "Premium London Delivery",
    "carrier_account_id": "1ee1b219-d64e-4e67-8bc4-ff1c8c955457",
    "description": "Same-day delivery within Greater London.\nFree for orders over £50.",
    "shipping_fee": { "amount": 9.99, "currency": "GBP" },
    "estimated_arrival_to": "2026-05-09T18:00:00.000Z"
  }
]

Render each entry as a delivery choice on the checkout. Show name, description, shipping_fee, and estimated_arrival_to.

2. Capture the customer's choice

The customer picks Express Delivery. Persist the option's code (EXPRESS_DELIVERY) on the cart. The code is the bridge to the order create call: it's stable across deployments, whereas the option's id is mutable.

3. Create the order

Submit the order to Carriyo with delivery_option.code set to the chosen option. Identify each product by sku or product_ref; Carriyo fills in its own product_id on the response:

curl -X POST 'https://api.carriyo.com/orders' \
  -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",
    "partner_order_reference": "YOUR_ORDER_REF",
    "delivery_option": { "code": "EXPRESS_DELIVERY" },
    "order_date": "2026-05-08T07:40:08.477Z",
    "sales_channel": "web",
    "payment": {
      "currency": "GBP",
      "order_total": 763.74
    },
    "customer": {
      "contact_name": "Oliver Bennett",
      "contact_email": "oliver.bennett@example.co.uk",
      "contact_phone": "+44 7700 900123"
    },
    "delivery_address": {
      "contact_name": "Oliver Bennett",
      "contact_email": "oliver.bennett@example.co.uk",
      "contact_phone": "+44 7700 900123",
      "address1": "45 Gloucester Place",
      "address2": "Marylebone",
      "city": "London",
      "country": "GB",
      "postcode": "W1U 8HU"
    },
    "billing_address": {
      "contact_name": "Oliver Bennett",
      "contact_email": "oliver.bennett@example.co.uk",
      "contact_phone": "+44 7700 900123",
      "address1": "45 Gloucester Place",
      "address2": "Marylebone",
      "city": "London",
      "country": "GB",
      "postcode": "W1U 8HU"
    },
    "line_items": [
      {
        "sku": "SKU-CAM-001",
        "description": "Action Camera",
        "quantity": 1,
        "unit_price": 309.29
      },
      {
        "sku": "SKU-LAP-002",
        "description": "Laptop 14-inch",
        "quantity": 1,
        "unit_price": 454.45
      }
    ]
  }'

The response, abridged here, is the created order with allocation already applied. Carriyo used the chosen delivery option to constrain location selection. The option is recorded on each fulfillment order, not on the order itself:

{
  "tenant": "your-tenant",
  "order_id": "OMOX893M9QYBBD5",
  "merchant": "ACME",
  "partner_order_reference": "YOUR_ORDER_REF",
  "order_date": "2026-05-08T07:40:08.477Z",
  "sales_channel": "web",
  "status": "allocated",
  "payment": { "currency": "GBP", "order_total": 763.74 },
  "customer": {
    "contact_name": "Oliver Bennett",
    "contact_phone": "+44 7700 900123",
    "contact_email": "oliver.bennett@example.co.uk"
  },
  "billing_address": {
    "contact_name": "Oliver Bennett",
    "contact_phone": "+44 7700 900123",
    "contact_email": "oliver.bennett@example.co.uk",
    "address1": "45 Gloucester Place",
    "address2": "Marylebone",
    "city": "London",
    "postcode": "W1U 8HU",
    "country": "GB"
  },
  "line_items": [
    {
      "id": "VUV7D",
      "sku": "SKU-CAM-001",
      "product_ref": "SKU-CAM-001",
      "product_id": "PDTHDMCY4YN4Z7L0Q",
      "quantity": 1,
      "unit_price": 309.29
    },
    {
      "id": "7OL4C",
      "sku": "SKU-LAP-002",
      "product_ref": "SKU-LAP-002",
      "product_id": "PDTHDMCY4YN4Z7L0R",
      "quantity": 1,
      "unit_price": 454.45
    }
  ],
  "fulfillment_orders": [
    {
      "fulfillment_order_id": "FOMOX893VJAMFZCK",
      "fulfillment_location": {
        "partner_location_id": "ACCOUNT_b5c325c0-edeb-4559-803c-d1b0ca3ec9c2",
        "partner_location_code": "LDN-WH-01",
        "partner_location_name": "London Warehouse"
      },
      "status": "allocated",
      "delivery_method": "DELIVERY",
      "delivery_option": {
        "code": "EXPRESS_DELIVERY",
        "id": "012694a1-04af-42fd-ba4d-beeaca2034ed",
        "name": "Express Delivery"
      },
      "delivery_address": {
        "contact_name": "Oliver Bennett",
        "address1": "45 Gloucester Place",
        "address2": "Marylebone",
        "city": "London",
        "postcode": "W1U 8HU",
        "country": "GB"
      },
      "line_items": [{ "id": "VUV7D", "quantity": 1, "status": "allocated" }],
      "creation_date": "2026-05-08T18:07:11.621Z"
    },
    {
      "fulfillment_order_id": "FOMOX893VJEIWVQ9",
      "fulfillment_location": {
        "partner_location_id": "ACCOUNT_64c72d0e-19f5-4ec1-b572-d51c97688606",
        "partner_location_code": "MAN-WH-01",
        "partner_location_name": "Manchester Warehouse"
      },
      "status": "allocated",
      "delivery_method": "DELIVERY",
      "delivery_option": {
        "code": "EXPRESS_DELIVERY",
        "id": "012694a1-04af-42fd-ba4d-beeaca2034ed",
        "name": "Express Delivery"
      },
      "delivery_address": {
        "contact_name": "Oliver Bennett",
        "address1": "45 Gloucester Place",
        "address2": "Marylebone",
        "city": "London",
        "postcode": "W1U 8HU",
        "country": "GB"
      },
      "line_items": [{ "id": "7OL4C", "quantity": 1, "status": "allocated" }],
      "creation_date": "2026-05-08T18:07:11.621Z"
    }
  ],
  "creation_date": "2026-05-08T18:07:11.505Z"
}

What just happened

  • The order was accepted and immediately moved to allocated.
  • Allocation produced two fulfillment orders because the two line items couldn't all ship from a single location. The Action Camera came from one location and the Laptop from another.
  • Both FOs carry the chosen delivery_option (EXPRESS_DELIVERY). The allocation engine considered only the locations associated with that option, so location selection respected the customer's choice.
  • Each FO holds its own delivery_address (same in this case because the customer picked one shipping address). With a cross-merchant or multi-destination order, FOs can carry different addresses. See the Fulfillment orders page.

Fulfilling an FO creates and books its shipment.

Pitfalls

  • Pass code, not id. The delivery_option.code is your stable identifier. The id (UUID) changes if a merchant deletes and recreates an option.
  • Allocation can fail. If the chosen delivery option's associated locations don't carry inventory for the items, the order may land in partially_allocated, or its fulfillment order may carry auto_allocation_failed. Listen for the order webhook and escalate a fallback to ops.
  • Currency must match. The currency on the delivery options request, the option, and the order create payload must match.