Culinary resources
The food graph: ingredients → recipes → menu items → menus → a dated, site-specific effective menu that the rest of the platform reads. Writes require manageCulinary (manager+) unless noted.
Ingredients
GET /orgs/{orgId}/ingredients
POST /orgs/{orgId}/ingredients
PUT /orgs/{orgId}/ingredients/{id}
An ingredient carries its base unit, cost per unit, density, allergens, diet flags, and nutrition per 100 g/ml.
Recipes and versions
GET /orgs/{orgId}/recipes — list (with computed roll-ups)
POST /orgs/{orgId}/recipes — create the recipe shell
GET /orgs/{orgId}/recipes/{id} — detail incl. versions
PUT /orgs/{orgId}/recipes/{id} — update name/category/station/tags
POST /orgs/{orgId}/recipes/{id}/versions — add a version (draft or published)
POST /orgs/{orgId}/recipes/{id}/archive
PATCH /orgs/{orgId}/recipes/{id}/image — attach a plate photo (media id)
POST /orgs/{orgId}/import/culinary — CSV import (ingredients/recipes)
Recipes are versioned: the version document holds yield, portions, components (ingredients or sub-recipes), method steps with CCPs, and texture/diet variants. Publishing a version computes and freezes cost per portion, nutrition per portion, and the allergen/diet roll-up — returned on the recipe as computed:
{
"id": "23f67f69-3531-4d17-b9b2-a1aac236ce4d",
"name": "Ahi Poke-Style Bowl",
"category": "bowl",
"station": "cold",
"status": "active",
"currentVersionId": "83537e82-e837-40c1-87db-2d32199e6a11",
"portions": 24,
"computed": {
"warnings": [],
"allergens": ["fish", "soy"],
"dietFlags": ["gluten_free"],
"costPerPortion": 4.6,
"nutritionEstimated": false,
"nutritionPerPortion": { "kcal": 477.1, "proteinG": 44.94, "sodiumMg": 139.2 }
},
"imageUrl": "https://miseline.keyedsystems.com/api/media/content/..."
}
(nutritionPerPortion is abbreviated here — the real object carries the full nutrient set.) nutritionEstimated: true flags AI-estimated inputs pending dietitian review.
Menu items
GET /orgs/{orgId}/menu-items
POST /orgs/{orgId}/menu-items
PUT /orgs/{orgId}/menu-items/{id}
PATCH /orgs/{orgId}/menu-items/{id}/image
A menu item wraps a recipe (or stands alone) with category, serving text, price in cents, and an image. Allergen and diet flags flow up from the recipe.
Menus, slots, and review
GET /orgs/{orgId}/menus
POST /orgs/{orgId}/menus — kinds: daily | cycle | static | catering
GET /orgs/{orgId}/menus/{id}
PUT /orgs/{orgId}/menus/{id}
PUT /orgs/{orgId}/menus/{id}/slots — replace the slot grid
POST /orgs/{orgId}/menus/{id}/plan/move — move a slot on the planner
POST /orgs/{orgId}/menus/{id}/plan/copy-day
POST /orgs/{orgId}/menus/{id}/submit-review — freeze a snapshot, status → pending_review
POST /orgs/{orgId}/menus/{id}/publish
Slots place a menu item at day (or date) × day part × station, with alternates and texture variants. Menus under RD review follow draft → pending_review → approved → published; signoffs record the decisions:
GET /orgs/{orgId}/signoffs
POST /orgs/{orgId}/signoffs — request a review
POST /orgs/{orgId}/signoffs/{id}/decide — approve/reject (requires the rd credential)
Assignments and the effective menu
GET /orgs/{orgId}/menu-assignments
POST /orgs/{orgId}/menu-assignments — place a cycle menu on a site calendar
PUT /orgs/{orgId}/menu-assignments/{id}
GET /orgs/{orgId}/effective-menu?siteId=…&date=YYYY-MM-DD
The effective menu resolves the assignment (anchor date + rotation weeks) for a site and date and returns the menu, the resolved cycle day, and slots grouped by day part — this is what production generation, tray lines, boards, and order lists consume:
{
"assignment": { "menuId": "ce60318d-...", "startDate": "2026-06-28", "anchorDate": "2026-07-06", "active": true },
"menu": { "id": "ce60318d-...", "name": "Tower Café Week", "kind": "cycle", "cycleWeeks": 1 },
"dayIndex": 5,
"dayParts": [ { "dayPart": "breakfast", "slots": [ ... ] } ]
}
Nutrition targets
GET/POST /orgs/{orgId}/population-targets — DRI-based or custom nutrient bands
PUT /orgs/{orgId}/population-targets/{id}
PUT /orgs/{orgId}/menus/{id}/population-target — attach to a menu
PUT /orgs/{orgId}/sites/{siteId}/population-target — site default
GET /orgs/{orgId}/menus/{id}/nutrition-check — band-by-band analysis
Content library
GET /orgs/{orgId}/content/packs
GET /orgs/{orgId}/content/packs/{key}
POST /orgs/{orgId}/content/packs/{key}/install — Pro+; {publish, includeMenus}
Installation clones the pack's recipes and cycle menus into the organization as editable records; it's idempotent — existing names are skipped.