Skip to content

JavaScript Checkouts ​

For checkouts that update without page loads, Delivery Slots has two actions for the current cart.

Get the slots ​

js
const response = await fetch('/actions/delivery-slots/slots/days', {
  headers: { Accept: 'application/json' },
})
const { chosen, days } = await response.json()

Add ?shippingMethodHandle=pickup for a method the cart hasn’t chosen yet.

json
{
  "chosen": "2026-11-17@10:00",
  "days": [
    {
      "date": "2026-11-16",
      "available": true,
      "unavailableReason": null,
      "slots": [
        { "value": "2026-11-16@08:00", "start": "08:00", "end": "10:00", "label": "8 – 10am", "left": 6, "full": false, "fee": 0 }
      ]
    },
    { "date": "2026-11-22", "available": false, "unavailableReason": "Closed", "slots": [] }
  ]
}

Choose a slot ​

js
const body = new FormData()
body.append(window.csrfTokenName, window.csrfTokenValue)
body.append('deliverySlot', '2026-11-17@10:00')

const response = await fetch('/actions/delivery-slots/slots/choose', {
  method: 'POST',
  headers: { Accept: 'application/json' },
  body,
})
const data = await response.json()
// Success: { message: 'Delivery time saved.', deliverySlot: '2026-11-17@10:00', label: 'Tuesday 17 November, 10am – 12pm' }
// Failure (status 400): { message: 'That delivery time is no longer available. Choose another.' }

Output the CSRF token name and value into the page for this:

twig
<script>
  window.csrfTokenName = '{{ craft.app.config.general.csrfTokenName }}';
  window.csrfTokenValue = '{{ craft.app.request.csrfToken }}';
</script>

Choosing a slot also recalculates the cart, so a zone fee shows in its totals. Post an empty deliverySlot to clear it.

You can also post deliverySlot with Commerce’s own commerce/cart/update-cart action over Ajax, along with other cart changes.

In Commerce’s cart JSON ​

Commerce’s cart actions, such as commerce/cart/update-cart and commerce/cart/get-cart with Accept: application/json, return the cart with two more keys:

json
{
  "cart": {
    "hasDeliverySlots": true,
    "deliverySlot": {
      "value": "2026-11-16@08:00",
      "label": "Monday 16 November, 8 – 10am",
      "timeLabel": "8 – 10am",
      "date": "2026-11-16",
      "start": "08:00",
      "end": "10:00",
      "fee": 0,
      "zoneId": 281,
      "isBooked": false
    }
  }
}

deliverySlot is null until a slot is chosen.

Commerce doesn’t have orders or carts in its GraphQL API, so headless checkouts use these actions.

A complete picker is in the JavaScript example.

A Craft Commerce plugin by Suprim