Back to Alchemy
Alchemy RecipeAdvancedautomation

Restaurant menu engineering from sales data and supplier cost sheets

28 March 2026

Introduction Most restaurants operate on thin margins, yet they make menu decisions based on outdated assumptions and incomplete data.

A dish might appear profitable on paper because it has a high menu price, but when you factor in actual supplier costs (which fluctuate weekly), waste, portion creep, and real sales velocity from your point-of-sale system, the true contribution margin tells a very different story. Managers who discover this truth usually do so months too late, after the damage to profitability is already done. The problem compounds because the data exists in silos. Your POS system knows what sold and at what price. Your supplier invoices know what ingredients actually cost. Your recipe documentation knows portion sizes and yields. But nobody is connecting these dots automatically. Instead, a manager spends an afternoon each week pulling spreadsheets, manually calculating margins, and making gut-feel decisions about which dishes to promote, reprice, or remove. This workflow automates that entire process. By connecting your POS data to supplier costs and recipe information, you can identify which dishes are genuinely profitable within hours of receiving new pricing, then use AI to generate optimised recipe variations that maintain margin while preserving what customers love about your menu.

The Automated Workflow This solution uses n8n as the orchestration backbone, running on a schedule to pull fresh data from your POS and accounting systems, then passing it through a data analysis layer before generating actionable menu recommendations.

Step 1: Extract POS sales data

The workflow starts each morning by querying your POS system's API. Most modern systems (Toast, Square, TouchBistro, MarginEdge) expose historical sales and inventory data. We'll assume Square here, but the pattern works with any REST API.

GET https://connect.squareup.com/v2/locations/{location_id}/orders
?begin_time=2026-03-15T00:00:00Z&end_time=2026-03-15T23:59:59Z&state=COMPLETED
Headers: Authorization: Bearer {square_access_token}

Create an n8n HTTP Request node configured as follows:

json
{ "method": "GET", "url": "https://connect.squareup.com/v2/locations/{{ $env.SQUARE_LOCATION_ID }}/orders", "headers": { "Authorization": "Bearer {{ $env.SQUARE_ACCESS_TOKEN }}" }, "qs": { "begin_time": "{{ $now.toISO().split('T')[0] }}T00:00:00Z", "end_time": "{{ $now.toISO().split('T')[0] }}T23:59:59Z", "state": "COMPLETED" }
}

This returns an array of completed orders with item names, quantities sold, and revenue. n8n will parse this JSON response automatically.

Step 2: Fetch current supplier costs

Simultaneously, pull pricing from your accounting system (QuickBooks, Xero) or supplier platforms. If your suppliers email cost sheets, you could use a Gmail trigger to capture them, but a direct API call is more reliable. Here's a QuickBooks example:

GET https://quickbooks.api.intuit.com/v2/companyid/query
?query=select * from Item where Type='Inventory'
Headers: Authorization: Bearer {access_token}

In n8n, add a second HTTP Request node:

json
{ "method": "GET", "url": "https://quickbooks.api.intuit.com/v2/{{ $env.QB_COMPANY_ID }}/query", "headers": { "Authorization": "Bearer {{ $env.QB_ACCESS_TOKEN }}" }, "qs": { "query": "select * from Item where Type='Inventory'" }
}

This returns current costs for each ingredient in your inventory.

Step 3: Transform and calculate margins in Deepnote

Rather than trying to do complex calculations in n8n, pass both datasets (sales and costs) to Deepnote, which excels at data analysis. Create a Deepnote notebook that runs via API trigger. n8n can invoke it like this:

json
{ "method": "POST", "url": "https://api.deepnote.com/v1/projects/{{ $env.DEEPNOTE_PROJECT_ID }}/notebooks/{{ $env.DEEPNOTE_NOTEBOOK_ID }}/run", "headers": { "Authorization": "Bearer {{ $env.DEEPNOTE_API_KEY }}" }, "body": { "poszData": "{{ JSON.stringify($node['Square Orders'].data) }}", "costData": "{{ JSON.stringify($node['QB Costs'].data) }}" }
}

Inside Deepnote, write Python code to: 1. Merge sales quantities with ingredient costs 2. Calculate food cost percentage for each dish sold 3. Rank dishes by contribution margin (revenue minus COGS) 4. Identify low-margin dishes and high-volume items Here's a simplified example:

python
import pandas as pd
import json # Parse inputs
pos_data = json.loads(notebook.params['poszData'])
cost_data = json.loads(notebook.params['costData']) # Create DataFrames
sales_df = pd.DataFrame([ {'item_name': order['item'], 'qty': order['quantity'], 'price': order['price']} for order in pos_data
]) costs_df = pd.DataFrame([ {'ingredient': item['name'], 'unit_cost': item['unit_cost']} for item in cost_data
]) # Aggregate by dish
daily_sales = sales_df.groupby('item_name').agg({ 'qty': 'sum', 'price': 'sum'
}).reset_index() # (In reality, you'd join this to recipe data to calculate COGS per dish)
daily_sales['margin_pct'] = (daily_sales['margin'] / daily_sales['price'] * 100).round(1) # Sort by margin and volume
daily_sales = daily_sales.sort_values('margin', ascending=False) # Identify problem dishes (low margin, decent volume)
problem_dishes = daily_sales[ (daily_sales['margin_pct'] < 25) & (daily_sales['qty'] > 10)
] print(daily_sales)
print("\n--- Low-Margin, High-Volume Dishes ---")
print(problem_dishes)

Deepnote outputs a CSV or JSON file with ranked dishes, which n8n can retrieve and store.

Step 4: Generate recipe optimisations with Tastebuds AI

For each low-margin dish, call Tastebuds AI to generate cost-optimised recipe variations. Tastebuds has a public API that lets you request recipe modifications based on constraints like target food cost or ingredient swaps.

json
{ "method": "POST", "url": "https://api.tastebujds.ai/v1/recipes/optimise", "headers": { "Authorization": "Bearer {{ $env.TASTEBUDS_API_KEY }}" }, "body": { "dishName": "{{ item.name }}", "currentRecipe": "{{ item.recipe }}", "targetFoodCost": "{{ item.currentCost * 0.85 }}", "constraints": ["preserve_core_flavor", "maintain_plating"] }
}

Tastebuds returns suggestions like "reduce X ingredient by Y grams" or "substitute Y with Z" along with revised nutritional data (backed by USDA standards). n8n loops this for each problem dish.

Step 5: Compile and send recommendations

Use n8n's Email node to send a formatted report to your manager:

Subject: Daily Menu Optimisation Report - {{ $now.toFormat('yyyy-MM-dd') }} High Performers (>40% margin):
- [Dish names and margins] Optimisation Opportunities (20-35% margin):
- [Dish names with suggested recipe changes] Recipe Adjustments Generated:
- [Tastebuds AI suggestions with new cost estimates] Next Steps:
1. Review Tastebuds suggestions in the attached spreadsheet
2. Taste-test proposed variations
3. Update menu prices or recipes in Square

Attach the Deepnote output CSV as a spreadsheet for manual review. Orchestration tool choice: n8n We use n8n here rather than Zapier or Make because: 1. You need conditional logic (only send Tastebuds requests for dishes below a margin threshold) 2. You need to loop over multiple dishes without hitting rate limits 3. You need to transform and merge data between systems 4. n8n's self-hosted version keeps API keys on your own infrastructure If you prefer cloud hosting, Zapier works too, but you'll need more separate zaps and lose some control over sequencing.

The Manual Alternative If you want direct control without full automation, use Deepnote standalone.

Upload your POS and cost CSV files, run the margin analysis manually each week, review the output, then manually log into Tastebuds AI to generate recipe variations. This takes 1 to 2 hours per week but costs nothing beyond the tool subscriptions. It's a reasonable middle ground if you're uncertain about the data quality or don't want to commit to automation yet. Alternatively, hire a freelance data analyst on Upwork for £15-25 per hour to set up the Deepnote analysis and send you weekly reports. You'll spend £300-500 per month but avoid orchestration complexity.

Pro Tips Monitor API rate limits. Square allows 200 requests per second; QuickBooks allows 500 per day.

If you have multiple locations, stagger requests across your workflow to avoid hitting these ceilings. n8n's Rate Limit node helps. Cache cost data. Don't fetch supplier costs more than once daily. Store them in n8n's built-in data store or a cheap PostgreSQL database so you can run margin calculations hourly without hammering your accounting API. Validate recipe data upstream. Tastebuds AI works best with standardised recipe formats (grams, ml, units). Before sending to Tastebuds, validate that your recipes are complete and consistent. Missing ingredients or portion sizes will cause bad suggestions. Set confidence thresholds. Don't automatically reprice dishes based on margin alone. Flag them for human review. A dish with 22% margin might still be worth keeping if it drives traffic or complements high-margin items. Track changes over time. Store daily margin reports in a Google Sheet or lightweight database. You'll spot seasonal trends, supplier cost swings, and the impact of menu changes. This historical data is very useful for spotting patterns a single report can't show.

Cost Breakdown

ToolPlan NeededMonthly CostNotes
n8nCloud Pro or Self-hosted Open Source£20-100 (cloud) or £0 (self-hosted)Pro includes 10,000 executions; self-hosted needs your server
DeepnoteFree or Professional£0-25Free tier has limits; Professional adds priority compute
Tastebuds AIStandard£30-80Pay-per-recipe or monthly; typically £50 for 100+ recipe analyses
Square APIIncluded with Square account£0No extra charge for API access
QuickBooks APIIncluded with QB subscription£0Requires QB Plus or higher (starts £50/month)
Total,£50-205Varies by choice of n8n hosting and tool tiers