Skip to content
Skip to main content
Monday.comn8nAI Automation

Monday.com + AI: Automating Client Project Management with n8n

Carlos Aragón··~12 min read
Monday.com + AI Project Management Automation with n8n

The Problem with Manual Project Routing

If you run an agency or manage multiple clients in Monday.com, you know the drill. A new item drops into your board — a client request, a bug report, a strategy deliverable — and someone has to figure out: who handles this? How urgent is it? What type of work is it?

At VIXI, we were doing this manually. Every morning I'd scan 15–30 new items, mentally triage them, assign them to the right person or agent, and drop a note in Telegram. It took 35–45 minutes a day. For a solo operator running AI agents, that's a significant tax.

This post walks through the exact workflow I built to eliminate that. When a new item lands in Monday.com, n8n catches the webhook, Claude AI scores it on urgency and type, a Switch node routes it to the right agent, Monday auto-assigns the item, and a Telegram message fires — all in under 4 seconds.

What you'll build:

Monday.com webhook → n8n → Claude AI scoring → auto-assign → Telegram notification. Full JSON template at the end.

The Stack

You don't need much. Here's what this workflow uses:

  • Monday.comAny plan with API access — Pro or Enterprise for advanced column types
  • n8nSelf-hosted (Docker) or n8n Cloud. I use self-hosted on a $12/mo VPS
  • Claude API (Anthropic)claude-sonnet-4-6 for scoring — fast, cheap, reliable tool use
  • Telegram BotFree, takes 2 minutes to set up via BotFather

Set these environment variables in n8n before you start. You'll reference them in the credential nodes:

MONDAY_API_KEY=your_monday_api_token
ANTHROPIC_API_KEY=your_claude_api_key
TELEGRAM_BOT_TOKEN=your_bot_token
TELEGRAM_CHAT_ID=914916089

Workflow Architecture

Here's the full flow at a glance, before we dig into each step:

Monday.com Board
      │
      │  (new item created — webhook fires)
      ▼
n8n Webhook Node  ──────────────────────────────┐
      │                                          │
      │  item_name, board_id, column_values      │
      ▼                                          │
Claude AI HTTP Node                             │
  → Score: urgency (1-5)                        │
  → Score: complexity (1-5)                     │
  → Classify: type (dev|design|strategy|ops)    │
      │                                          │
      │  returns structured JSON                 │
      ▼                                          │
n8n Switch Node                                 │
  ├── dev       → Dev Agent Queue               │
  ├── design    → Design Agent Queue            │
  ├── strategy  → Carlos Review                 │
  └── ops       → Ops Agent Queue               │
      │                                          │
      ▼                                          │
Monday.com API Node                             │
  → change_column_values (assign person)        │
  → update status column                        │
      │                                          │
      ▼                                          │
Telegram sendMessage                            │
  "🆕 [item_name] → routed to [agent]           │
   Urgency: 4/5 | Type: dev"                   │
      │                                          │
      └──────────────────────────────────────────┘

End-to-end latency from item creation to Telegram message: typically 2.8–4.1 seconds. Claude's response time is the bottleneck (~1.8s), but that's well within acceptable range for async project routing.

Step 1 — Setting Up the Monday.com Webhook

In Monday.com, go to your board → Integrate → Webhooks. Create a new webhook for the create_item event. Paste your n8n Webhook URL as the endpoint.

Here's a sample payload Monday sends when a new item is created. This is what your n8n Webhook node will receive:

Monday.com Webhook Payload
{
  "event": {
    "type": "create_item",
    "boardId": 1234567890,
    "itemId": 9876543210,
    "itemName": "Build lead scoring dashboard for Client X",
    "createdAt": "2026-04-01T14:23:11Z",
    "userId": 55443322,
    "columnValues": {
      "status": { "label": "Not Started" },
      "priority": { "label": "High" },
      "text_notes": { "text": "Client wants this by EOW. Needs Supabase query + chart component." }
    }
  }
}

In your n8n Webhook node, set the HTTP Method to POST and copy the production URL into Monday. Use the Test URL during development — it captures a single request so you can build the rest of the workflow with real data.

Step 2 — The Claude AI Scoring Engine

This is the heart of the workflow. I use an n8n HTTP Request node to call the Claude API directly, passing the item name and notes from the Monday webhook payload. Claude returns a structured JSON object with scores and a routing type.

Here's the exact system prompt I use:

Claude System Prompt
You are a project routing AI for a digital agency.
Given a project task description, return ONLY valid JSON with:

{
  "urgency": <1-5>,         // 5 = client-blocking, 1 = low priority
  "complexity": <1-5>,      // 5 = multi-week, 1 = quick fix
  "type": "<dev|design|strategy|ops>",
  "summary": "<one sentence>",
  "reasoning": "<why this routing>"
}

Routing rules:
- dev: code, APIs, databases, integrations, bugs
- design: UI, UX, branding, Figma, graphics
- strategy: analysis, reports, planning, consulting
- ops: admin tasks, billing, contracts, scheduling

Return ONLY the JSON object. No markdown, no explanation.

And here's the HTTP Request node configuration in n8n (JSON body):

n8n HTTP Request Body — Claude API
{
  "model": "claude-sonnet-4-6",
  "max_tokens": 256,
  "system": "{{ $('System Prompt').item.json.prompt }}",
  "messages": [
    {
      "role": "user",
      "content": "Task: {{ $('Webhook').item.json.event.itemName }}\nNotes: {{ $('Webhook').item.json.event.columnValues.text_notes.text }}"
    }
  ]
}

Set the header x-api-key: {{ $env.ANTHROPIC_API_KEY }} and anthropic-version: 2023-06-01.

After the HTTP node, add a Code node to parse Claude's response:

// Parse Claude's response
const raw = $input.item.json.content[0].text;
const scored = JSON.parse(raw);
return { json: scored };

Typical Claude output for our example item:

{
  "urgency": 4,
  "complexity": 3,
  "type": "dev",
  "summary": "Lead scoring dashboard with Supabase backend and chart component",
  "reasoning": "Code-heavy task with database integration — routes to dev agent"
}

Step 3 — Routing with the Switch Node

Add an n8n Switch node after the Code parser. It reads the type field from Claude's JSON and routes to one of four output branches.

Switch Node Configuration
Switch on: {{ $json.type }}

Output 0 → "dev"      equals "dev"
Output 1 → "design"   equals "design"
Output 2 → "strategy" equals "strategy"
Output 3 → "ops"      equals "ops"
Output 4 → "fallback" (catch-all)

Each branch leads to a Set node that defines the assignee_monday_id for that agent type — the Monday.com user ID you want assigned for each category. These are just numbers you copy from your Monday board settings.

// Set node for "dev" branch
{
  "assignee_monday_id": "12345678",   // Dev agent user ID
  "agent_label": "Dev Agent",
  "status_label": "In Progress"
}

// Set node for "strategy" branch
{
  "assignee_monday_id": "87654321",   // Carlos review
  "agent_label": "Carlos — Review",
  "status_label": "Review Needed"
}

Step 4 — Auto-Assign in Monday.com

After the Switch routes to the right branch, each branch connects to an HTTP Request node that calls the Monday.com GraphQL API to assign the item and update its status.

Monday.com GraphQL Mutation
mutation {
  change_multiple_column_values(
    board_id: {{ $('Webhook').item.json.event.boardId }},
    item_id: {{ $('Webhook').item.json.event.itemId }},
    column_values: "{\"person\": {\"personsAndTeams\":[{\"id\":{{ $json.assignee_monday_id }},\"kind\":\"person\"}]}, \"status\": {\"label\":\"{{ $json.status_label }}\"}}"
  ) {
    id
  }
}

The HTTP Request node setup:

  • URL: https://api.monday.com/v2
  • Method: POST
  • Header: Authorization: {{ $env.MONDAY_API_KEY }}
  • Header: API-Version: 2024-04
  • Body: JSON with the query field containing the mutation above

This updates two columns simultaneously: the person (assignee) column and the status column. Monday reflects the change instantly — no polling needed.

Step 5 — Telegram Alert to Close the Loop

The last node in every branch fires a Telegram message. Set up your bot with BotFather (/newbot), grab your token, and find your chat ID by messaging your bot and calling getUpdates.

Telegram sendMessage — n8n HTTP Request Body
{
  "chat_id": "{{ $env.TELEGRAM_CHAT_ID }}",
  "parse_mode": "Markdown",
  "text": "*🆕 New Task Routed*\n\n*Task:* {{ $('Webhook').item.json.event.itemName }}\n*Routed to:* {{ $('Set Agent').item.json.agent_label }}\n*Urgency:* {{ $('Parse Claude').item.json.urgency }}/5\n*Complexity:* {{ $('Parse Claude').item.json.complexity }}/5\n*Type:* {{ $('Parse Claude').item.json.type }}\n\n_{{ $('Parse Claude').item.json.summary }}_\n\n[View in Monday](https://your-account.monday.com/boards/{{ $('Webhook').item.json.event.boardId }}/pulses/{{ $('Webhook').item.json.event.itemId }})"
}

The resulting Telegram message looks like this:

🆕 New Task Routed

Task: Build lead scoring dashboard for Client X

Routed to: Dev Agent

Urgency: 4/5

Complexity: 3/5

Type: dev

Lead scoring dashboard with Supabase backend and chart component

View in Monday →

Full n8n Workflow JSON Template

Copy the JSON below, go to your n8n instance → Workflows → Import → paste. You'll need to update your credential IDs and environment variable names, but the structure is production-ready.

n8n Workflow JSON — Monday AI Routing
{
  "name": "Monday.com AI Task Router",
  "nodes": [
    {
      "id": "webhook-trigger",
      "name": "Monday Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [240, 300],
      "parameters": {
        "httpMethod": "POST",
        "path": "monday-new-item",
        "responseMode": "onReceived"
      }
    },
    {
      "id": "claude-scorer",
      "name": "Claude AI Score",
      "type": "n8n-nodes-base.httpRequest",
      "position": [460, 300],
      "parameters": {
        "method": "POST",
        "url": "https://api.anthropic.com/v1/messages",
        "authentication": "predefinedCredentialType",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "x-api-key", "value": "={{ $env.ANTHROPIC_API_KEY }}" },
            { "name": "anthropic-version", "value": "2023-06-01" },
            { "name": "content-type", "value": "application/json" }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "body",
              "value": "={"model":"claude-sonnet-4-6","max_tokens":256,"system":"You are a project routing AI. Return ONLY valid JSON: {urgency:1-5, complexity:1-5, type:dev|design|strategy|ops, summary:string, reasoning:string}","messages":[{"role":"user","content":"Task: {{ $json.event.itemName }} Notes: {{ $json.event.columnValues.text_notes.text }}"}]}"
            }
          ]
        }
      }
    },
    {
      "id": "parse-claude",
      "name": "Parse Claude Response",
      "type": "n8n-nodes-base.code",
      "position": [680, 300],
      "parameters": {
        "jsCode": "const raw = $input.item.json.content[0].text;\nconst scored = JSON.parse(raw);\nreturn { json: { ...scored, itemId: $('Monday Webhook').item.json.event.itemId, boardId: $('Monday Webhook').item.json.event.boardId, itemName: $('Monday Webhook').item.json.event.itemName } };"
      }
    },
    {
      "id": "route-switch",
      "name": "Route by Type",
      "type": "n8n-nodes-base.switch",
      "position": [900, 300],
      "parameters": {
        "dataType": "string",
        "value1": "={{ $json.type }}",
        "rules": {
          "rules": [
            { "value2": "dev", "output": 0 },
            { "value2": "design", "output": 1 },
            { "value2": "strategy", "output": 2 },
            { "value2": "ops", "output": 3 }
          ]
        },
        "fallbackOutput": 4
      }
    },
    {
      "id": "monday-assign",
      "name": "Monday Assign & Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [1120, 300],
      "parameters": {
        "method": "POST",
        "url": "https://api.monday.com/v2",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "={{ $env.MONDAY_API_KEY }}" },
            { "name": "Content-Type", "value": "application/json" },
            { "name": "API-Version", "value": "2024-04" }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "=mutation { change_multiple_column_values(board_id: {{ $json.boardId }}, item_id: {{ $json.itemId }}, column_values: \"{\\\"person\\\":{\\\"personsAndTeams\\\":[{\\\"id\\\":{{ $json.assignee_monday_id }},\\\"kind\\\":\\\"person\\\"}]},\\\"status\\\":{\\\"label\\\":\\\"{{ $json.status_label }}\\\"}}\") { id } }"
            }
          ]
        }
      }
    },
    {
      "id": "telegram-alert",
      "name": "Telegram Notify",
      "type": "n8n-nodes-base.httpRequest",
      "position": [1340, 300],
      "parameters": {
        "method": "POST",
        "url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
        "sendBody": true,
        "bodyContentType": "json",
        "bodyParameters": {
          "parameters": [
            { "name": "chat_id", "value": "={{ $env.TELEGRAM_CHAT_ID }}" },
            { "name": "parse_mode", "value": "Markdown" },
            { "name": "text", "value": "=*🆕 Task Routed*\n\n*Task:* {{ $json.itemName }}\n*To:* {{ $json.agent_label }}\n*Urgency:* {{ $json.urgency }}/5 | *Complexity:* {{ $json.complexity }}/5\n\n_{{ $json.summary }}_" }
          ]
        }
      }
    }
  ],
  "connections": {
    "Monday Webhook": { "main": [[{ "node": "Claude AI Score", "type": "main", "index": 0 }]] },
    "Claude AI Score": { "main": [[{ "node": "Parse Claude Response", "type": "main", "index": 0 }]] },
    "Parse Claude Response": { "main": [[{ "node": "Route by Type", "type": "main", "index": 0 }]] },
    "Route by Type": {
      "main": [
        [{ "node": "Set Dev Agent", "type": "main", "index": 0 }],
        [{ "node": "Set Design Agent", "type": "main", "index": 0 }],
        [{ "node": "Set Strategy Review", "type": "main", "index": 0 }],
        [{ "node": "Set Ops Agent", "type": "main", "index": 0 }],
        [{ "node": "Fallback Alert", "type": "main", "index": 0 }]
      ]
    }
  }
}

Note: After importing, update the Set nodes for each branch with your actual Monday.com user IDs. Find them in Monday: Admin → Users → click a user → the ID is in the URL.

Results After 3 Weeks in Production

I've been running this workflow since mid-March. Here's what the actual numbers look like:

~42 min/day

Manual triage eliminated

94.2%

Correct routing accuracy

3.1s avg

End-to-end latency

$0.0008

Claude cost per item scored

The 5.8% misrouting rate is almost entirely edge cases — items with vague names like "Review X" or "Update Y" where the notes field is empty. Adding a validation step that requires a description before the item is created in Monday has cut that in half.

What I'm building next:

  • Supabase logging — every routing decision stored with timestamp, scores, and item ID for analytics
  • Weekly digest: n8n scheduled workflow that queries Supabase and fires a Sunday summary to Telegram
  • Complexity escalation: items scoring complexity 5 auto-create a Monday subitem for scoping before routing
  • Multi-board support: a single webhook URL that reads board_id and applies board-specific routing rules

Ship It

This workflow is one of the highest-ROI automations I've built. The Monday.com API is underrated — most people use the GUI and never touch the webhook or GraphQL layer. Once you do, the board becomes a programmable task queue rather than a place humans click.

Claude's consistent JSON output is what makes this reliable. I tested GPT-4o-mini on the same scoring prompt and got malformed JSON about 12% of the time. With claude-sonnet-4-6, I've had zero parse failures across 600+ items.

If you want help wiring this up for your agency or have a variation in mind — AI-scored priority queues, client-specific routing rules, multi-language support — I build these at VIXI or you can reach me directly at carlosaragon.online.

#Monday.com#n8n#project management#automation#Claude AI#Telegram