Skip to main content
Authenticated API

This endpoint requires a valid JWT Bearer token. Accessible via the API gateway at /v1/commerce/*.

Menu Management API

Complete API for managing restaurant menus including items, categories, modifiers, 86ing (out of stock), time-based availability, variants, nutrition, and ingredients.

Authentication Required

All write operations require a valid Bearer token with the can_manage_menus permission. Read operations on public menus are available without authentication.

Base Path: /api/v1

Overview

The Menu Management API provides:

FeatureDescription
Menus & ItemsCRUD operations for menus and menu items
CategoriesHierarchical categories with drag-and-drop reordering
Modifier GroupsReusable modifier groups (e.g., "Burger Toppings")
86ingMark items out of stock with audit log
DaypartsTime-based availability (breakfast, lunch, dinner)
VariantsSize/price variants (Small, Medium, Large)
NutritionCalorie and macro information
IngredientsIngredient library with allergen tracking
PhotosUpload and manage item/category images

Core Menu Operations

Create Menu

POST /api/v1/menus
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "Main Menu",
"description": "Our regular dining menu",
"location_id": "loc-abc123",
"is_active": true
}

List Menus

GET /api/v1/menus?tenant_id={tenant_id}&location_id={location_id}
Authorization: Bearer {access_token}

Get Menu with Items

GET /api/v1/menus/{menu_id}?tenant_id={tenant_id}

Update Menu

PATCH /api/v1/menus/{menu_id}
Authorization: Bearer {access_token}
Content-Type: application/json

Delete Menu

DELETE /api/v1/menus/{menu_id}
Authorization: Bearer {access_token}

Create Menu Item

POST /api/v1/menus/items
Authorization: Bearer {access_token}
Content-Type: application/json
{
"menu_id": "menu-123",
"category_id": "cat-456",
"name": "Classic Burger",
"description": "Our signature 8oz beef patty",
"price": 14.99,
"sku": "BURG-001",
"is_active": true,
"allergens": ["gluten", "dairy"],
"prep_time_minutes": 15,
"display_order": 1
}

List Menu Items

GET /api/v1/menus/items?tenant_id={tenant_id}&menu_id={menu_id}&is_active=true

Get Menu Item

GET /api/v1/menus/items/{item_id}?tenant_id={tenant_id}

Update Menu Item

PATCH /api/v1/menus/items/{item_id}
Authorization: Bearer {access_token}
Content-Type: application/json

Delete Menu Item

DELETE /api/v1/menus/items/{item_id}
Authorization: Bearer {access_token}

Categories

Organize menu items into hierarchical categories.

Create Category

POST /api/v1/menus/{menu_id}/categories
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "Appetizers",
"description": "Starters and small plates",
"parent_id": null,
"display_order": 1,
"is_active": true
}

List Categories

GET /api/v1/menus/{menu_id}/categories?tenant_id={tenant_id}&parent_id={parent_id}&include_items=true
ParameterTypeDescription
parent_idUUIDFilter to subcategories of parent
include_itemsbooleanInclude items in each category

Get Category

GET /api/v1/menus/{menu_id}/categories/{category_id}?tenant_id={tenant_id}

Update Category

PATCH /api/v1/menus/{menu_id}/categories/{category_id}
Authorization: Bearer {access_token}

Delete Category

DELETE /api/v1/menus/{menu_id}/categories/{category_id}
Authorization: Bearer {access_token}

Reorder Categories

Drag-and-drop reordering of categories.

POST /api/v1/menus/{menu_id}/categories/reorder
Authorization: Bearer {access_token}
Content-Type: application/json
{
"category_ids": [
"cat-appetizers",
"cat-salads",
"cat-entrees",
"cat-desserts"
]
}

Modifier Groups

Reusable modifier groups that can be assigned to multiple menu items.

Create Modifier Group

POST /api/v1/modifier-groups
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "Burger Toppings",
"description": "Available burger toppings",
"selection_type": "multiple",
"min_selections": 0,
"max_selections": 10,
"modifiers": [
{
"name": "Cheese",
"price": 1.50,
"is_default": true
},
{
"name": "Bacon",
"price": 2.00,
"is_default": false
},
{
"name": "Avocado",
"price": 2.50,
"is_default": false
}
]
}

List Modifier Groups

GET /api/v1/modifier-groups?tenant_id={tenant_id}&include_modifiers=true

Get Modifier Group

GET /api/v1/modifier-groups/{group_id}?tenant_id={tenant_id}

Update Modifier Group

PATCH /api/v1/modifier-groups/{group_id}
Authorization: Bearer {access_token}

Delete Modifier Group

DELETE /api/v1/modifier-groups/{group_id}
Authorization: Bearer {access_token}

Assign Modifier Group to Item

POST /api/v1/menus/items/{item_id}/modifier-groups
Authorization: Bearer {access_token}
Content-Type: application/json
{
"modifier_group_id": "group-toppings",
"is_required": true,
"display_order": 1
}

List Item's Modifier Groups

GET /api/v1/menus/items/{item_id}/modifier-groups?tenant_id={tenant_id}

Remove Modifier Group from Item

DELETE /api/v1/menus/items/{item_id}/modifier-groups/{group_id}
Authorization: Bearer {access_token}

86ing (Out of Stock)

Real-Time Sync

When an item is 86'd, a menu.item.86ed event is published to all connected POS terminals, kiosks, and online ordering channels in real time. Un-86ing publishes a menu.item.restored event.

Mark items as temporarily unavailable. Industry term "86" means out of stock.

86 an Item

Mark an item as out of stock.

POST /api/v1/menus/items/{item_id}/86
Authorization: Bearer {access_token}
Content-Type: application/json
{
"reason": "Sold out for the day",
"until": "2026-01-24T06:00:00Z"
}
FieldTypeRequiredDescription
reasonstringNoReason for 86ing
untildatetimeNoAuto-restore time (null = manual restore)

Response: Updated menu item with is_eighty_sixed: true

Events Published

When an item is 86'd:

  • Event type: menu.item.86ed
  • Published to: Table events topic

Un-86 an Item

Restore an item to available status.

DELETE /api/v1/menus/items/{item_id}/86
Authorization: Bearer {access_token}

Events Published

When an item is restored:

  • Event type: menu.item.restored

Batch 86 Items

86 multiple items at once.

POST /api/v1/menus/items/86/batch
Authorization: Bearer {access_token}
Content-Type: application/json
{
"item_ids": [
"item-burger-123",
"item-steak-456",
"item-lobster-789"
],
"reason": "Supply chain issue",
"until": null
}

List 86'd Items

Get all currently 86'd items.

GET /api/v1/menus/items/86?tenant_id={tenant_id}&location_id={location_id}

Get 86 Audit Log

View the history of 86/restore actions.

GET /api/v1/menus/86/log?tenant_id={tenant_id}&entity_id={item_id}&limit=50

Response

{
"entries": [
{
"id": "log-001",
"entity_id": "item-burger-123",
"entity_type": "menu_item",
"action": "86",
"reason": "Sold out",
"performed_by": "user-manager",
"created_at": "2026-01-23T18:00:00Z"
},
{
"id": "log-002",
"entity_id": "item-burger-123",
"entity_type": "menu_item",
"action": "restore",
"reason": null,
"performed_by": "system",
"created_at": "2026-01-24T06:00:00Z"
}
]
}

Dayparts (Time-Based Availability)

Control when menu items are available based on time of day.

Create Daypart

POST /api/v1/menus/{menu_id}/dayparts
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "Breakfast",
"start_time": "06:00",
"end_time": "11:00",
"days_of_week": ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"],
"is_active": true
}
FieldTypeDescription
start_timestringStart time (HH:MM format)
end_timestringEnd time (HH:MM format)
days_of_weekarrayDays this daypart is active

List Dayparts

GET /api/v1/menus/{menu_id}/dayparts
Authorization: Bearer {access_token}

Update Daypart

PATCH /api/v1/menus/{menu_id}/dayparts/{daypart_id}
Authorization: Bearer {access_token}

Delete Daypart

DELETE /api/v1/menus/{menu_id}/dayparts/{daypart_id}
Authorization: Bearer {access_token}

Update Item Availability

Set which dayparts an item is available during.

POST /api/v1/menus/items/{item_id}/availability
Authorization: Bearer {access_token}
Content-Type: application/json
{
"daypart_ids": ["daypart-breakfast", "daypart-brunch"],
"available_from": "2026-01-01",
"available_until": "2026-03-31"
}

Variants

Menu items can have multiple variants with different sizes and prices.

Create Variant

POST /api/v1/menus/items/{item_id}/variants
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "Large",
"sku": "PIZZA-LG",
"price": 18.99,
"price_adjustment": 4.00,
"display_order": 2,
"is_default": false,
"is_active": true
}
FieldTypeDescription
namestringVariant name (e.g., "Large", "12 inch")
skustringUnique SKU for this variant
pricedecimalAbsolute price for this variant
price_adjustmentdecimalPrice difference from base item
is_defaultbooleanDefault selection

List Variants

GET /api/v1/menus/items/{item_id}/variants
Authorization: Bearer {access_token}

Response

{
"variants": [
{
"id": "var-sm",
"menu_item_id": "item-pizza",
"name": "Small",
"sku": "PIZZA-SM",
"price": 12.99,
"display_order": 1,
"is_default": true,
"is_active": true
},
{
"id": "var-md",
"menu_item_id": "item-pizza",
"name": "Medium",
"sku": "PIZZA-MD",
"price": 15.99,
"display_order": 2,
"is_default": false,
"is_active": true
},
{
"id": "var-lg",
"menu_item_id": "item-pizza",
"name": "Large",
"sku": "PIZZA-LG",
"price": 18.99,
"display_order": 3,
"is_default": false,
"is_active": true
}
]
}

Update Variant

PATCH /api/v1/menus/items/{item_id}/variants/{variant_id}
Authorization: Bearer {access_token}

Delete Variant

DELETE /api/v1/menus/items/{item_id}/variants/{variant_id}
Authorization: Bearer {access_token}

Nutrition Information

Track calorie and nutritional information for menu items.

Update Item Nutrition

POST /api/v1/menus/items/{item_id}/nutrition
Authorization: Bearer {access_token}
Content-Type: application/json
{
"calories": 850,
"calories_from_fat": 450,
"total_fat_g": 50,
"saturated_fat_g": 18,
"trans_fat_g": 0,
"cholesterol_mg": 125,
"sodium_mg": 1200,
"total_carbs_g": 45,
"dietary_fiber_g": 3,
"sugars_g": 8,
"protein_g": 42,
"serving_size": "1 burger (280g)"
}

Response

Returns the updated menu item with embedded nutrition info:

{
"id": "item-burger",
"name": "Classic Burger",
"nutrition": {
"calories": 850,
"protein_g": 42,
"total_fat_g": 50,
"total_carbs_g": 45,
"serving_size": "1 burger (280g)"
}
}

Ingredients

Manage an ingredient library with allergen tracking.

Create Ingredient

POST /api/v1/ingredients
Authorization: Bearer {access_token}
Content-Type: application/json
{
"name": "Beef Patty",
"description": "8oz ground beef",
"allergens": [],
"is_active": true
}

List Ingredients

GET /api/v1/ingredients
Authorization: Bearer {access_token}

Update Ingredient

PATCH /api/v1/ingredients/{ingredient_id}
Authorization: Bearer {access_token}

Delete Ingredient

DELETE /api/v1/ingredients/{ingredient_id}
Authorization: Bearer {access_token}

Assign Ingredient to Item

POST /api/v1/menus/items/{item_id}/ingredients
Authorization: Bearer {access_token}
Content-Type: application/json
{
"ingredient_id": "ing-beef-patty",
"quantity": 1,
"unit": "piece",
"is_optional": false
}

List Item Ingredients

GET /api/v1/menus/items/{item_id}/ingredients
Authorization: Bearer {access_token}

Remove Ingredient from Item

DELETE /api/v1/menus/items/{item_id}/ingredients/{ingredient_id}
Authorization: Bearer {access_token}

Photos

Upload and manage photos for items and categories.

Upload Item Photo

POST /api/v1/menus/items/{item_id}/photos
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Form data:

  • file: Image file (JPEG, PNG, WebP)
  • display_order: Optional integer
  • alt_text: Optional alt text

Upload Category Photo

POST /api/v1/menus/categories/{category_id}/photo
Authorization: Bearer {access_token}
Content-Type: multipart/form-data

Get Photo

GET /api/v1/photos/{photo_id}

Delete Photo

DELETE /api/v1/photos/{photo_id}
Authorization: Bearer {access_token}

Permissions

Most menu operations require the can_manage_menus permission:

RoleCreateReadUpdateDelete86
tenant_adminYesYesYesYesYes
managerYesYesYesYesYes
staffNoYesNoNoNo
PublicNoYesNoNoNo

Error Responses

{
"error": {
"code": "NOT_FOUND",
"message": "Menu not found"
}
}

Unauthorized (401)

{
"error": {
"code": "UNAUTHORIZED",
"message": "insufficient permissions to manage menus"
}
}

  • KDS API - Kitchen display integration
  • Orders API - Order processing
  • Manager Menu Guide - Staff operations