Sales CRM AI agent on Telegram

Your sales team adds leads, logs calls and asks "who should I call today?" in plain words on Telegram.

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

Works with n8n · Make · Zapier

How it works

Trigger: Telegram — a salesperson messages the bot
  1. A salesperson writes "called Mona from Nile Foods, wants a proposal by Thursday".
  2. The agent finds the lead and updates its stage, next step and last contact.
  3. It answers questions about the pipeline and who to follow up with.
  4. It drafts follow-up emails in Gmail.

What it can do

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

  • Adds and updates leads from plain messages
  • Lists today's follow-ups
  • Summarises the pipeline by stage
  • Drafts follow-up emails

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 sales assistant for YOUR_COMPANY on Telegram, talking to our own sales team. Reply in their language, short and clear. Today is {{ $now.toFormat('cccc d LLLL yyyy') }}.

Tools:
- "Read leads": the Leads sheet (phone, name, company, email, stage, value, owner, next_step, last_contact). Read it before answering anything.
- "Add lead": adds a new lead. Ask for at least name and phone, plus anything they mention (company, need, value).
- "Update lead": updates one lead by its phone number: stage, next step, value or last contact. Stages: new, contacted, meeting, proposal, won, lost.
- "Draft email": creates a Gmail draft to a lead (never sends).

You can:
- Answer "who should I call today?": open leads with the oldest last_contact or a next_step due today.
- Log calls and meetings in plain words ("called Mona from Nile Foods, wants a proposal by Thursday") as a lead update.
- Summarise the pipeline by stage with totals.
- Draft follow-up emails.

Rules:
- Confirm before changing a stage to won or lost.
- If more than one lead matches, list them and ask which one. Never guess.
- Never invent leads, numbers or promises.

Safety rules

Built into the prompt and the tools:

  • Only answers your sales team's Telegram chat
  • Asks before marking a deal won or lost
  • Drafts 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 sales chat?IfSales agentAI AgentClaude modelAnthropic Chat Mo…◷MemorySimple MemoryGRead leadsGoogle Sheets ToolGAdd leadGoogle Sheets ToolGUpdate leadGoogle Sheets ToolGDraft emailGmail 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 (394 lines)
{
  "name": "Sales CRM AI agent on Telegram (Flowngn)",
  "nodes": [
    {
      "parameters": {
        "content": "## Sales CRM AI agent on Telegram\nYour sales team adds leads, logs calls and asks \"who should I call today?\" in plain words on Telegram.\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": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -60
      ]
    },
    {
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Incoming message",
      "type": "n8n-nodes-base.telegramTrigger",
      "typeVersion": 1.1,
      "position": [
        0,
        0
      ],
      "webhookId": "4582ffa0-b14a-4886-a363-b883185e0565"
    },
    {
      "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": "4582ffa0-b14a-4886-a363-b883185e0565",
      "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_SALES_CHAT_ID",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "From our sales 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 sales assistant for YOUR_COMPANY on Telegram, talking to our own sales team. Reply in their language, short and clear. Today is {{ $now.toFormat('cccc d LLLL yyyy') }}.\n\nTools:\n- \"Read leads\": the Leads sheet (phone, name, company, email, stage, value, owner, next_step, last_contact). Read it before answering anything.\n- \"Add lead\": adds a new lead. Ask for at least name and phone, plus anything they mention (company, need, value).\n- \"Update lead\": updates one lead by its phone number: stage, next step, value or last contact. Stages: new, contacted, meeting, proposal, won, lost.\n- \"Draft email\": creates a Gmail draft to a lead (never sends).\n\nYou can:\n- Answer \"who should I call today?\": open leads with the oldest last_contact or a next_step due today.\n- Log calls and meetings in plain words (\"called Mona from Nile Foods, wants a proposal by Thursday\") as a lead update.\n- Summarise the pipeline by stage with totals.\n- Draft follow-up emails.\n\nRules:\n- Confirm before changing a stage to won or lost.\n- If more than one lead matches, list them and ask which one. Never guess.\n- Never invent leads, numbers or promises."
        }
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Sales 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": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Claude model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        475,
        220
      ]
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Get message').item.json.chatId }}",
        "contextWindowLength": 10
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        645,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Returns the Leads sheet.",
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Leads",
          "mode": "name"
        },
        "options": {}
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Read leads",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        815,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Adds a new lead.",
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Leads",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "phone": "={{ $fromAI('phone', \"Phone number with country code\", 'string') }}",
            "name": "={{ $fromAI('name', \"Contact name\", 'string') }}",
            "company": "={{ $fromAI('company', \"Company, or empty\", 'string') }}",
            "email": "={{ $fromAI('email', \"Email, or empty\", 'string') }}",
            "stage": "new",
            "value": "={{ $fromAI('value', \"Estimated deal value, or empty\", 'string') }}",
            "owner": "={{ $('Get message').item.json.name }}",
            "next_step": "={{ $fromAI('next_step', \"Next step, or empty\", 'string') }}",
            "last_contact": "={{ $now.toISODate() }}"
          }
        },
        "options": {}
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Add lead",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        985,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Updates one lead, matched by phone number.",
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Leads",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "phone": "={{ $fromAI('phone', \"The lead's phone number exactly as in the sheet\", 'string') }}",
            "stage": "={{ $fromAI('stage', \"new, contacted, meeting, proposal, won or lost\", 'string') }}",
            "next_step": "={{ $fromAI('next_step', \"The next step and its date\", 'string') }}",
            "last_contact": "={{ $fromAI('last_contact', \"Date of the last contact, YYYY-MM-DD\", 'string') }}"
          },
          "matchingColumns": [
            "phone"
          ]
        },
        "options": {}
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Update lead",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        1155,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Creates a Gmail draft to a lead (never sends).",
        "resource": "draft",
        "operation": "create",
        "subject": "={{ $fromAI('subject', \"Email subject\", 'string') }}",
        "message": "={{ $fromAI('body', \"Email body\", 'string') }}",
        "options": {
          "sendTo": "={{ $fromAI('to', \"The recipient's email address\", 'string') }}"
        }
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "name": "Draft email",
      "type": "n8n-nodes-base.gmailTool",
      "typeVersion": 2.1,
      "position": [
        1325,
        220
      ]
    },
    {
      "parameters": {
        "chatId": "={{ $('Get message').item.json.chatId }}",
        "text": "={{ $json.output }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "id": "4582ffa0-b14a-4886-a363-b883185e0565",
      "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 sales chat?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "From our sales chat?": {
      "main": [
        [
          {
            "node": "Sales agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sales agent": {
      "main": [
        [
          {
            "node": "Reply on Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude model": {
      "ai_languageModel": [
        [
          {
            "node": "Sales agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Memory": {
      "ai_memory": [
        [
          {
            "node": "Sales agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Read leads": {
      "ai_tool": [
        [
          {
            "node": "Sales agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Add lead": {
      "ai_tool": [
        [
          {
            "node": "Sales agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update lead": {
      "ai_tool": [
        [
          {
            "node": "Sales agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Draft email": {
      "ai_tool": [
        [
          {
            "node": "Sales agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

Open in the playground to edit →

Tips

  • Use the phone number as the lead's key, and keep it in one format.

Related flows