> ## Documentation Index
> Fetch the complete documentation index at: https://help.atlas.kitchen/llms.txt
> Use this file to discover all available pages before exploring further.

# Delivery outlets

> Only available when cart fulfilment_type is delivery.



## OpenAPI

````yaml get /cart/delivery_outlets
openapi: 3.1.0
info:
  title: Atlas Storefront API
  version: 1.0.0
  description: ''
servers:
  - url: https://api.atlas.kitchen/storefronts/v1
    description: Storefront API
security:
  - channelId: []
    sessionId: []
tags:
  - name: Introduction
    description: >
      The Atlas Storefront API powers online ordering for food and beverage
      merchants. Each merchant on Atlas operates one or more **outlets**
      (physical locations), each with its own menus, service hours, delivery
      zones, and payment processing.


      This API lets you build a complete ordering experience on top of Atlas:


      - **Browse** a merchant's menus with sections, items, modifiers, and
      real-time stock

      - **Build** a cart with configurable items, promo codes, and loyalty
      points

      - **Pay** via a hosted payment page with real-time confirmation

      - **Confirm** orders with a single API call after payment


      ### How it works


      Every merchant has a **channel** — a unique identifier representing their
      storefront (website, app, kiosk, etc.). The channel determines which
      outlets, menus, and branding the diner sees. You receive a channel ID when
      a merchant is onboarded.


      The API is stateless from your perspective. You pass the channel ID, the
      API gives you a session, and from there you can browse menus, build a
      cart, and check out — all without user accounts or login.


      ### Conventions


      **Monetary values** — All monetary fields (`price_cents`, `subtotal`,
      `total`, `tax`, `delivery_fee`, etc.) are integers in **minor currency
      units** (e.g. cents). `1580` = $15.80 SGD.


      **Timeslots** — Time values (`timeslot_start`, `timeslot_end`,
      `service_start`, `service_end`) are in **seconds since midnight**. `36000`
      = 10:00 AM.


      **Errors** — All errors follow a consistent structure:

      ```json

      {
        "type": "Invalid Parameter",
        "message": "Human-readable description",
        "details": [
          { "field": "item_id", "message": "must exist" }
        ]
      }

      ```
  - name: Authentication
    description: >
      ### Channel ID


      Every request must include an `X-Channel-Id` header. This identifies which
      merchant's storefront you're accessing — it determines the outlets, menus,
      branding, and payment configuration the diner sees.


      You receive the channel ID when a merchant is onboarded to Atlas. It is a
      fixed identifier, not a secret.


      ### Sessions


      The API automatically creates a session on your first request and returns
      it in the `X-Session-Id` response header. This session tracks the diner's
      cart.


      ```bash

      # First request — only X-Channel-Id needed

      curl -sD - https://api.example.com/storefronts/v1/channel \
        -H "X-Channel-Id: your-channel-id"
      ```


      ```

      # Response header — save this

      X-Session-Id: b7ac755d301dc5d23c790ccd7bb6dadf

      ```


      Include both headers on all subsequent requests:


      | Header | What it is | Where it comes from |

      |--------|-----------|-------------------|

      | `X-Channel-Id` | Merchant's storefront identifier | Provided during
      onboarding |

      | `X-Session-Id` | Diner's session (tracks cart) | Auto-created, returned
      in first response header |


      Sessions are lightweight — they hold a reference to the diner's active
      cart. When an order is placed, the session gets a new empty cart
      automatically.
  - name: Checkout Flow
    description: >
      The complete ordering flow from menu to confirmed order:


      <img src="/checkout-flow.svg" alt="Checkout Flow"
      style="width:100%;max-width:100%" />


      ### After payment


      Once the diner completes payment on the hosted page and is redirected back
      to your app, call `POST /cart/order`.


      This endpoint validates the payment **in real-time** — it makes a
      synchronous call to the payment processor to check status. It does **not**
      depend on webhooks.


      - **Payment succeeded** → cart converts to a confirmed order, full order
      object returned

      - **Payment not completed** → `422` with `"Insufficient payment made to
      the cart"`


      No polling needed. No webhook waiting. Just one call.
  - name: Channel
    description: >
      Retrieve merchant configuration, outlet details, service hours, delivery
      fees, and content (announcements, banners, popups).


      Start here — `GET /channel` gives you the outlets you can order from,
      including their coordinates, service hours, and delivery fee structure.
  - name: Menu
    description: >
      Browse menus for a specific outlet and serving date. Returns the full
      catalog: sections, items with prices, configurable items with modifier
      groups, stock levels, timeslots, and availability.


      ### How menus are structured


      ```

      Menu

      ├── sections[]           → categories (Mains, Sides, Drinks)

      │   ├── products[]       → item IDs + display_order

      │   └── sub_sections[]   → nested categories

      └── products{}           → full item details keyed by ID
          ├── price_cents
          ├── is_configurable
          └── item_modifier_groups[]  → modifier groups with options
      ```


      Use `sections[].products[].id` to look up full item details in the
      `products{}` map.
  - name: Cart
    description: >
      Manage the shopping cart — create, configure, add/remove items, apply
      promos, and review pricing.


      ### Cart lifecycle


      1. `POST /cart` — create empty cart

      2. `PATCH /cart` — set outlet, fulfilment type, timeslot, contact details

      3. `POST /cart/items` — add items (with optional modifiers via
      `sub_items`)

      4. `GET /cart/payment_breakdown` — review subtotal, tax, fees, discounts

      5. `POST /cart/validation` — verify cart is ready for checkout


      ### Adding items with modifiers


      For configurable items (`is_configurable: true`), pass modifiers as
      `sub_items`:


      ```json

      {
        "item_id": 1,
        "quantity": 2,
        "sub_items": [
          {
            "item_id": 2,
            "modifier_id": 1,
            "item_modifier_group_id": 1,
            "quantity": 1
          }
        ]
      }

      ```


      Get `modifier_id` and `item_modifier_group_id` from the menu's
      `item_modifier_groups`.
  - name: Payment
    description: >
      Create a payment intent to generate a hosted payment page URL.


      ### Flow


      1. Call `POST /payment_intents` → receive `atlas_pay_url`

      2. Redirect the diner to `atlas_pay_url`

      3. Diner enters payment details and pays

      4. Diner is redirected back to your app

      5. Call `POST /cart/order` to confirm (see **Order**)


      If a pending payment intent already exists for the same cart amount, the
      existing one is returned instead of creating a duplicate.
  - name: Order
    description: >
      Convert a paid cart into a confirmed order.


      Call `POST /cart/order` after the diner completes payment. This endpoint:


      1. Validates the cart (items, timeslot, minimum order)

      2. Checks payment status **in real-time** against the payment processor

      3. Converts the cart to a confirmed order


      On success, returns the full order object. The session automatically gets
      a fresh empty cart for the next order.


      If called before payment completes, returns `422` with a clear error
      message.
paths:
  /cart/delivery_outlets:
    get:
      tags:
        - Cart
      summary: Delivery outlets
      description: Only available when cart fulfilment_type is delivery.
      operationId: listDeliveryOutlets
      responses:
        '200':
          description: Delivery-capable outlets
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DeliveryOutlet'
              example:
                - id: 1
                  name: Aviato Burger - McNair
                  distance: 2400
                  address: 51 McNair Rd, Singapore
                  status: OPEN
        '422':
          description: Cart is not set to delivery fulfilment
components:
  schemas:
    DeliveryOutlet:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        distance:
          type: integer
          description: Meters
        address:
          type: string
        status:
          type: string
          enum:
            - OPEN
            - CLOSED
  securitySchemes:
    channelId:
      type: apiKey
      in: header
      name: X-Channel-Id
      description: Merchant storefront identifier. Provided during onboarding.
    sessionId:
      type: apiKey
      in: header
      name: X-Session-Id
      description: >-
        Diner session identifier. Created by `GET /channel` and returned in the
        `X-Session-Id` response header.

````