Inventory AI agent on Telegram

Ask "how many black abayas size M are left?" or say "received 40 of SKU-102"; the agent reads and updates your stock sheet.

AI agentAdvanced Saves ~10 hours/month AI AgentsBy Flowngn team

Works with n8n · Make · Zapier

How it works

Trigger: Telegram — you message the bot
  1. You ask about stock or report a delivery or sale in plain words.
  2. The agent finds the product in your Stock sheet.
  3. For updates, it confirms the new quantity, then saves it.
  4. When items run low, it can draft a reorder email to the supplier.

What it can do

Unlike a fixed flow, an agent decides which of its tools to use, in what order — and remembers the conversation.

  • Answers stock questions by name, SKU, size or colour
  • Adds received stock and removes sold or damaged items
  • Lists everything under its reorder level
  • Drafts purchase orders to suppliers in Gmail

System prompt

The instructions that shape the agent. It's already inside the n8n template — copy it into Make or Zapier, and adjust the YOUR_… parts.

System prompt
You are the stock assistant for YOUR_SHOP on Telegram. You talk to our own team. Reply in their language (Arabic or English), short and clear. Today is {{ $now.toFormat('d LLLL yyyy') }}.

Tools:
- "Read stock": the Stock sheet (sku, product, size, colour, quantity, reorder_level, supplier, supplier_email). Always read it before answering or changing anything.
- "Update quantity": sets the new quantity for one SKU. Use only after the person confirms the SKU and the new number.
- "Draft reorder email": creates a Gmail draft to a supplier (never sends).

You can:
- Answer "how many … are left?" by product, SKU, size or colour.
- Record stock received, sold, returned or damaged: work out the new quantity from the current one, say "SKU-102: 12 → 52. Save?", and update only after a yes.
- List items at or below their reorder level, and draft reorder emails grouped by supplier when asked.

Rules:
- If more than one row matches, list them and ask which one. Never guess the SKU.
- Never set a negative quantity; ask the person to check instead.
- Never invent products, quantities or supplier details.

Safety rules

Built into the prompt and the tools:

  • Confirms every change before saving it
  • Only answers people in your team's Telegram chat
  • Drafts supplier emails, never sends them

Uses your own AI key (Claude, OpenAI or another model). Cost depends on the model and conversation length — a small, fast model keeps most conversations to a fraction of a cent.

Diagram

trueTIncoming messageTelegram Trigger{ }Get messageCode⑂From our team chat?IfStock agentAI AgentClaude modelAnthropic Chat Mo…◷MemorySimple MemoryGRead stockGoogle Sheets ToolGUpdate quantityGoogle Sheets ToolGDraft reorder …Gmail ToolTReply on TelegramTelegram
Trigger App Logic Code AI Agent tool

Code

JavaScript used in the Code step — already included in the template below.

Get message · Code node
// Keeps only text messages and pulls out who sent it and what they asked.
const msg = $input.first().json.message;
if (!msg?.text) return [];

return [{
  json: {
    chatId: msg.chat.id,
    userId: msg.from.id,
    name: [msg.from.first_name, msg.from.last_name].filter(Boolean).join(" "),
    question: msg.text,
  },
}];

Build it

Pick your tool — same automation, step by step.

Copy and paste straight into an n8n canvas (Ctrl+V), or download and use Import from File. Then connect your own credentials and replace every YOUR_… placeholder. AI steps use a Claude model node — swap it for OpenAI, Gemini or Ollama if you prefer.

Workflow JSON
Show code (341 lines)
{
  "name": "Inventory AI agent on Telegram (Flowngn)",
  "nodes": [
    {
      "parameters": {
        "content": "## Inventory AI agent on Telegram\nAsk \"how many black abayas size M are left?\" or say \"received 40 of SKU-102\"; the agent reads and updates your stock sheet.\n\n**Setup**\n1. Open each node and connect your own credentials.\n2. Replace every YOUR_… placeholder.\n3. Test once, then activate.\n\nFree template from Flowngn",
        "height": 260,
        "width": 340
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -60
      ]
    },
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Incoming message",
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.1,
      "position": [
        0,
        0
      ],
      "webhookId": "35c47c31-a6eb-4039-a611-85b8a1b7b74a"
    },
    {
      "parameters": {
        "jsCode": "// Keeps only text messages and pulls out who sent it and what they asked.\nconst msg = $input.first().json.message;\nif (!msg?.text) return [];\n\nreturn [{\n  json: {\n    chatId: msg.chat.id,\n    userId: msg.from.id,\n    name: [msg.from.first_name, msg.from.last_name].filter(Boolean).join(\" \"),\n    question: msg.text,\n  },\n}];"
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Get message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ String($json.chatId) }}",
              "rightValue": "YOUR_TEAM_CHAT_ID",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "From our team chat?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        600,
        0
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $('Get message').item.json.question }}",
        "options": {
          "systemMessage": "=You are the stock assistant for YOUR_SHOP on Telegram. You talk to our own team. Reply in their language (Arabic or English), short and clear. Today is {{ $now.toFormat('d LLLL yyyy') }}.\n\nTools:\n- \"Read stock\": the Stock sheet (sku, product, size, colour, quantity, reorder_level, supplier, supplier_email). Always read it before answering or changing anything.\n- \"Update quantity\": sets the new quantity for one SKU. Use only after the person confirms the SKU and the new number.\n- \"Draft reorder email\": creates a Gmail draft to a supplier (never sends).\n\nYou can:\n- Answer \"how many … are left?\" by product, SKU, size or colour.\n- Record stock received, sold, returned or damaged: work out the new quantity from the current one, say \"SKU-102: 12 → 52. Save?\", and update only after a yes.\n- List items at or below their reorder level, and draft reorder emails grouped by supplier when asked.\n\nRules:\n- If more than one row matches, list them and ask which one. Never guess the SKU.\n- Never set a negative quantity; ask the person to check instead.\n- Never invent products, quantities or supplier details."
        }
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Stock agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        900,
        0
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "claude-sonnet-5",
          "mode": "list"
        },
        "options": {}
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Claude model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        560,
        220
      ]
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Get message').item.json.chatId }}",
        "contextWindowLength": 10
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        730,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Returns the Stock sheet: sku, product, size, colour, quantity, reorder_level, supplier, supplier_email.",
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Stock",
          "mode": "name"
        },
        "options": {}
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Read stock",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        900,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Sets the new quantity for one SKU, after the person confirms.",
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Stock",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "sku": "={{ $fromAI('sku', \"The exact SKU\", 'string') }}",
            "quantity": "={{ $fromAI('quantity', \"The new quantity\", 'number') }}"
          },
          "matchingColumns": [
            "sku"
          ]
        },
        "options": {}
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Update quantity",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        1070,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Creates a Gmail draft purchase order to a supplier (never sends).",
        "resource": "draft",
        "operation": "create",
        "subject": "={{ $fromAI('subject', \"Email subject\", 'string') }}",
        "message": "={{ $fromAI('body', \"Email body listing SKUs, products and quantities to reorder\", 'string') }}",
        "options": {
          "sendTo": "={{ $fromAI('to', \"The supplier's email from the Stock sheet\", 'string') }}"
        }
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Draft reorder email",
      "type": "n8n-nodes-base.gmailTool",
      "typeVersion": 2.1,
      "position": [
        1240,
        220
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $('Get message').item.json.chatId }}",
        "text": "={{ $json.output }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "id": "35c47c31-a6eb-4039-a611-85b8a1b7b74a",
      "name": "Reply on Telegram",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [
        1200,
        0
      ]
    }
  ],
  "connections": {
    "Incoming message": {
      "main": [
        [
          {
            "node": "Get message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get message": {
      "main": [
        [
          {
            "node": "From our team chat?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "From our team chat?": {
      "main": [
        [
          {
            "node": "Stock agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stock agent": {
      "main": [
        [
          {
            "node": "Reply on Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude model": {
      "ai_languageModel": [
        [
          {
            "node": "Stock agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Memory": {
      "ai_memory": [
        [
          {
            "node": "Stock agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Read stock": {
      "ai_tool": [
        [
          {
            "node": "Stock agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update quantity": {
      "ai_tool": [
        [
          {
            "node": "Stock agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Draft reorder email": {
      "ai_tool": [
        [
          {
            "node": "Stock agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

Open in the playground to edit →

Tips

  • Give each product a unique SKU. It stops the agent from updating the wrong row.

Related flows