> ## 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 -X GET "https://api.craveup.com/api/v1/locations/loc_123" \
    -H "X-API-Key: $CRAVEUP_API_KEY"
  ```
</CodeGroup>

## Start a session to get the menu

Starting an ordering session gives you a `cartId` and loads the menu for the current time. The menus, categories, and products are returned as part of the location's data model.

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

  // The session creates a cart; use the location endpoint
  // to fetch categories and products
  const location = await storefront.locations.getById('loc_123');
  ```

  ```bash REST theme={null}
  curl -X POST "https://api.craveup.com/api/v1/locations/loc_123/ordering-sessions" \
    -H "X-API-Key: $CRAVEUP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"marketplaceId": "loc_123"}'
  ```
</CodeGroup>

## 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 -X GET "https://api.craveup.com/api/v1/locations/loc_123/time-intervals" \
    -H "X-API-Key: $CRAVEUP_API_KEY"
  ```
</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>
