> Portal Navigation:
> 
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt

## Resource: Restaurants Menus and Ordering

## Article: Restaurants Menus and Ordering

## Article Link: https://dev.wix.com/docs/api-reference/business-solutions/restaurants/skills/restaurants-menus-and-ordering.md

## Article Content:

# RECIPE: Read the Menu and Order Food

## When to use this recipe

- "What's for breakfast and what does it cost?" / "Do you have anything with cardamom?" / "Something vegetarian under 60"
- "Can I order online? Pickup or delivery? Fees?" / "My order is 40, can I get it delivered?"
- "Add 2 flat whites and a shakshuka for pickup" / "Add a cookie, show my order and the total"
- "Check out my café order"

Table reservations and experiences are a different app — see `Table-Reservations.skill.md`.

## Inputs you need before STEP 4

| Input | How to get it |
|---|---|
| Visitor token | STEP 1 |
| Menu `id`, its ordered `sectionIds`; section `id`s with ordered `itemIds`; item `id`, `name`, `description`, `priceInfo.price` | STEP 2 (three list calls, assembled client-side) |
| `operationId` of the ENABLED ordering operation | STEP 3 |
| Fulfillment methods (name, type, `fee`, `minOrderPrice`) | STEP 3 |
| Cart line `id`s (quantity changes) | STEP 4 response |

## Decision tree

- **Menu questions** ("what's for breakfast", "anything with X", "under N shekels") → STEP 1 + STEP 2, answer from the assembled tree; group by section **in `sectionIds` order**.
- **"Can I order online / delivery fees / minimum?"** → STEP 3.
- **"Add X to my order"** → STEP 2 (ids) + STEP 3 (`operationId`) → STEP 4 → STEP 5 (totals).
- **"Can I get it delivered for N?"** → compare N with the DELIVERY method's `minOrderPrice` from STEP 3.
- **"Check out"** → STEP 6. Pickup/delivery time is chosen on the hosted checkout, not through the API.

---

## STEP 1: Get a visitor token

`GenerateVisitorToken` once; reuse it. The cart is bound to the token.

---

## STEP 2: Read the menu tree

Three visitor-readable GETs on `https://www.wixapis.com/restaurants/menus/v1/`:

```bash
curl 'https://www.wixapis.com/restaurants/menus/v1/menus?onlyVisible=true'    -H 'Authorization: <VISITOR_TOKEN>'
curl 'https://www.wixapis.com/restaurants/menus/v1/sections?onlyVisible=true' -H 'Authorization: <VISITOR_TOKEN>'
curl 'https://www.wixapis.com/restaurants/menus/v1/items?onlyVisible=true'    -H 'Authorization: <VISITOR_TOKEN>'
```

```jsonc
// menus
{ "menus": [{ "id": "7e7c573d-…", "name": "Studio Café", "visible": true, "sectionIds": ["511f021b-…", "8a63287c-…", …] }] }
// sections
{ "sections": [{ "id": "511f021b-…", "name": "Morning", "description": "Served until noon.", "itemIds": ["…", "…"] }] }
// items
{ "items": [{ "id": "…", "name": "Green Shakshuka", "description": "Eggs poached in spinach…",
              "priceInfo": { "price": "58.00", "formattedPrice": "₪58.00" }, "labels": [], "image": { … } }] }
```

**Assemble bottom-up and keep the id order**: `menu.sectionIds → section`, `section.itemIds → item`. The flat `sections`/`items` arrays are in creation order, not display order. Skip ids that don't resolve (deleted). Quote `priceInfo.formattedPrice` (REST includes it). `labels` (vegan, spicy…) are usually empty — infer dietary answers from `description` and say so.

---

## STEP 3: Is ordering on, and how is food delivered?

```bash
curl 'https://www.wixapis.com/restaurants-operations/v1/operations' -H 'Authorization: <VISITOR_TOKEN>'
curl 'https://www.wixapis.com/fulfillment-methods/v1/fulfillment-methods' -H 'Authorization: <VISITOR_TOKEN>'
```

```jsonc
{ "operations": [{ "id": "48605ac5-…", "default": true, "onlineOrderingStatus": "ENABLED",   // ← operationId for STEP 4
                   "fulfillmentIds": ["…"], "defaultFulfillmentType": "PICKUP" }] }
{ "fulfillmentMethods": [
  { "id": "…", "name": "Delivery", "type": "DELIVERY", "enabled": true, "fee": "15", "minOrderPrice": "60", "deliveryOptions": { "deliveryTimeInMinutes": 60, "deliveryArea": { … } } },
  { "id": "…", "name": "Pickup",   "type": "PICKUP",   "enabled": true, "minOrderPrice": "0", "pickupOptions": { … } },      // "fee" may be absent → 0
  { "id": "…", "name": "DoorDash Drive", "type": "DELIVERY", "enabled": false }
] }
```

- Ordering is possible when at least one operation has `onlineOrderingStatus: "ENABLED"`. `PAUSED_UNTIL`/`DISABLED` → say ordering is closed.
- Show only `enabled: true` methods. `fee` and `minOrderPrice` are decimal strings in the site currency; a missing `fee` means 0.
- "Order of ₪40 delivered?" → `40 < minOrderPrice(60)` → no; offer pickup (no minimum) or suggest adding items.

---

## STEP 4: Add dishes to the cart

`POST https://www.wixapis.com/ecom/v1/carts/current/add-to-cart` with the **Restaurants Orders app id** and **all three** of `operationId`, `menuId`, `sectionId` in `options`:

```bash
curl -X POST 'https://www.wixapis.com/ecom/v1/carts/current/add-to-cart' \
-H 'Authorization: <VISITOR_TOKEN>' -H 'Content-Type: application/json' \
-d '{ "lineItems": [
  { "catalogReference": { "catalogItemId": "<ITEM_ID>", "appId": "9a5d83fd-8570-482e-81ab-cfa88942ee60",
      "options": { "operationId": "<OPERATION_ID>", "menuId": "<MENU_ID>", "sectionId": "<SECTION_ID>" } }, "quantity": 2 },
  { "catalogReference": { "catalogItemId": "<ITEM_ID_2>", "appId": "9a5d83fd-8570-482e-81ab-cfa88942ee60",
      "options": { "operationId": "<OPERATION_ID>", "menuId": "<MENU_ID>", "sectionId": "<SECTION_ID_2>" } }, "quantity": 1 }
] }'
```

→ `cart.lineItems[]` with `id`, `productName.original` ("Flat White"), `quantity`, `price.formattedAmount`. Use the **section the dish is shown under** (from STEP 2), not any section that happens to contain it. Shop products can share the same cart (different `appId`).

---

## STEP 5: Totals and changes

```bash
curl -X POST 'https://www.wixapis.com/ecom/v1/carts/current/estimate-totals' -H 'Authorization: <VISITOR_TOKEN>' -H 'Content-Type: application/json' -d '{}'
```
→ `priceSummary.subtotal.formattedAmount` / `total.formattedAmount` (₪104.00 for 2 flat whites + shakshuka + cookie). Quantity and removal calls are the same as the shop recipe (`update-line-items-quantity`, `remove-line-items`).

---

## STEP 6: Checkout

`POST https://www.wixapis.com/ecom/v1/carts/current/create-checkout` `{ "channelType": "WEB" }` → `checkoutId`. Then create a redirect session (`POST /_api/redirects-api/v1/redirect-session` with `ecomCheckout.checkoutId`) and give the visitor `redirectSession.fullUrl`. The hosted checkout is where pickup vs delivery and the time slot are chosen. The `checkoutUrl` from `GET /ecom/v1/checkouts/{id}/checkout-url` is a `/checkout?checkoutId=` page that headless sites don't have — don't send visitors there.

Completing a **paid** order needs a payment provider on the site; on a site without one, say the order can be placed but payment isn't available online yet.

---

## Common errors and how to avoid them

### 1. Cart rejects the dish / item never resolves

`options` is missing `operationId`, `menuId` or `sectionId`, or you used the **Stores** app id. Restaurants dishes use `9a5d83fd-8570-482e-81ab-cfa88942ee60`. There is no `variantId` here.

### 2. Sections or dishes in the wrong order

You rendered the flat list arrays. Order comes from `menu.sectionIds` and `section.itemIds`.

### 3. "Add to cart" docs search returns *Create Order* / *Create Item*

Those are management endpoints. The visitor path is always the eCommerce **current cart** with the triple above.

### 4. `fee` is `undefined` on Pickup

Treat a missing fee as 0; only DELIVERY carries a fee and a minimum.

### 5. Answering dietary questions with certainty

Items have no dietary labels on most sites; say "based on the description" when inferring vegetarian/vegan.

### 6. `ExecuteWixAPI` masks failures as "Visitor token rejected (HTTP 403)"

Re-run the single failing call through `CallWixSiteAPI` to see the real 4xx body before reacting; never mint a new token mid-cart.

---

## Constants

| Constant | Value |
|---|---|
| Restaurants Orders (New) app id (cart `catalogReference.appId` for dishes) | `9a5d83fd-8570-482e-81ab-cfa88942ee60` |
| Restaurants Menus app id | `b278a256-2757-4f19-9313-c05c783bec92` |
| Menus base URL | `https://www.wixapis.com/restaurants/menus/v1/` (`menus`, `sections`, `items`) |

---

## References

- [List Menus](https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/menus/list-menus.md) · [List Sections](https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/sections/list-sections.md) · [List Items](https://dev.wix.com/docs/api-reference/business-solutions/restaurants/menus/items/items/list-items.md)
- [List Operations](https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-ordering/operations/list-operations.md)
- [List Fulfillment Methods](https://dev.wix.com/docs/api-reference/business-solutions/restaurants/online-ordering/fulfillment-methods/list-fulfillment-methods.md)
- [Add To Current Cart](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart/current-cart/add-to-current-cart.md)
- [Create Checkout From Current Cart](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart/current-cart/create-checkout-from-current-cart.md)