> This page is for API Reference.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.navipartner.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.navipartner.com/_mcp/server.

# Get Menu

GET https://api.npretail.app/{tenant}/{environment}/{company}/restaurant/{restaurantId}/menu/{menuId}

Get a specific menu with full details including categories, items, addons, and translations

Reference: https://docs.navipartner.com/apis/api-reference/restaurant/menu/get-menu

## Authentication

- `x-np-api-key` header (required) — API Key authentication via header

## Request

### Path parameters

- `tenant` (string, required) — Your Entra Tenant ID. [More details.](/paths#1-tenant)
- `environment` (string, required) — Your Business Central Environment. [More details.](/paths#2-environment)
- `company` (string, required) — Your Business Central Company. [More details.](/paths#3-company)
- `restaurantId` (UUID, required) — The restaurant system ID
- `menuId` (UUID, required) — The menu system ID

### Query parameters

- `vatBusinessPostingGroup` (string, optional) — Optional VAT Business Posting Group override. When provided, each menu item's unit price is recomputed using the VAT Posting Setup formed by this override + the item's VAT Product Posting Group instead of the item's default VAT setup. Typical use: exposing EU / international VAT-exempt prices to self-service clients. Returns 400 if the override is not a known VAT Business Posting Group, or if a menu item's VAT Product Posting Group has no matching VAT Posting Setup under the override — in the latter case the error text names the offending item so the caller can surface it directly.

## Response

### 200

- `id` (UUID, required) — The unique system identifier for the menu
- `code` (string, required) — The menu code
- `startTime` (string, required) — When the menu becomes active (HH:MM:SS format)
- `endTime` (string, required) — When the menu stops accepting orders (HH:MM:SS format)
- `timezone` (string, required) — The timezone for the menu times
- `active` (boolean, required) — Whether the menu is currently active
- `lastUpdated` (datetime, required) — Cache key for the menu payload (UTC). Moves whenever anything the payload carries changes, prices included, and is never older than the start of the server day.
- `menuContent` (MenuContent, required) — Complete menu structure with categories, items, and upsells

## Types

### MenuContent

Complete menu structure with categories, items, and upsells

- `categories` (list of Category, required) — Menu categories with their items
- `checkoutUpsellItems` (list of UpsellItem, required) — Items shown as upsells during checkout. Only items that also appear in the menu categories are returned, so Inactive Hidden items are left out.
- `addonCategories` (map from string to AddonCategory, required) — Addon category definitions keyed by category code

### Category

Menu category grouping items

- `code` (string, required) — Category code
- `sortKey` (integer, required) — Sort order for display
- `title` (map from string to string, required) — Category title translations
- `description` (map from string to string, required) — Category description translations
- `items` (list of MenuItem, required) — Items in this category

### UpsellItem

Upsell suggestion item

- `itemCode` (string, required) — Business Central item number
- `variantCode` (string, required) — Item variant code
- `sortKey` (integer, required) — Sort order for display
- `unitPrice` (double, required) — Item price
- `title` (map from string to string, required) — Item title translations
- `descriptionMarkdown` (map from string to string, required) — Item description in markdown format
- `nutritionMarkdown` (map from string to string, required) — Nutritional information in markdown format
- `status` (enum, optional) — Status of the menu item behind the upsell. Active items can be ordered. Inactive Visible items are shown but cannot be ordered. Inactive Hidden items are never returned as upsells.
  - Allowed values: `Active`, `Inactive Visible`, `Inactive Hidden`
- `imageUrl` (string, optional) — Cloudflare URL for the upsell item image (with 16-hour TTL)

### AddonCategory

Addon category definition with translations

- `sortKey` (integer, required) — Sort order for display
- `title` (map from string to string, required) — Category title translations
- `description` (map from string to string, required) — Category description translations

### MenuItem

Menu item with pricing, translations, addons, and upsells

- `itemCode` (string, required) — Business Central item number
- `variantCode` (string, required) — Item variant code
- `sortKey` (integer, required) — Sort order for display
- `unitPrice` (double, required) — Item price
- `title` (map from string to string, required) — Item title translations
- `descriptionMarkdown` (map from string to string, required) — Item description in markdown format
- `nutritionMarkdown` (map from string to string, required) — Nutritional information in markdown format
- `status` (enum, optional) — Item availability status. Active items can be ordered. Inactive Visible items are shown but cannot be ordered. Inactive Hidden items are not shown.
  - Allowed values: `Active`, `Inactive Visible`, `Inactive Hidden`
- `imageUrl` (string, optional) — Cloudflare URL for the menu item image (with 16-hour TTL)
- `addonItems` (list of AddonItem, optional) — Addon options for this item
- `upsellItems` (list of UpsellItem, optional) — Upsell suggestions for this item. Only items that also appear in the menu categories are returned, so Inactive Hidden items are left out.

### AddonItem

Addon option for a menu item (quantity or select type)

- `category` (string, required) — Addon category code
- `sortKey` (integer, required) — Sort order for display
- `type` (string, required) — Addon type (Quantity or Select)
- `mandatory` (boolean, required) — Whether this addon is mandatory when purchasing the main item
- `fixedQuantity` (boolean, required) — Whether quantity is fixed
- `quantityPerUnit` (boolean, required) — Whether quantity scales with parent item quantity
- `quantity` (double, required) — Default quantity
- `itemCode` (string, required) — Business Central item number (for Quantity type)
- `variantCode` (string, required) — Item variant code (for Quantity type)
- `unitPrice` (double, required) — Addon price
- `description` (map from string to string, required) — Addon description translations
- `selectOptions` (list of SelectOption, optional) — Options to select from (for Select type)

### SelectOption

Option within a Select-type addon

- `sortKey` (integer, required) — Sort order for display
- `fixedQuantity` (boolean, required) — Whether quantity is fixed
- `quantityPerUnit` (boolean, required) — Whether quantity scales with parent item quantity
- `quantity` (double, required) — Default quantity
- `itemCode` (string, required) — Business Central item number
- `variantCode` (string, required) — Item variant code
- `unitPrice` (double, required) — Option price
- `description` (map from string to string, required) — Option description translations

## Examples

**Response**

```json
{
  "id": "e7b7e6b6-e3b7-f011-a901-f68f27c8de7a",
  "code": "QR_MENU",
  "startTime": "09:00:00",
  "endTime": "18:00:00",
  "timezone": "(UTC+01:00) Brussels, Copenhagen, Madrid, Paris",
  "active": true,
  "lastUpdated": "2026-01-15T14:30:00Z",
  "menuContent": {
    "categories": [
      {
        "code": "DURUM",
        "sortKey": 10000,
        "title": {
          "DAN": "Durum",
          "ENU": "Durum"
        },
        "description": {
          "DAN": "Hjemmelavet fladbrød hver morgen",
          "ENU": "Homemade flatbread every morning"
        },
        "items": [
          {
            "itemCode": "10000",
            "variantCode": "",
            "sortKey": 10000,
            "unitPrice": 120,
            "title": {
              "DAN": "Durum Kebab",
              "ENU": "Durum Kebab"
            },
            "descriptionMarkdown": {
              "DAN": "# Overskrift\nlavet med kærlighed",
              "ENU": "# Headline\nMade with love"
            },
            "nutritionMarkdown": {
              "DAN": "kcal per 100g: For mange",
              "ENU": "kcal per 100g: Too many"
            },
            "status": "Active",
            "addonItems": [
              {
                "category": "PROTEIN",
                "sortKey": 1,
                "type": "Select",
                "mandatory": false,
                "fixedQuantity": false,
                "quantityPerUnit": false,
                "quantity": 0,
                "itemCode": "",
                "variantCode": "",
                "unitPrice": 0,
                "description": {},
                "selectOptions": [
                  {
                    "sortKey": 10000,
                    "fixedQuantity": true,
                    "quantityPerUnit": true,
                    "quantity": 1,
                    "itemCode": "10011",
                    "variantCode": "",
                    "unitPrice": 0,
                    "description": {
                      "DAN": "Kebab fyld",
                      "ENU": "Kebab filling"
                    }
                  },
                  {
                    "sortKey": 20000,
                    "fixedQuantity": true,
                    "quantityPerUnit": true,
                    "quantity": 1,
                    "itemCode": "10012",
                    "variantCode": "",
                    "unitPrice": 0,
                    "description": {
                      "DAN": "Falafel fyld",
                      "ENU": "Falafel filling"
                    }
                  }
                ]
              },
              {
                "category": "EXTRAS",
                "sortKey": 1,
                "type": "Quantity",
                "mandatory": false,
                "fixedQuantity": false,
                "quantityPerUnit": false,
                "quantity": 0,
                "itemCode": "10006",
                "variantCode": "",
                "unitPrice": 15,
                "description": {
                  "DAN": "Ekstra fyld",
                  "ENU": "Extra filling"
                }
              }
            ],
            "upsellItems": [
              {
                "itemCode": "10018",
                "variantCode": "",
                "sortKey": 10000,
                "unitPrice": 80,
                "title": {},
                "descriptionMarkdown": {},
                "nutritionMarkdown": {},
                "status": "Active"
              }
            ]
          }
        ]
      }
    ],
    "checkoutUpsellItems": [
      {
        "itemCode": "10024",
        "variantCode": "",
        "sortKey": 20000,
        "unitPrice": 4,
        "title": {
          "DAN": "plastikpose",
          "ENU": "plasticbag"
        },
        "descriptionMarkdown": {
          "DAN": "",
          "ENU": ""
        },
        "nutritionMarkdown": {
          "DAN": "",
          "ENU": ""
        },
        "status": "Active"
      }
    ],
    "addonCategories": {
      "PROTEIN": {
        "sortKey": 1,
        "title": {
          "DAN": "Protein",
          "ENU": "Protein"
        },
        "description": {
          "DAN": "Protein beskrivelse",
          "ENU": "Protein description"
        }
      },
      "EXTRAS": {
        "sortKey": 3,
        "title": {
          "DAN": "Tilvalg",
          "ENU": "Extras"
        },
        "description": {
          "DAN": "",
          "ENU": ""
        }
      }
    }
  }
}
```

**SDK Code**

```python ExampleGetMenu
import requests

url = "https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a"

headers = {"x-np-api-key": "<NaviPartner API Key>"}

response = requests.get(url, headers=headers)

print(response.json())
```

```javascript ExampleGetMenu
const url = 'https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a';
const options = {method: 'GET', headers: {'x-np-api-key': '<NaviPartner API Key>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go ExampleGetMenu
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("x-np-api-key", "<NaviPartner API Key>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby ExampleGetMenu
require 'uri'
require 'net/http'

url = URI("https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["x-np-api-key"] = '<NaviPartner API Key>'

response = http.request(request)
puts response.read_body
```

```java ExampleGetMenu
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a")
  .header("x-np-api-key", "<NaviPartner API Key>")
  .asString();
```

```php ExampleGetMenu
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a', [
  'headers' => [
    'x-np-api-key' => '<NaviPartner API Key>',
  ],
]);

echo $response->getBody();
```

```csharp ExampleGetMenu
using RestSharp;

var client = new RestClient("https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a");
var request = new RestRequest(Method.GET);
request.AddHeader("x-np-api-key", "<NaviPartner API Key>");
IRestResponse response = client.Execute(request);
```

```swift ExampleGetMenu
import Foundation

let headers = ["x-np-api-key": "<NaviPartner API Key>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.npretail.app/01234567-89ab-cdef-0123-456789abcdef/production/CRONUS%2520International%2520Ltd./restaurant/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a/menu/e7b7e6b6-e3b7-f011-a901-f68f27c8de7a")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```