Hi everyone, I’m Kushal Sapkota, an independent developer from Panauti, Nepal. I built an AI ordering agent in n8n for a cake shop (a client project) and wanted to share how it’s structured and what went wrong along the way. It has been running in production for the client.
The problem
- Customers write in Nepali, Roman Nepali and English, often mixed in one message.
- Orders arrive as text, voice notes, photos and payment screenshots.
- The owner is not technical, so behaviour has to be changeable without me.
- Money is involved, so the model must never decide that something is paid.
- Failures have to be visible, never silent.
Shape of the workflow
98 nodes across 5 n8n workflows, 2 channels (WhatsApp via the 360dialog API, and website chat), 3 languages.
WhatsApp / web chat
→ webhook → dedupe → voice to text / image fetch
→ gate: is this chat paused for staff? owner settings
→ AI agent (LLM + memory + 5 SQL tools + structured output)
→ code guards: feature flags, items valid?, date valid?, fee calculation
→ reply + photos + payment QR · save order · Telegram alert to the owner
State: PostgreSQL (orders, settings, memory), admin panel, shared inbox
Decisions that mattered
- The model proposes, code decides. The owner’s feature switches are re-checked in code after the model answers, so “off” really means off. Totals and delivery fees are computed in SQL, never by the model.
- Structured output. The agent returns one customer reply plus machine-readable fields. A parser fixes the shape before anything downstream runs, and the agent never writes to the database.
- SQL tools instead of memorised facts. Five tools (cakes, occasions, delivery zones, time slots, payment methods). A price changed in the admin panel is used by the bot on the next message.
- Payment proofs. A vision model reads the paid amount, with a backup model if the first fails. The result only flags the order for the owner to confirm. The AI cannot mark an order paid.
- Behaviour as data. The owner flips switches, edits FAQs and adds holiday notices in an admin panel; a Postgres function composes them into the prompt.
- Humans stay in the loop. One inbox for both channels. A staff reply pauses the bot for that customer, and the owner gets a Telegram alert when it needs help.
- Test on a copy, never the live shop. Tests run on a copy of the workflow with every send node disabled and fake phone numbers. Each deploy is diffed node by node.
What broke
- Website chat went silent for about an hour. A regenerated workflow was left inactive. I now check every workflow’s active flag after each deploy.
- A test left the bot stuck on “always English”. A Roman Nepali customer got an English reply. Tests now restore production defaults.
- Meta rejected Nepali-script documents, twice, during WhatsApp business verification. Compliance turned out to be part of the system design.
Questions for the community
- How do you handle debounce when customers send several short messages in a row?
- Any patterns for versioning and diffing workflows across deploys?
I’m happy to go deeper on any part of this (I can’t share the client’s data or credentials). More about my work: https://kushal.aafaiai.com · GitHub: kushal867 (Kushal Sapkota) · GitHub