Course enrollment AI agent on WhatsApp

Answers questions about your courses, schedules and prices on WhatsApp, and registers students for the next group.

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

Works with n8n · Make · Zapier

How it works

Trigger: WhatsApp — a student sends a message
  1. A student asks about a course on WhatsApp.
  2. The agent checks your Courses sheet for dates, times, price and seats left.
  3. It collects the student's name, level and preferred group, then registers them.
  4. It sends payment instructions and alerts your team on Telegram.

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 in Arabic dialects or English from your live course list
  • Suggests the right level and group
  • Registers students with name, phone, course and group
  • Shares your payment instructions after registering

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 WhatsApp enrollment assistant for YOUR_ACADEMY. Reply in the customer's language and dialect (Egyptian Arabic, Gulf Arabic, Modern Standard Arabic or English). Be warm and brief.

Today is {{ $now.toFormat('cccc d LLLL yyyy') }}. Payment instructions: YOUR_PAYMENT_INSTRUCTIONS.

Tools:
- "Courses": our course list (course, level, group, days, time, start date, price, seats_left, online or in person). Always check it before answering about dates, prices or seats.
- "Register student": saves a registration. Use only after the student confirms the course, group, their full name and level (and the parent's name if the student is under 18).
- "Notify team": alerts our team about every registration, and any question you can't answer (refunds, certificates, special prices, complaints).

Rules:
- Never invent courses, dates, prices, discounts or certificates.
- Only offer groups with seats_left above 0. If a group is full, offer the next one.
- If they're unsure of their level, ask 2–3 short questions about what they already know, then suggest a level.
- After registering, share the payment instructions and say the team will confirm their seat once payment arrives.

Safety rules

Built into the prompt and the tools:

  • Never invents courses, dates, prices or discounts
  • Never promises certificates or results you don't offer
  • Hands parents' and payment questions it can't answer to the team

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

WIncoming messageWhatsApp Trigger{ }Get questionCodeEnrollment agentAI AgentClaude modelAnthropic Chat Mo…◷MemorySimple MemoryGCoursesGoogle Sheets ToolGRegister stude…Google Sheets ToolTNotify teamTelegram ToolWReply on WhatsAppWhatsApp Business Cloud
Trigger App Code AI Agent tool

Code

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

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

return [{ json: { from: msg.from, question: msg.text.body } }];

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 (297 lines)
{
  "name": "Course enrollment AI agent on WhatsApp (Flowngn)",
  "nodes": [
    {
      "parameters": {
        "content": "## Course enrollment AI agent on WhatsApp\nAnswers questions about your courses, schedules and prices on WhatsApp, and registers students for the next group.\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": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Setup notes",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -420,
        -60
      ]
    },
    {
      "parameters": {
        "updates": [
          "messages"
        ]
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Incoming message",
      "type": "n8n-nodes-base.whatsAppTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "webhookId": "2c527986-f663-44a2-ab4f-9b3f13e4bf18"
    },
    {
      "parameters": {
        "jsCode": "// Keeps only text messages and pulls out who sent it and what they asked.\nconst msg = $input.first().json.messages?.[0];\nif (!msg || msg.type !== \"text\") return [];\n\nreturn [{ json: { from: msg.from, question: msg.text.body } }];"
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Get question",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        0
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.question }}",
        "options": {
          "systemMessage": "=You are the WhatsApp enrollment assistant for YOUR_ACADEMY. Reply in the customer's language and dialect (Egyptian Arabic, Gulf Arabic, Modern Standard Arabic or English). Be warm and brief.\n\nToday is {{ $now.toFormat('cccc d LLLL yyyy') }}. Payment instructions: YOUR_PAYMENT_INSTRUCTIONS.\n\nTools:\n- \"Courses\": our course list (course, level, group, days, time, start date, price, seats_left, online or in person). Always check it before answering about dates, prices or seats.\n- \"Register student\": saves a registration. Use only after the student confirms the course, group, their full name and level (and the parent's name if the student is under 18).\n- \"Notify team\": alerts our team about every registration, and any question you can't answer (refunds, certificates, special prices, complaints).\n\nRules:\n- Never invent courses, dates, prices, discounts or certificates.\n- Only offer groups with seats_left above 0. If a group is full, offer the next one.\n- If they're unsure of their level, ask 2–3 short questions about what they already know, then suggest a level.\n- After registering, share the payment instructions and say the team will confirm their seat once payment arrives."
        }
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Enrollment agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        600,
        0
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "claude-sonnet-5",
          "mode": "list"
        },
        "options": {}
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Claude model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        260,
        220
      ]
    },
    {
      "parameters": {
        "sessionIdType": "customKey",
        "sessionKey": "={{ $('Get question').item.json.from }}",
        "contextWindowLength": 10
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        430,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Returns our courses: course, level, group, days, time, start date, price, seats_left, format.",
        "operation": "read",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Courses",
          "mode": "name"
        },
        "options": {}
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Courses",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        600,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Saves a confirmed registration.",
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "YOUR_SPREADSHEET_ID",
          "mode": "id"
        },
        "sheetName": {
          "__rl": true,
          "value": "Registrations",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "date": "={{ $now.toISO() }}",
            "phone": "={{ $('Get question').item.json.from }}",
            "student": "={{ $fromAI('student', \"Student's full name\", 'string') }}",
            "parent": "={{ $fromAI('parent', \"Parent's name if the student is under 18, otherwise empty\", 'string') }}",
            "course": "={{ $fromAI('course', \"Course name\", 'string') }}",
            "group": "={{ $fromAI('group', \"Group or start date\", 'string') }}",
            "level": "={{ $fromAI('level', \"Student's level\", 'string') }}",
            "status": "awaiting payment"
          }
        },
        "options": {}
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Register student",
      "type": "n8n-nodes-base.googleSheetsTool",
      "typeVersion": 4.5,
      "position": [
        770,
        220
      ]
    },
    {
      "parameters": {
        "descriptionType": "manual",
        "toolDescription": "Alerts our team about every registration, and questions you can't answer.",
        "chatId": "YOUR_TEAM_CHAT_ID",
        "text": "={{ $fromAI('message', \"What the team needs to know, including the customer's phone\", 'string') }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Notify team",
      "type": "n8n-nodes-base.telegramTool",
      "typeVersion": 1.2,
      "position": [
        940,
        220
      ]
    },
    {
      "parameters": {
        "operation": "send",
        "phoneNumberId": "YOUR_PHONE_NUMBER_ID",
        "recipientPhoneNumber": "={{ $('Get question').item.json.from }}",
        "textBody": "={{ $json.output }}"
      },
      "id": "2c527986-f663-44a2-ab4f-9b3f13e4bf18",
      "name": "Reply on WhatsApp",
      "type": "n8n-nodes-base.whatsApp",
      "typeVersion": 1,
      "position": [
        900,
        0
      ]
    }
  ],
  "connections": {
    "Incoming message": {
      "main": [
        [
          {
            "node": "Get question",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get question": {
      "main": [
        [
          {
            "node": "Enrollment agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enrollment agent": {
      "main": [
        [
          {
            "node": "Reply on WhatsApp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude model": {
      "ai_languageModel": [
        [
          {
            "node": "Enrollment agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Memory": {
      "ai_memory": [
        [
          {
            "node": "Enrollment agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Courses": {
      "ai_tool": [
        [
          {
            "node": "Enrollment agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Register student": {
      "ai_tool": [
        [
          {
            "node": "Enrollment agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Notify team": {
      "ai_tool": [
        [
          {
            "node": "Enrollment agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}

Open in the playground to edit →

Tips

  • Update the seats_left column after each payment so full groups are never offered.

Related flows