{
  "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
          }
        ]
      ]
    }
  }
}