AutomationFlowsWeb Scraping › Automatically Classify Zoho Desk Support Tickets Using Gemini AI

Automatically Classify Zoho Desk Support Tickets Using Gemini AI

ByJulian Kaiser @jksr on n8n.io

Transform your customer support workflow with intelligent ticket classification. This automation leverages AI to automatically categorize incoming support tickets in Zoho Desk, reducing manual work and ensuring faster ticket routing to the right teams. Fetches all tickets from…

Event trigger★★★★☆ complexityAI-powered14 nodesOpenRouter ChatHTTP RequestChain Llm
Web Scraping Trigger: Event Nodes: 14 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #9307 — we link there as the canonical source.

This workflow follows the Chainllm → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "f34db366-b13a-43ac-8d4e-a52e3a7243dd",
      "name": "When clicking \u2018Execute workflow\u2019",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -432,
        -256
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "e2386bfd-2803-4f40-8744-0c86aecfb167",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        1200,
        -96
      ],
      "parameters": {
        "model": "google/gemini-2.5-flash-lite-preview-09-2025",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fe6a1452-471c-4e2b-8c64-7d32e35bb33b",
      "name": "Filter classification = null",
      "type": "n8n-nodes-base.code",
      "position": [
        496,
        -256
      ],
      "parameters": {
        "jsCode": "// Filter items where classification is null\nconst filteredItems = $input.all().filter(item => item.json.classification === null);\n\nreturn filteredItems;\n"
      },
      "typeVersion": 2
    },
    {
      "id": "4153b802-af64-4ec1-b55e-2dcd41a8f038",
      "name": "Get threads",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        720,
        -256
      ],
      "parameters": {
        "url": "=https://desk.zoho.eu/api/v1/tickets/{{ $json.id }}/threads",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "queryParameters": {
          "parameters": [
            {
              "name": "sortBy",
              "value": "sendDateTime"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {}
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "f41d94a5-3070-4874-a72d-2ff28af6e4ca",
      "name": "Get first thread",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        944,
        -256
      ],
      "parameters": {
        "url": "=https://desk.zoho.eu/api/v1/tickets/{{ $('Filter classification = null').item.json.id }}/threads/{{ $json.data[0].id }}",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "queryParameters": {
          "parameters": [
            {
              "name": "include",
              "value": "plainText"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "dba88e6c-e555-42d6-b0b6-b02c2f5ef977",
      "name": "Classify",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        1168,
        -256
      ],
      "parameters": {
        "text": "=**Role:** You are an expert support ticket classification system.\n\n**Task:** Read the provided ticket title and request body. Based on the content, classify the ticket into one of the following categories. Respond with only the single, most appropriate category name.\n\n**Categories:**\n\u2022 Content\n\u2022 Contract\n\u2022 Invoice\n\u2022 Featured Products\n\u2022 Affiliate-Partner\n\u2022 Bug\n\u2022 Feature\n\u2022 Other\n\n---\n\n**Ticket Title:**\n{{ $('Filter classification = null').item.json.subject }}\n\n**Ticket Request:**\n{{ $json.plainText }}\n\n**Category:**",
        "batching": {},
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "b14e73ba-0046-4395-9e26-f80014a3332a",
      "name": "Update Ticket",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        1600,
        -256
      ],
      "parameters": {
        "url": "=https://desk.zoho.eu/api/v1/tickets/{{ $('Filter classification = null').item.json.id }}",
        "method": "PUT",
        "options": {},
        "sendBody": true,
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "classification",
              "value": "={{ $json.text }}"
            }
          ]
        },
        "genericAuthType": "oAuth2Api"
      },
      "typeVersion": 4.2
    },
    {
      "id": "62d15c70-77fb-4947-a808-29e0c366e957",
      "name": "Fetch All Tickets",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        48,
        -256
      ],
      "parameters": {
        "url": "https://desk.zoho.eu/api/v1/tickets/search",
        "options": {
          "pagination": {
            "pagination": {
              "parameters": {
                "parameters": [
                  {
                    "name": "from",
                    "value": "={{ $pageCount * 100 }}"
                  }
                ]
              },
              "completeExpression": "={{ $response.body.data.length === 0 || $response.body.data.length < 100 }}",
              "paginationCompleteWhen": "other"
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2Api",
        "queryParameters": {
          "parameters": [
            {
              "name": "limit",
              "value": "100"
            },
            {
              "name": "sortBy",
              "value": "createdTime"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "4e551054-ffb2-4d4b-ba37-3b24045c9971",
      "name": "Split Tickets",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        272,
        -256
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "8e29f267-2cae-4429-8914-a58487d45840",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -576,
        -784
      ],
      "parameters": {
        "width": 368,
        "height": 480,
        "content": "## \ud83c\udfaf WORKFLOW PURPOSE\n\nAutomatically classifies Zoho Desk tickets using AI based on their title and content.\nProcesses all unclassified tickets in batches.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4b6d79df-3535-4d37-b959-64f5642817eb",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -80,
        -784
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 480,
        "content": "## \ud83d\udce5 FETCH TICKETS WITH PAGINATION\n- Retrieves 100 tickets per page\n- Automatically paginates through ALL results\n- Sorted by creation time\n\n## \ud83d\udd10 OAUTH2 SETUP\nSetting up OAuth2 with Zoho can be tricky! \nFollow my complete guide: https://gist.github.com/Julian194/7c0ef5abaa5e3850f2bcc0a51bcd4633\n\n## \u2699\ufe0f PAGINATION EXPLAINED\nThis demonstrates proper Zoho API pagination:\n- Uses 'from' parameter: {{ $pageCount * 100 }}\n- Stops when: data.length === 0 or < 100\n- This pattern works for all Zoho Desk paginated endpoints\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a019181e-7023-4002-b106-2635cf4ccf3d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        -784
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 480,
        "content": "## \ud83d\udd0d FILTER LOGIC\nOnly processes tickets where 'classification' is empty/null.\nPrevents re-processing already classified tickets.\n\n## \ud83d\udca1 ALTERNATIVE APPROACH\nYou can filter directly in the API using query parameters instead!\nCheck the Zoho API docs for available filters.\nThis example shows client-side filtering for simplicity.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "33dbe4e2-6f94-41f9-bc39-2b57c3df728e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1104,
        -784
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 480,
        "content": "## \ud83e\udd16 AI CLASSIFICATION CATEGORIES\n\u2022 Content\n\u2022 Contract\n\u2022 Invoice\n\u2022 Featured Products\n\u2022 Affiliate-Partner\n\u2022 Bug\n\u2022 Feature\n\u2022 Other\n\n## \u270f\ufe0f CUSTOMIZE FOR YOUR USE CASE\nChange these categories to match your business needs!\nYou can also modify the prompt to classify different aspects \n(urgency, department, product type, etc.)\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "57d25075-78d6-42cc-8415-9a51c8c7883e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        -512
      ],
      "parameters": {
        "color": 7,
        "width": 272,
        "height": 208,
        "content": "## \ud83d\udcbe SAVE CLASSIFICATION\nUpdates the Zoho Desk ticket with the AI-generated classification.\nError handling enabled to continue processing other tickets if one fails.\n"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Classify": {
      "main": [
        [
          {
            "node": "Update Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get threads": {
      "main": [
        [
          {
            "node": "Get first thread",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Tickets": {
      "main": [
        [
          {
            "node": "Filter classification = null",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get first thread": {
      "main": [
        [
          {
            "node": "Classify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch All Tickets": {
      "main": [
        [
          {
            "node": "Split Tickets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Classify",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Filter classification = null": {
      "main": [
        [
          {
            "node": "Get threads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking \u2018Execute workflow\u2019": {
      "main": [
        [
          {
            "node": "Fetch All Tickets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Transform your customer support workflow with intelligent ticket classification. This automation leverages AI to automatically categorize incoming support tickets in Zoho Desk, reducing manual work and ensuring faster ticket routing to the right teams. Fetches all tickets from…

Source: https://n8n.io/workflows/9307/ — original creator credit. Request a take-down →

More Web Scraping workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Web Scraping

Spot Workplace Discrimination Patterns with AI. Uses manualTrigger, lmChatOpenAi, httpRequest, html. Event-driven trigger; 38 nodes.

OpenAI Chat, HTTP Request, Information Extractor +2
Web Scraping

Spot Workplace Discrimination Patterns with AI. Uses manualTrigger, lmChatOpenAi, httpRequest, html. Event-driven trigger; 38 nodes.

OpenAI Chat, HTTP Request, Information Extractor +2
Web Scraping

Accounting teams spend hours manually entering purchase bills into accounting systems—copying vendor details, creating items, checking duplicates, and reconciling totals. This workflow removes that ma

HTTP Request, QuickBooks, Information Extractor +2
Web Scraping

Animal advocates & campaigners who want a weekly briefing on animal-related bills with clear, actionable steps—no manual research needed.

OpenRouter Chat, HTTP Request, Information Extractor +3
Web Scraping

This workflow is built for one core purpose: to maximize the return on your reading time. It turns your passive consumption of articles and highlights into an active system for generating original con

HTTP Request, Chain Llm, OpenRouter Chat