> For the complete documentation index, see [llms.txt](https://docs.hos.accessacloud.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hos.accessacloud.com/evo-recipes-api/menus.md).

# Menus

Menu hierarchy with menu items

## List menus

> Returns a projection of menus for the authenticated organisation, ordered by name ascending and defaulting to active menus. Menu contents are not inlined — page them from \`GET /apim/menu-items?menuId=...\`.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Menus","description":"Menu hierarchy with menu items"}],"servers":[{"url":"https://api.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Production"},{"url":"https://api-dev.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Development"},{"url":"https://api-staging.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Staging"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth2 client credentials JWT obtained from the Access Identity M2M token endpoint (`POST https://api.hos.accessacloud.com/platform/m2m-auth/v1/token`). The token request must use `grant_type=client_credentials` with `audience=fandb-platform-api evo-dishes-recipes` and `scope=fandb.read fandb.write openid <organisationId>`, where `<organisationId>` is the calling organisation's GUID. The response returns `{ \"access_token\": \"<JWT>\", \"expires_in\": 3599, \"scope\": \"fandb.read fandb.write openid <organisationId>\", \"token_type\": \"bearer\" }`. Tokens expire after `expires_in` seconds (typically ~1 hour). APIM validates the token at the gateway. The token's `scp` claim must also carry the caller's organisation ID as a bare GUID; the backend resolves the tenant by matching that GUID case-insensitively against either the `id` or the `workspace_org_id` column. A token with no organisation GUID is rejected with `401`, and one carrying more than one distinct organisation GUID with `403`."}},"parameters":{"PageSize":{"name":"page_size","in":"query","required":false,"description":"Number of items per page. Clamped to the range [1, 500]. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"Opaque cursor for keyset pagination. Pass the next_cursor value from a previous response to fetch the next page.","schema":{"type":"string"}},"ActiveFilter":{"name":"active","in":"query","required":false,"description":"Filter on the active flag. Use `all` to disable the filter. Defaults to `true`.","schema":{"type":"string","enum":["true","false","all"],"default":"true"}},"ParentMenuIdFilter":{"name":"parentMenuId","in":"query","required":false,"description":"Restrict results to the children of a single parent menu.","schema":{"type":"string"}},"UpdatedSince":{"name":"updatedSince","in":"query","required":false,"description":"ISO 8601 timestamp. Returns only records updated at or after this instant, ordered by `updatedAt` ascending for incremental sync.","schema":{"type":"string","format":"date-time"}}},"schemas":{"PaginatedResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"Pagination":{"type":"object","required":["page_size","has_next_page","next_cursor"],"properties":{"page_size":{"type":"integer","description":"The page size used for this request."},"has_next_page":{"type":"boolean","description":"Whether more results exist beyond this page."},"next_cursor":{"type":"string","nullable":true,"description":"Cursor to pass as the cursor query parameter for the next page. Null when there are no more results."}}},"MenuListItem":{"type":"object","description":"Menu list projection; contents are served by /apim/menu-items.","required":["id","name","currency","sortOrder","updatedAt"],"properties":{"id":{"type":"string","description":"Unique menu identifier (CUID)."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"currency":{"type":"string","maxLength":3,"description":"ISO 4217 currency code for menu pricing."},"parentMenuId":{"type":"string","nullable":true,"description":"Parent menu ID for hierarchical menu structures."},"sortOrder":{"type":"integer"},"updatedAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code (e.g. INVALID_QUERY_PARAMETER, MISSING_PATH_PARAMETER, RESOURCE_NOT_FOUND, INTERNAL_ERROR)."},"parameter":{"type":"string","description":"The offending query or path parameter, when applicable."}}}},"responses":{"BadRequest":{"description":"A query or path parameter failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid, or expired authorization token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The token does not grant access to exactly one organisation, so no tenant can be resolved from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"OrganizationNotFound":{"description":"No tenant found matching the organisation GUID in the token's `scp` claim.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/menus":{"get":{"operationId":"GetMenus","summary":"List menus","description":"Returns a projection of menus for the authenticated organisation, ordered by name ascending and defaulting to active menus. Menu contents are not inlined — page them from `GET /apim/menu-items?menuId=...`.","tags":["Menus"],"parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/ActiveFilter"},{"$ref":"#/components/parameters/ParentMenuIdFilter"},{"$ref":"#/components/parameters/UpdatedSince"}],"responses":{"200":{"description":"Paginated list of menus.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MenuListItem"}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/OrganizationNotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Get a menu

> Returns one menu with its non-deleted menu items (including EPOS PLU codes) and a bounded-depth child-menu hierarchy: at most 3 levels of descendants (\`maxHierarchyDepth\`), at most 500 child menus per level and at most 500 items per menu. When a breadth cap is reached anywhere in the returned tree, \`childMenusTruncated\` / \`menuItemsTruncated\` say so. Allergen data is the stored kind only — the associations recorded against an ingredient-backed item's ingredient and the overrides recorded against a recipe-backed item's current version. No cost, GP or margin figures are returned.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Menus","description":"Menu hierarchy with menu items"}],"servers":[{"url":"https://api.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Production"},{"url":"https://api-dev.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Development"},{"url":"https://api-staging.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Staging"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth2 client credentials JWT obtained from the Access Identity M2M token endpoint (`POST https://api.hos.accessacloud.com/platform/m2m-auth/v1/token`). The token request must use `grant_type=client_credentials` with `audience=fandb-platform-api evo-dishes-recipes` and `scope=fandb.read fandb.write openid <organisationId>`, where `<organisationId>` is the calling organisation's GUID. The response returns `{ \"access_token\": \"<JWT>\", \"expires_in\": 3599, \"scope\": \"fandb.read fandb.write openid <organisationId>\", \"token_type\": \"bearer\" }`. Tokens expire after `expires_in` seconds (typically ~1 hour). APIM validates the token at the gateway. The token's `scp` claim must also carry the caller's organisation ID as a bare GUID; the backend resolves the tenant by matching that GUID case-insensitively against either the `id` or the `workspace_org_id` column. A token with no organisation GUID is rejected with `401`, and one carrying more than one distinct organisation GUID with `403`."}},"parameters":{"MenuId":{"name":"menuId","in":"path","required":true,"description":"The menu id, which must belong to the authenticated organisation.","schema":{"type":"string"}}},"schemas":{"MenuDetail":{"type":"object","description":"Menu detail with inlined items and a bounded child hierarchy. No cost, GP or margin figures are returned.","required":["id","name","currency","sortOrder","active","tags","menuItems","maxHierarchyDepth","maxChildMenusPerLevel","maxMenuItems","childMenusTruncated","menuItemsTruncated","childMenus","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"currency":{"type":"string","maxLength":3},"parentMenuId":{"type":"string","nullable":true},"sortOrder":{"type":"integer"},"active":{"type":"boolean"},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagRef"}},"menuItems":{"type":"array","description":"Non-deleted items, capped at 500.","items":{"$ref":"#/components/schemas/MenuDetailItem"}},"maxHierarchyDepth":{"type":"integer","description":"Levels of descendants included below this menu."},"maxChildMenusPerLevel":{"type":"integer","description":"Child menus returned per hierarchy level."},"maxMenuItems":{"type":"integer","description":"Items returned per menu in the hierarchy."},"childMenusTruncated":{"type":"boolean","description":"True when a hierarchy level reached `maxChildMenusPerLevel`, so at least one menu in the tree is missing children."},"menuItemsTruncated":{"type":"boolean","description":"True when any menu in the tree reached `maxMenuItems`, so its `menuItems` array is incomplete."},"childMenus":{"type":"array","items":{"$ref":"#/components/schemas/MenuHierarchyNode"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TagRef":{"type":"object","description":"Lightweight reference to a tag.","required":["id","name","color"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"color":{"type":"string","description":"Hex colour code."}}},"MenuDetailItem":{"type":"object","description":"A menu item as inlined on a menu, with its stored allergen data.","required":["id","name","price","sortOrder","active","pluCodes","updatedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"price":{"type":"string","format":"decimal"},"servingQty":{"type":"string","format":"decimal","nullable":true},"servingUnit":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UnitRef"}]},"sortOrder":{"type":"integer"},"active":{"type":"boolean"},"pluCodes":{"type":"array","items":{"$ref":"#/components/schemas/PluCode"}},"ingredient":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/MenuItemIngredientSummary"}]},"recipe":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/MenuItemRecipeSummary"}]},"updatedAt":{"type":"string","format":"date-time"}}},"UnitRef":{"type":"object","description":"Lightweight reference to a measurement unit.","required":["id","name","abbreviation","unitType"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"abbreviation":{"type":"string"},"unitType":{"type":"string","enum":["WEIGHT","VOLUME","COUNT"]}}},"PluCode":{"type":"object","description":"EPOS PLU code stored against a menu item.","required":["pluCode","eposSystem"],"properties":{"pluCode":{"type":"string"},"eposSystem":{"type":"string"},"servingQty":{"type":"string","format":"decimal","nullable":true},"servingUnitId":{"type":"string","nullable":true},"recipeId":{"type":"string","nullable":true},"recipeVersionId":{"type":"string","nullable":true},"ingredientId":{"type":"string","nullable":true}}},"MenuItemIngredientSummary":{"type":"object","required":["id","name","allergens"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"productCode":{"type":"string","nullable":true},"allergens":{"type":"array","items":{"$ref":"#/components/schemas/AllergenAssociation"}}}},"AllergenAssociation":{"description":"Allergen as stored against an ingredient or supplier offer. `status` is the recorded association, never a calculated roll-up.","allOf":[{"$ref":"#/components/schemas/AllergenRef"},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["NO","YES","MAY_CONTAIN"]}}}]},"AllergenRef":{"type":"object","description":"Lightweight allergen reference as included on a product.","required":["id","code","name","severity"],"properties":{"id":{"type":"string"},"code":{"type":"string","description":"Unique allergen code (e.g. CELERY, EGGS, MILK)."},"name":{"type":"string"},"severity":{"type":"string","enum":["MILD","MODERATE","SEVERE","LIFE_THREATENING"]}}},"MenuItemRecipeSummary":{"allOf":[{"$ref":"#/components/schemas/RecipeRef"},{"type":"object","properties":{"currentVersion":{"nullable":true,"type":"object","required":["id","versionNumber","allergenOverrides"],"properties":{"id":{"type":"string"},"versionNumber":{"type":"integer"},"allergenOverrides":{"type":"array","items":{"$ref":"#/components/schemas/AllergenOverride"}}}}}}]},"RecipeRef":{"type":"object","description":"Lightweight reference to a recipe.","required":["id","name","status"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]}}},"AllergenOverride":{"description":"Cross-contamination allergen override stored against a recipe version.","allOf":[{"$ref":"#/components/schemas/AllergenRef"},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["NO","YES","MAY_CONTAIN"]},"reason":{"type":"string","nullable":true}}}]},"MenuHierarchyNode":{"type":"object","description":"A descendant menu. Nesting stops at the menu's `maxHierarchyDepth`, so `childMenus` is empty on the deepest level returned.","required":["id","name","currency","sortOrder","active","menuItems","childMenus","updatedAt"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"currency":{"type":"string","maxLength":3},"sortOrder":{"type":"integer"},"active":{"type":"boolean"},"menuItems":{"type":"array","items":{"$ref":"#/components/schemas/MenuDetailItem"}},"childMenus":{"type":"array","items":{"$ref":"#/components/schemas/MenuHierarchyNode"}},"updatedAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code (e.g. INVALID_QUERY_PARAMETER, MISSING_PATH_PARAMETER, RESOURCE_NOT_FOUND, INTERNAL_ERROR)."},"parameter":{"type":"string","description":"The offending query or path parameter, when applicable."}}}},"responses":{"BadRequest":{"description":"A query or path parameter failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid, or expired authorization token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The token does not grant access to exactly one organisation, so no tenant can be resolved from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No resource found for the given id in the caller's organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/menus/{menuId}":{"get":{"operationId":"GetMenu","summary":"Get a menu","description":"Returns one menu with its non-deleted menu items (including EPOS PLU codes) and a bounded-depth child-menu hierarchy: at most 3 levels of descendants (`maxHierarchyDepth`), at most 500 child menus per level and at most 500 items per menu. When a breadth cap is reached anywhere in the returned tree, `childMenusTruncated` / `menuItemsTruncated` say so. Allergen data is the stored kind only — the associations recorded against an ingredient-backed item's ingredient and the overrides recorded against a recipe-backed item's current version. No cost, GP or margin figures are returned.","tags":["Menus"],"parameters":[{"$ref":"#/components/parameters/MenuId"}],"responses":{"200":{"description":"The menu, its items and its bounded child hierarchy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuDetail"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## List menu items

> Returns menu items for the authenticated organisation, ordered by name ascending and defaulting to active, non-deleted items. Filter by \`menuId\` to page the contents of a single menu.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Menus","description":"Menu hierarchy with menu items"}],"servers":[{"url":"https://api.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Production"},{"url":"https://api-dev.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Development"},{"url":"https://api-staging.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Staging"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth2 client credentials JWT obtained from the Access Identity M2M token endpoint (`POST https://api.hos.accessacloud.com/platform/m2m-auth/v1/token`). The token request must use `grant_type=client_credentials` with `audience=fandb-platform-api evo-dishes-recipes` and `scope=fandb.read fandb.write openid <organisationId>`, where `<organisationId>` is the calling organisation's GUID. The response returns `{ \"access_token\": \"<JWT>\", \"expires_in\": 3599, \"scope\": \"fandb.read fandb.write openid <organisationId>\", \"token_type\": \"bearer\" }`. Tokens expire after `expires_in` seconds (typically ~1 hour). APIM validates the token at the gateway. The token's `scp` claim must also carry the caller's organisation ID as a bare GUID; the backend resolves the tenant by matching that GUID case-insensitively against either the `id` or the `workspace_org_id` column. A token with no organisation GUID is rejected with `401`, and one carrying more than one distinct organisation GUID with `403`."}},"parameters":{"PageSize":{"name":"page_size","in":"query","required":false,"description":"Number of items per page. Clamped to the range [1, 500]. Defaults to 100.","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},"Cursor":{"name":"cursor","in":"query","required":false,"description":"Opaque cursor for keyset pagination. Pass the next_cursor value from a previous response to fetch the next page.","schema":{"type":"string"}},"ActiveFilter":{"name":"active","in":"query","required":false,"description":"Filter on the active flag. Use `all` to disable the filter. Defaults to `true`.","schema":{"type":"string","enum":["true","false","all"],"default":"true"}},"DeletedFilter":{"name":"deleted","in":"query","required":false,"description":"Filter on the soft-delete flag. Use `all` to disable the filter. Defaults to `false`.","schema":{"type":"string","enum":["true","false","all"],"default":"false"}},"MenuIdFilter":{"name":"menuId","in":"query","required":false,"description":"Restrict results to a single menu.","schema":{"type":"string"}},"UpdatedSince":{"name":"updatedSince","in":"query","required":false,"description":"ISO 8601 timestamp. Returns only records updated at or after this instant, ordered by `updatedAt` ascending for incremental sync.","schema":{"type":"string","format":"date-time"}}},"schemas":{"PaginatedResponse":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{}},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"Pagination":{"type":"object","required":["page_size","has_next_page","next_cursor"],"properties":{"page_size":{"type":"integer","description":"The page size used for this request."},"has_next_page":{"type":"boolean","description":"Whether more results exist beyond this page."},"next_cursor":{"type":"string","nullable":true,"description":"Cursor to pass as the cursor query parameter for the next page. Null when there are no more results."}}},"MenuItem":{"type":"object","required":["id","menuId","name","price","sortOrder","active","deleted","updatedAt"],"properties":{"id":{"type":"string"},"menuId":{"type":"string"},"recipeId":{"type":"string","nullable":true,"description":"Associated recipe, if this menu item is recipe-backed."},"ingredientId":{"type":"string","nullable":true,"description":"Associated product, if this menu item is product-backed."},"name":{"type":"string"},"description":{"type":"string","nullable":true},"price":{"type":"string","format":"decimal"},"servingQty":{"type":"string","format":"decimal","nullable":true},"servingUnitId":{"type":"string","nullable":true},"sortOrder":{"type":"integer"},"active":{"type":"boolean"},"deleted":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code (e.g. INVALID_QUERY_PARAMETER, MISSING_PATH_PARAMETER, RESOURCE_NOT_FOUND, INTERNAL_ERROR)."},"parameter":{"type":"string","description":"The offending query or path parameter, when applicable."}}}},"responses":{"BadRequest":{"description":"A query or path parameter failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid, or expired authorization token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The token does not grant access to exactly one organisation, so no tenant can be resolved from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"OrganizationNotFound":{"description":"No tenant found matching the organisation GUID in the token's `scp` claim.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/menu-items":{"get":{"operationId":"GetMenuItems","summary":"List menu items","description":"Returns menu items for the authenticated organisation, ordered by name ascending and defaulting to active, non-deleted items. Filter by `menuId` to page the contents of a single menu.","tags":["Menus"],"parameters":[{"$ref":"#/components/parameters/PageSize"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/ActiveFilter"},{"$ref":"#/components/parameters/DeletedFilter"},{"$ref":"#/components/parameters/MenuIdFilter"},{"$ref":"#/components/parameters/UpdatedSince"}],"responses":{"200":{"description":"Paginated list of menu items.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/PaginatedResponse"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MenuItem"}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/OrganizationNotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```

## Get a menu item

> Returns one menu item with its parent menu summary, EPOS PLU codes and a summary of whatever it is backed by: an ingredient (with stored allergen associations and the current stored nutrition row) or a recipe (with the current version's stored allergen overrides, manually entered nutrition and dietary suitability). Nothing is calculated and no cost, GP or margin figures are returned.

```json
{"openapi":"3.0.1","info":{"title":"EvoDishesRecipes APIM Operations API","version":"0.1"},"tags":[{"name":"Menus","description":"Menu hierarchy with menu items"}],"servers":[{"url":"https://api.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Production"},{"url":"https://api-dev.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Development"},{"url":"https://api-staging.hos.accessacloud.com/evo/dishes-recipes/v1","description":"Staging"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth2 client credentials JWT obtained from the Access Identity M2M token endpoint (`POST https://api.hos.accessacloud.com/platform/m2m-auth/v1/token`). The token request must use `grant_type=client_credentials` with `audience=fandb-platform-api evo-dishes-recipes` and `scope=fandb.read fandb.write openid <organisationId>`, where `<organisationId>` is the calling organisation's GUID. The response returns `{ \"access_token\": \"<JWT>\", \"expires_in\": 3599, \"scope\": \"fandb.read fandb.write openid <organisationId>\", \"token_type\": \"bearer\" }`. Tokens expire after `expires_in` seconds (typically ~1 hour). APIM validates the token at the gateway. The token's `scp` claim must also carry the caller's organisation ID as a bare GUID; the backend resolves the tenant by matching that GUID case-insensitively against either the `id` or the `workspace_org_id` column. A token with no organisation GUID is rejected with `401`, and one carrying more than one distinct organisation GUID with `403`."}},"parameters":{"MenuItemId":{"name":"menuItemId","in":"path","required":true,"description":"The menu item id, which must belong to the authenticated organisation.","schema":{"type":"string"}}},"schemas":{"MenuItemDetail":{"type":"object","description":"Menu item detail with its parent menu, PLU codes and the stored data of whatever backs it. No cost, GP or margin figures are returned.","required":["id","menuId","name","price","unitsSold","sortOrder","active","deleted","pluCodes","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"menuId":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"price":{"type":"string","format":"decimal"},"servingQty":{"type":"string","format":"decimal","nullable":true},"servingUnit":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/UnitRef"}]},"unitsSold":{"type":"integer"},"sortOrder":{"type":"integer"},"active":{"type":"boolean"},"deleted":{"type":"boolean"},"menu":{"$ref":"#/components/schemas/MenuRef"},"pluCodes":{"type":"array","items":{"$ref":"#/components/schemas/PluCode"}},"ingredient":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/MenuItemDetailIngredient"}]},"recipe":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/MenuItemDetailRecipe"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"UnitRef":{"type":"object","description":"Lightweight reference to a measurement unit.","required":["id","name","abbreviation","unitType"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"abbreviation":{"type":"string"},"unitType":{"type":"string","enum":["WEIGHT","VOLUME","COUNT"]}}},"MenuRef":{"type":"object","description":"Lightweight reference to the menu an item belongs to.","required":["id","name","currency","active"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"currency":{"type":"string","maxLength":3},"active":{"type":"boolean"}}},"PluCode":{"type":"object","description":"EPOS PLU code stored against a menu item.","required":["pluCode","eposSystem"],"properties":{"pluCode":{"type":"string"},"eposSystem":{"type":"string"},"servingQty":{"type":"string","format":"decimal","nullable":true},"servingUnitId":{"type":"string","nullable":true},"recipeId":{"type":"string","nullable":true},"recipeVersionId":{"type":"string","nullable":true},"ingredientId":{"type":"string","nullable":true}}},"MenuItemDetailIngredient":{"type":"object","required":["id","name","allergens"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true,"description":"Free-text product description (not the pack size)."},"productCode":{"type":"string","nullable":true},"ingredientDeclaration":{"type":"string","nullable":true},"allergens":{"type":"array","items":{"$ref":"#/components/schemas/AllergenAssociation"}},"nutrition":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/StoredNutrition"}]},"dietarySuitability":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/DietarySuitability"}]}}},"AllergenAssociation":{"description":"Allergen as stored against an ingredient or supplier offer. `status` is the recorded association, never a calculated roll-up.","allOf":[{"$ref":"#/components/schemas/AllergenRef"},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["NO","YES","MAY_CONTAIN"]}}}]},"AllergenRef":{"type":"object","description":"Lightweight allergen reference as included on a product.","required":["id","code","name","severity"],"properties":{"id":{"type":"string"},"code":{"type":"string","description":"Unique allergen code (e.g. CELERY, EGGS, MILK)."},"name":{"type":"string"},"severity":{"type":"string","enum":["MILD","MODERATE","SEVERE","LIFE_THREATENING"]}}},"StoredNutrition":{"description":"Current stored nutrition row of an ingredient (`IngredientNutrition`) or a supplier offer (`OfferNutrition`). Never an aggregate.","allOf":[{"$ref":"#/components/schemas/NutritionValues"},{"type":"object","required":["referenceUnit","dataSource","version"],"properties":{"referenceUnit":{"type":"string"},"dataSource":{"type":"string"},"sourceReference":{"type":"string","nullable":true},"verifiedAt":{"type":"string","format":"date-time","nullable":true},"version":{"type":"integer"}}}]},"NutritionValues":{"type":"object","description":"Big-8 plus extended nutrition values. Decimal columns are serialised as strings to preserve precision.","properties":{"energyKcal":{"type":"string","format":"decimal","nullable":true},"energyKj":{"type":"string","format":"decimal","nullable":true},"fatG":{"type":"string","format":"decimal","nullable":true},"saturatedFatG":{"type":"string","format":"decimal","nullable":true},"carbohydrateG":{"type":"string","format":"decimal","nullable":true},"sugarsG":{"type":"string","format":"decimal","nullable":true},"proteinG":{"type":"string","format":"decimal","nullable":true},"saltG":{"type":"string","format":"decimal","nullable":true},"fibreG":{"type":"string","format":"decimal","nullable":true},"monoUnsaturatesG":{"type":"string","format":"decimal","nullable":true},"polyUnsaturatesG":{"type":"string","format":"decimal","nullable":true},"transFatG":{"type":"string","format":"decimal","nullable":true},"sodiumMg":{"type":"string","format":"decimal","nullable":true},"freeSugarsG":{"type":"string","format":"decimal","nullable":true}}},"DietarySuitability":{"type":"object","description":"Stored dietary-suitability flags. Nulls mean \"not declared\".","properties":{"isVegetarian":{"type":"boolean","nullable":true},"isVegan":{"type":"boolean","nullable":true},"isDairyFree":{"type":"boolean","nullable":true},"isGlutenFree":{"type":"boolean","nullable":true},"isLactoseFree":{"type":"boolean","nullable":true},"isNutFree":{"type":"boolean","nullable":true},"isHalalSuitable":{"type":"boolean","nullable":true},"isKosherSuitable":{"type":"boolean","nullable":true},"isHinduismSuitable":{"type":"boolean","nullable":true}}},"MenuItemDetailRecipe":{"allOf":[{"$ref":"#/components/schemas/RecipeRef"},{"type":"object","required":["productType"],"properties":{"productType":{"type":"string","enum":["FOOD","DRINK"]},"currentVersion":{"nullable":true,"type":"object","required":["id","versionNumber","status","servings","allergenOverrides"],"properties":{"id":{"type":"string"},"versionNumber":{"type":"integer"},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]},"servings":{"type":"string","format":"decimal"},"portionSizeG":{"type":"string","format":"decimal","nullable":true},"allergenOverrides":{"type":"array","items":{"$ref":"#/components/schemas/AllergenOverride"}},"nutritionOverride":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RecipeNutritionOverride"}]},"dietarySuitability":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/DietarySuitability"}]}}}}}]},"RecipeRef":{"type":"object","description":"Lightweight reference to a recipe.","required":["id","name","status"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["DRAFT","PENDING_APPROVAL","PUBLISHED","ARCHIVED"]}}},"AllergenOverride":{"description":"Cross-contamination allergen override stored against a recipe version.","allOf":[{"$ref":"#/components/schemas/AllergenRef"},{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["NO","YES","MAY_CONTAIN"]},"reason":{"type":"string","nullable":true}}}]},"RecipeNutritionOverride":{"description":"Manually entered nutrition for a recipe version.","allOf":[{"$ref":"#/components/schemas/NutritionValues"},{"type":"object","required":["inputBasis","updatedAt"],"properties":{"inputBasis":{"type":"string","enum":["PER_100G","PER_PORTION","PER_RECIPE"]},"updatedAt":{"type":"string","format":"date-time"}}}]},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable error message."},"code":{"type":"string","description":"Stable machine-readable error code (e.g. INVALID_QUERY_PARAMETER, MISSING_PATH_PARAMETER, RESOURCE_NOT_FOUND, INTERNAL_ERROR)."},"parameter":{"type":"string","description":"The offending query or path parameter, when applicable."}}}},"responses":{"BadRequest":{"description":"A query or path parameter failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing, invalid, or expired authorization token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The token does not grant access to exactly one organisation, so no tenant can be resolved from it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No resource found for the given id in the caller's organisation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalServerError":{"description":"Unexpected server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/apim/menu-items/{menuItemId}":{"get":{"operationId":"GetMenuItem","summary":"Get a menu item","description":"Returns one menu item with its parent menu summary, EPOS PLU codes and a summary of whatever it is backed by: an ingredient (with stored allergen associations and the current stored nutrition row) or a recipe (with the current version's stored allergen overrides, manually entered nutrition and dietary suitability). Nothing is calculated and no cost, GP or margin figures are returned.","tags":["Menus"],"parameters":[{"$ref":"#/components/parameters/MenuItemId"}],"responses":{"200":{"description":"The menu item.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MenuItemDetail"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.hos.accessacloud.com/evo-recipes-api/menus.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
