AutomationFlowsSlack & Telegram › Confirm and Log Whatsapp Restaurant Orders with Groq and Google Sheets

Confirm and Log Whatsapp Restaurant Orders with Groq and Google Sheets

ByKanishka Shrivastava @kanishka-shrivastava on n8n.io

This workflow triggers on incoming WhatsApp orders, uses Groq to extract items and quantities, validates them against a live Google Sheets menu, logs the result to an orders sheet, and replies to the customer with either a clarification request or a priced confirmation (with…

Event trigger★★★★☆ complexityAI-powered22 nodesWhatsApp TriggerChain LlmGroq ChatOutput Parser StructuredGoogle SheetsWhatsApp
Slack & Telegram Trigger: Event Nodes: 22 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #17044 — we link there as the canonical source.

This workflow follows the Chainllm → Google Sheets recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "EVTOyLitCKuudkS3",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Confirm restaurant orders from WhatsApp with Groq and Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "a068f197-276f-48f4-b3ae-8958d4be0aee",
      "name": "Template Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        112
      ],
      "parameters": {
        "color": 4,
        "width": 700,
        "height": 1008,
        "content": "## \ud83c\udf5b Confirm Restaurant Orders from WhatsApp with Groq and Google Sheets\n\n## Who's it for\nSmall restaurants and cloud kitchens taking orders over WhatsApp who want orders automatically validated against their menu, priced, logged, and confirmed, without a staff member manually reading and tallying every message.\n\n## How it works\nA customer sends their order over WhatsApp. Groq parses the items and quantities, then the workflow checks each item against your live menu sheet (name match and availability) and calculates the total. If anything doesn't match the menu or is unavailable, the customer gets an automatic reply asking them to correct it, nothing gets logged as a real order until it's valid. Once valid, the order is logged to Google Sheets, the customer gets a confirmation with the total, and if the order is above a configurable amount, the owner gets a separate WhatsApp alert for VIP handling.\n\n## How to set up\n1. Connect your WhatsApp Business Cloud credentials to the trigger and both send nodes.\n2. Connect your Groq API credentials to the Chat Model node.\n3. Connect your Google Sheets credentials and create two tabs: Menu and Orders (see the sticky notes near each Sheets node for required columns).\n4. Open the Set Configuration node and fill in your Sheet ID, WhatsApp phone number ID, owner notification number, and VIP order threshold.\n5. Activate the workflow.\n\n## Requirements\n- WhatsApp Business Cloud API access\n- Groq API key\n- Google Sheets account\n\n## How to customize\nEdit the confirmation and clarification message templates to match your restaurant's tone. Adjust the VIP threshold in Set Configuration, or remove that branch entirely if you don't need it."
      },
      "typeVersion": 1
    },
    {
      "id": "0fcbb70d-ac1c-4fc6-bbfb-c0e23e432332",
      "name": "Trigger Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 208,
        "content": "## 1\ufe0f\u20e3 Trigger\nFires on every incoming WhatsApp message. Connect your restaurant's WhatsApp Business number here."
      },
      "typeVersion": 1
    },
    {
      "id": "4eb73868-2732-4814-9d3d-31918fd90649",
      "name": "New WhatsApp Order",
      "type": "n8n-nodes-base.whatsAppTrigger",
      "position": [
        928,
        704
      ],
      "parameters": {
        "options": {},
        "updates": [
          "messages"
        ]
      },
      "credentials": {
        "whatsAppTriggerApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d0e98056-0ade-46f6-9d1f-5c57b7d98d6f",
      "name": "Set Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        1200,
        704
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-1",
              "name": "restaurant_name",
              "type": "string",
              "value": "REPLACE_WITH_RESTAURANT_NAME"
            },
            {
              "id": "cfg-2",
              "name": "whatsapp_phone_number_id",
              "type": "string",
              "value": "REPLACE_WITH_WHATSAPP_PHONE_NUMBER_ID"
            },
            {
              "id": "cfg-3",
              "name": "owner_notify_number",
              "type": "string",
              "value": "REPLACE_WITH_OWNER_WHATSAPP_NUMBER"
            },
            {
              "id": "cfg-4",
              "name": "vip_order_threshold",
              "type": "number",
              "value": 1000
            },
            {
              "id": "cfg-5",
              "name": "sheet_id",
              "type": "string",
              "value": "REPLACE_WITH_GOOGLE_SHEET_ID"
            },
            {
              "id": "cfg-6",
              "name": "menu_sheet_name",
              "type": "string",
              "value": "Menu"
            },
            {
              "id": "cfg-7",
              "name": "orders_sheet_name",
              "type": "string",
              "value": "Orders"
            },
            {
              "id": "cfg-8",
              "name": "raw_message",
              "type": "string",
              "value": "={{ $json.messages[0].text.body }}"
            },
            {
              "id": "cfg-9",
              "name": "sender_number",
              "type": "string",
              "value": "={{ $json.messages[0].from }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "85c3a245-83b9-4e53-bffe-768cbc974037",
      "name": "Extraction Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1408,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 192,
        "content": "## 2\ufe0f\u20e3 AI Extraction\nGroq parses the WhatsApp message into a list of items and quantities. It doesn't validate against your menu, that happens next."
      },
      "typeVersion": 1
    },
    {
      "id": "32f6e8b1-fc34-4ba9-a4bf-61d526c854b6",
      "name": "Extract Order Items",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1440,
        704
      ],
      "parameters": {
        "text": "=Extract the food items and quantities the customer is ordering from this WhatsApp message. If a quantity isn't mentioned, assume 1.\n\nMessage: {{ $('Set Configuration').item.json.raw_message }}",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.8
    },
    {
      "id": "35a36f85-101f-4e4a-a136-7e9f28f138ef",
      "name": "Groq Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGroq",
      "position": [
        1408,
        912
      ],
      "parameters": {
        "model": "llama-3.3-70b-versatile",
        "options": {}
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ad3fc9cb-a692-427a-9c0e-25c7119403f7",
      "name": "Order Items Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1600,
        912
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n  \"type\": \"object\",\n  \"properties\": {\n    \"items\": {\n      \"type\": \"array\",\n      \"items\": {\n        \"type\": \"object\",\n        \"properties\": {\n          \"item_name\": {\n            \"type\": \"string\"\n          },\n          \"quantity\": {\n            \"type\": \"number\"\n          }\n        },\n        \"required\": [\n          \"item_name\",\n          \"quantity\"\n        ]\n      }\n    }\n  },\n  \"required\": [\n    \"items\"\n  ]\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "d58308ee-25d2-41da-8b8f-bd3286b0de18",
      "name": "Menu Read Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1776,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 212,
        "content": "## 3\ufe0f\u20e3 Read Live Menu\nReads your Menu sheet fresh on every order, so price/availability changes take effect immediately. Required columns: item_name, price, available."
      },
      "typeVersion": 1
    },
    {
      "id": "dd27b273-184a-4fab-8e61-8c4fd3644da3",
      "name": "Read Menu Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1840,
        704
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.menu_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.sheet_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "0ad486f3-9481-4db7-b9db-ce9f1e7bf792",
      "name": "Validation Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2128,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 216,
        "content": "## 4\ufe0f\u20e3 Validate + Price\nMatches each parsed item against the menu, checks availability, and calculates the total. Anything that doesn't match becomes an issue that blocks the order until it's corrected."
      },
      "typeVersion": 1
    },
    {
      "id": "b460bd6e-2b74-4299-b63c-13dbc7cb0c98",
      "name": "Validate & Price Order",
      "type": "n8n-nodes-base.code",
      "position": [
        2128,
        704
      ],
      "parameters": {
        "jsCode": "const menuRows = $('Read Menu Sheet').all().map(item => item.json);\nconst orderedItems = $json.output.items || [];\n\nlet total = 0;\nlet issues = [];\nlet lineItems = [];\n\nfor (const ordered of orderedItems) {\n  const menuItem = menuRows.find(m =>\n    String(m.item_name).toLowerCase().trim() === String(ordered.item_name).toLowerCase().trim()\n  );\n\n  if (!menuItem) {\n    issues.push(`\"${ordered.item_name}\" isn't on the menu`);\n    continue;\n  }\n\n  const isAvailable = String(menuItem.available).toLowerCase() !== 'false';\n  if (!isAvailable) {\n    issues.push(`\"${ordered.item_name}\" is currently unavailable`);\n    continue;\n  }\n\n  const price = parseFloat(menuItem.price) || 0;\n  const qty = parseInt(ordered.quantity) || 1;\n  const subtotal = price * qty;\n  total += subtotal;\n\n  lineItems.push({\n    item_name: ordered.item_name,\n    quantity: qty,\n    price: price,\n    subtotal: subtotal\n  });\n}\n\nreturn [{\n  json: {\n    total_price: total,\n    line_items: lineItems,\n    order_summary: lineItems.map(li => `${li.quantity}x ${li.item_name}`).join(', '),\n    issues: issues,\n    issues_summary: issues.join('; '),\n    has_issues: issues.length > 0\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "833b17f4-be43-4d2e-b9bc-1897f6f6cab7",
      "name": "Are There Issues?",
      "type": "n8n-nodes-base.if",
      "position": [
        2400,
        704
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f1fe1f5a-fb14-4f17-a577-6dcc2856450c",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.has_issues }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b302cce6-ebd5-4f04-9fb5-6bc89999a636",
      "name": "Issues Branch Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        976
      ],
      "parameters": {
        "color": 7,
        "width": 316,
        "height": 192,
        "content": "## \u274c If Something's Off\nAsks the customer to correct their order and logs the attempt so nothing valid gets silently dropped, but nothing invalid gets confirmed either."
      },
      "typeVersion": 1
    },
    {
      "id": "8e42729b-435f-42e2-b748-13df0a5ac64b",
      "name": "Ask for Clarification",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        2688,
        1200
      ],
      "parameters": {
        "textBody": "=Sorry, a couple of things in your order need fixing: {{ $json.issues_summary }}. Could you resend the corrected order?",
        "operation": "send",
        "phoneNumberId": "={{ $('Set Configuration').item.json.whatsapp_phone_number_id }}",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration').item.json.sender_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2860a2bf-f83d-4479-b70c-67821f2deee5",
      "name": "Log Clarification Needed",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2944,
        1200
      ],
      "parameters": {
        "columns": {
          "value": {
            "notes": "={{ $json.issues_summary }}",
            "status": "needs_clarification",
            "total_price": "={{ $('Validate & Price Order').item.json.total_price }}",
            "order_summary": "={{ $('Validate & Price Order').item.json.order_summary }}",
            "customer_phone": "={{ $('Set Configuration').item.json.sender_number }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.orders_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.sheet_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "dfddbf8a-e1a8-41bf-bb45-8f6f80f25d5b",
      "name": "Confirmed Branch Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2624,
        480
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 196,
        "content": "## \u2705 If Valid\nLogs the order, confirms it to the customer, and separately checks whether it clears the VIP threshold for an owner alert. Both happen off the same log step."
      },
      "typeVersion": 1
    },
    {
      "id": "ce2ee97c-58db-42f8-b28a-82b760b862d7",
      "name": "Log Confirmed Order",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2688,
        688
      ],
      "parameters": {
        "columns": {
          "value": {
            "notes": "",
            "status": "confirmed",
            "total_price": "={{ $json.total_price }}",
            "order_summary": "={{ $json.order_summary }}",
            "customer_phone": "={{ $('Set Configuration').item.json.sender_number }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.orders_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.sheet_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "72d1dd44-f808-4568-a9fc-c1c669377e3d",
      "name": "Send Order Confirmation",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        3088,
        688
      ],
      "parameters": {
        "textBody": "=Order confirmed: {{ $('Validate & Price Order').item.json.order_summary }}. Total: \u20b9{{ $('Validate & Price Order').item.json.total_price }}. We'll have it ready shortly!",
        "operation": "send",
        "phoneNumberId": "={{ $('Set Configuration').item.json.whatsapp_phone_number_id }}",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration').item.json.sender_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b28a6540-a3bd-4e9f-869a-1971b103472b",
      "name": "Is VIP Order?",
      "type": "n8n-nodes-base.if",
      "position": [
        2928,
        816
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5662eead-7687-4a57-8303-b1d76dc85442",
              "operator": {
                "type": "number",
                "operation": "gte"
              },
              "leftValue": "={{ $('Validate & Price Order').item.json.total_price }}",
              "rightValue": "={{ $('Set Configuration').item.json.vip_order_threshold }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "16a53905-af7f-44c6-b586-be4b628c548c",
      "name": "Notify Owner - VIP Order",
      "type": "n8n-nodes-base.whatsApp",
      "position": [
        3248,
        800
      ],
      "parameters": {
        "textBody": "=Large order just came in: \u20b9{{ $('Validate & Price Order').item.json.total_price }} from {{ $('Set Configuration').item.json.sender_number }}. {{ $('Validate & Price Order').item.json.order_summary }}",
        "operation": "send",
        "phoneNumberId": "={{ $('Set Configuration').item.json.whatsapp_phone_number_id }}",
        "additionalFields": {},
        "recipientPhoneNumber": "={{ $('Set Configuration').item.json.owner_notify_number }}"
      },
      "credentials": {
        "whatsAppApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "dcd828cf-1f40-44b0-9b40-7ba31643fa4b",
      "name": "Sheets Schema Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3184,
        1120
      ],
      "parameters": {
        "color": 7,
        "width": 300,
        "height": 224,
        "content": "## Sheets Schema\nMenu tab: item_name, price, available (TRUE/FALSE).\nOrders tab: customer_phone, order_summary, total_price, status, notes."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "03e1edca-9d73-442e-96f9-06005895ee21",
  "nodeGroups": [],
  "connections": {
    "Is VIP Order?": {
      "main": [
        [
          {
            "node": "Notify Owner - VIP Order",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Groq Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Extract Order Items",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Read Menu Sheet": {
      "main": [
        [
          {
            "node": "Validate & Price Order",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Are There Issues?": {
      "main": [
        [
          {
            "node": "Log Confirmed Order",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ask for Clarification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration": {
      "main": [
        [
          {
            "node": "Extract Order Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New WhatsApp Order": {
      "main": [
        [
          {
            "node": "Set Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Order Items Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Extract Order Items",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Extract Order Items": {
      "main": [
        [
          {
            "node": "Read Menu Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Confirmed Order": {
      "main": [
        [
          {
            "node": "Send Order Confirmation",
            "type": "main",
            "index": 0
          },
          {
            "node": "Is VIP Order?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ask for Clarification": {
      "main": [
        [
          {
            "node": "Log Clarification Needed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate & Price Order": {
      "main": [
        [
          {
            "node": "Are There Issues?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow triggers on incoming WhatsApp orders, uses Groq to extract items and quantities, validates them against a live Google Sheets menu, logs the result to an orders sheet, and replies to the customer with either a clarification request or a priced confirmation (with…

Source: https://n8n.io/workflows/17044/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

This comprehensive N8N automation template revolutionizes content creation by delivering a complete end-to-end solution for AI-powered blog generation. Transform simple ideas into fully SEO-optimized,

Slack Trigger, Telegram Trigger, Gmail Trigger +16
Slack & Telegram

End-to-End Video Creation from user idea or transcript AI-Powered Scriptwriting using LLMs (e.g., DeepSeek via OpenRouter) Voiceover Generation with customizable TTS voices Image Scene Generation usin

HTTP Request, Form Trigger, Output Parser Structured +6
Slack & Telegram

Menu-Handler. Uses telegramTrigger, chatTrigger, executeWorkflowTrigger, chainLlm. Event-driven trigger; 28 nodes.

Telegram Trigger, Chat Trigger, Execute Workflow Trigger +7
Slack & Telegram

Supplier Churn Prediction & Retention Workflow. Uses notion, chainLlm, lmChatGroq, outputParserStructured. Event-driven trigger; 21 nodes.

Notion, Chain Llm, Groq Chat +2
Slack & Telegram

AI-Driven WooCommerce Product Importer with SEO. Uses manualTrigger, lmChatOpenRouter, chainLlm, googleSheets. Event-driven trigger; 16 nodes.

OpenRouter Chat, Chain Llm, Google Sheets +3