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

# Display Menu

> Fetch menus, categories, and products for a location.

This guide covers how to load a restaurant's menu data and display it in your storefront — including multiple menus, category filtering, and product details.

## How menus work

Every Crave location has one or more **menus**. Each menu contains **categories**, and each category links to **products**. The active menu depends on the current time and the location's schedule.

```
Merchant → Location → Menu(s) → Categories → Products → Modifiers
```

## Fetch location data

The location response includes basic metadata. Menu and product data comes from the ordering session and API endpoints.

<CodeGroup>
  ```ts SDK theme={null}
  import { storefront } from '@/lib/storefront';

  const location = await storefront.locations.getById('loc_123');
  console.log(location.restaurantDisplayName);

  ```

  ```bash REST theme={null}
  curl "https://api.craveup.com/api/v1/storefront/locations/loc_123"
  ```
</CodeGroup>

## Start a session to get the menu

Menus are anonymous published resources. Start an ordering session only when the customer begins a cart; the response includes the cart capability used for later cart operations.

<CodeGroup>
  ```ts SDK theme={null}
  const session = await storefront.orderingSessions.start('loc_123', {
    marketplaceId: 'web',
    fulfillmentMethod: 'takeout',
  });

  const menu = await storefront.menus.list('loc_123', {});

  ```

  ```bash REST theme={null}
  curl -X POST "https://api.craveup.com/api/v1/storefront/locations/loc_123/ordering-sessions" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: session_01" \
    -d '{"marketplaceId":"web","fulfillmentMethod":"takeout"}'
  ```
</CodeGroup>

`marketplaceId` is optional source attribution, such as `"web"`; it is not the
location identifier. The route already provides the location scope.

## Display categories

Categories are used to group products (e.g., "Appetizers", "Mains", "Drinks"). Render them as tabs or a sidebar.

```tsx filename="components/CategoryTabs.tsx" theme={null}
interface Category {
  id: string;
  name: string;
  productIds: string[];
}

function CategoryTabs({
  categories,
  activeId,
  onSelect,
}: {
  categories: Category[];
  activeId: string;
  onSelect: (id: string) => void;
}) {
  return (
    <div className="flex gap-2 overflow-x-auto">
      {categories.map((cat) => (
        <button
          key={cat.id}
          onClick={() => onSelect(cat.id)}
          className={`px-4 py-2 rounded-full text-sm whitespace-nowrap ${
            cat.id === activeId
              ? "bg-teal-600 text-white"
              : "bg-gray-100 text-gray-700"
          }`}
        >
          {cat.name}
        </button>
      ))}
    </div>
  );
}
```

## Display products

Each product includes a name, description, price, images, and modifier groups.

```tsx filename="components/ProductCard.tsx" theme={null}
interface Product {
  id: string;
  name: string;
  description: string;
  price: string;
  displayPrice: string;
  images: string[];
}

function ProductCard({
  product,
  onAdd,
}: {
  product: Product;
  onAdd: () => void;
}) {
  return (
    <div className="flex gap-4 p-4 border rounded-lg">
      {product.images[0] && (
        <img
          src={product.images[0]}
          alt={product.name}
          className="w-20 h-20 rounded-lg object-cover"
        />
      )}
      <div className="flex-1">
        <h3 className="font-medium">{product.name}</h3>
        <p className="text-sm text-gray-500 line-clamp-2">
          {product.description}
        </p>
        <div className="flex justify-between items-center mt-2">
          <span className="font-semibold">{product.displayPrice}</span>
          <button
            onClick={onAdd}
            className="px-3 py-1 bg-teal-600 text-white rounded text-sm"
          >
            Add
          </button>
        </div>
      </div>
    </div>
  );
}
```

## Filter and search

Crave menus are returned as structured data. You can implement client-side filtering:

```ts theme={null}
// Filter products by category
const categoryProducts = products.filter((p) =>
  activeCategory.productIds.includes(p.id)
);

// Search by name
const searchResults = products.filter((p) =>
  p.name.toLowerCase().includes(query.toLowerCase())
```

## Get order times

Fetch the available time slots for ASAP or scheduled orders.

<CodeGroup>
  ```ts SDK theme={null}
  const orderTimes = await storefront.locations.getOrderTimes('loc_123');

  if (orderTimes.requireScheduledOrders) {
  // Show day/time picker from orderTimes.orderDays
  } else {
  // ASAP is available; optionally show schedule option
  console.log('Schedule allowed:', orderTimes.scheduleAllowed);
  }

  ```

  ```bash REST theme={null}
  curl "https://api.craveup.com/api/v1/storefront/locations/loc_123/time-intervals"
  ```
</CodeGroup>

## Product types

The SDK exports these types for working with menu data:

| Type           | Description                                                    |
| -------------- | -------------------------------------------------------------- |
| `Menu`         | Top-level menu with `id`, `name`, `isActive`, and `categories` |
| `Category`     | Grouping with `id`, `name`, and `productIds`                   |
| `Product`      | Full product with price, images, modifiers, and nutrition      |
| `Modifier`     | Modifier group with selection rules and items                  |
| `ModifierItem` | Individual modifier option with price and max quantity         |

## Next steps

<CardGroup cols={2}>
  <Card title="Manage Cart" icon="cart-shopping" href="/guides/manage-cart">
    Add products to the cart with modifier selections.
  </Card>

  <Card title="Checkout Flow" icon="credit-card" href="/guides/checkout-flow">
    Collect customer details and process payments.
  </Card>
</CardGroup>
