Hello, I am creating one workflow where m getting tickets of last 24 hours, and thn again filtering which are in new state older thn 30mnts, and thn it will send an email to the person to notify, so i am stuck at next trigger where its sending duplicate mails for those tickets which was sent earlier. can you please help me here. i am attaching my workflow
<{
“nodes”: [
{
“parameters”: {
“requestMethod”: “POST”,
“url”: “={{ $node["Radium Authentication"].json.url }}/itsm/get_all_tickets”,
“allowUnauthorizedCerts”: true,
“options”: {},
“bodyParametersUi”: {
“parameter”: [
{}
]
},
“headerParametersUi”: {
“parameter”: [
{
“name”: “Authorization”,
“value”: “={{ $node["Radium Authentication"].json.token }}”
}
]
},
“queryParametersUi”: {
“parameter”: [
{
“name”: “page”,
“value”: “1”
},
{
“name”: “offset”,
“value”: “100”
}
]
}
},
“id”: “662d916b-7edd-4a5f-9337-83b4c81b650b”,
“name”: “Get Credential list Request”,
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 2,
“position”: [
-1960,
280
]
},
{
“parameters”: {},
“id”: “bc263f6e-4b85-4544-9372-e9070205ee7f”,
“name”: “Radium Authentication”,
“type”: “n8n-nodes-base.RadiumDetails”,
“typeVersion”: 1,
“position”: [
-2180,
280
]
},
{
“parameters”: {
“jsCode”: “\n/**\n * Filters tickets that are:\n * - status NEW (case-insensitive),\n * - created within the last 24 hours,\n * - at least 30 minutes old.\n *\n * It parses created_on1 robustly and builds an ISO string with +05:30 (IST),\n * so comparisons are done on UTC epoch milliseconds reliably.\n /\n\nconst IST_TZ = ‘+05:30’;\nconst NOW_MS = Date.now();\nconst TWENTY_FOUR_HOURS_MS = 24 * 60 * 60 * 1000;\nconst THIRTY_MINUTES_MS = 30 * 60 * 1000;\nconst WINDOW_START_MS = NOW_MS - TWENTY_FOUR_HOURS_MS;\n\n// ---- Collect tickets from typical shapes across all incoming items ----\nfunction collectTickets(items) {\n const all = [];\n for (const it of items) {\n const root = it.json;\n\n if (Array.isArray(root)) {\n all.push(…root);\n continue;\n }\n if (Array.isArray(root?.response)) {\n all.push(…root.response);\n continue;\n }\n if (Array.isArray(root?.response?.response)) {\n all.push(…root.response.response);\n continue;\n }\n\n // Fallback: single ticket per item\n if (root && typeof root === ‘object’) {\n all.push(root);\n }\n }\n return all;\n}\n\n// ---- Parse "created_on1" to UTC epoch ms by building an ISO with IST offset ----\n// Supports: "MM/DD/YYYY, HH:MM:SS" or "DD/MM/YYYY, HH:MM:SS", optional "AM/PM"\n// Also supports "YYYY-MM-DD HH:MM:SS" and ISO-like strings.\nfunction parseIstToEpochMs(str) {\n if (typeof str !== ‘string’) return null;\n let s = str.trim();\n\n // If it’s already an ISO string, let Date.parse handle it.\n // e.g., "2025-12-24T10:30:00+05:30" or "2025-12-24 10:30:00"\n if (/^\d{4}-\d{2}-\d{2}/.test(s)) {\n // If no timezone is present, assume IST\n if (!/[zZ]|[+\-]\d{2}:\d{2}$/.test(s)) s = s.replace(’ ‘, ‘T’) + IST_TZ;\n const ms = Date.parse(s);\n return Number.isNaN(ms) ? null : ms;\n }\n\n // Split "date, time" OR "date time"\n let datePart, timePart;\n const byComma = s.split(’, ‘);\n if (byComma.length >= 2) {\n datePart = byComma[0];\n timePart = byComma.slice(1).join(’ ').trim();\n } else {\n // Try space split between date and time\n const m = s.match(/^(.+?)\s+(\d{1,2}:\d{2}:\d{2}(?:\s[AP]M)?)$/i);\n if (!m) return null;\n datePart = m[1];\n timePart = m[2];\n }\n\n // Determine separator and split date\n const sep = datePart.includes(‘/’) ? ‘/’ :\n datePart.includes(‘-’) ? ‘-’ :\n datePart.includes(‘.’) ? ‘.’ : ‘/’;\n const parts = datePart.split(sep).map(x => x.trim());\n\n let year, month, day;\n if (parts[0].length === 4) {\n // YYYY-MM-DD\n year = Number(parts[0]);\n month = Number(parts[1]);\n day = Number(parts[2]);\n } else {\n // Decide MM/DD/YYYY vs DD/MM/YYYY by first part value\n const a = parts.map(Number);\n if (a[0] > 12) { // DD/MM/YYYY\n day = a[0]; month = a[1]; year = a[2];\n } else { // MM/DD/YYYY\n month = a[0]; day = a[1]; year = a[2];\n }\n }\n\n // Parse time with optional AM/PM\n let tp = timePart.trim();\n let ampm = null;\n if (/AM$/i.test(tp)) { ampm = ‘AM’; tp = tp.replace(/AM$/i, ‘’).trim(); }\n else if (/PM$/i.test(tp)) { ampm = ‘PM’; tp = tp.replace(/PM$/i, ‘’).trim(); }\n\n const [hStr, mStr, sStr] = tp.split(‘:’);\n let hour = Number(hStr);\n const minute = Number(mStr);\n const second = Number(sStr);\n\n if ([year, month, day, hour, minute, second].some(n => Number.isNaN(n))) return null;\n\n // 12h → 24h\n if (ampm === ‘AM’ && hour === 12) hour = 0;\n if (ampm === ‘PM’ && hour !== 12) hour += 12;\n\n // Build ISO string with IST timezone\n const iso =\n ${String(year).padStart(4, '0')}- +\n ${String(month).padStart(2, '0')}- +\n ${String(day).padStart(2, '0')}T +\n ${String(hour).padStart(2, '0')}: +\n ${String(minute).padStart(2, '0')}: +\n ${String(second).padStart(2, '0')} +\n ${IST_TZ};\n\n const ms = Date.parse(iso);\n return Number.isNaN(ms) ? null : ms;\n}\n\n// ---- Main filter ----\nconst tickets = collectTickets(items);\nconst result = ;\n\nfor (const t of tickets) {\n const created =\n t?.created_on1 ?? t?.created_on ?? t?.CreatedOn ?? t?.createdAt;\n const statusRaw =\n t?.radium_incident_status1 ?? t?.radium_incident_status ??\n t?.status ?? t?.incident_status;\n\n if (!created || !statusRaw) continue;\n\n const status = String(statusRaw).trim().toLowerCase();\n if (status !== ‘new’) continue;\n\n const createdMs = parseIstToEpochMs(String(created));\n if (createdMs == null) continue;\n\n // Only last 24h (inclusive) and not future\n if (createdMs < WINDOW_START_MS || createdMs > NOW_MS) continue;\n\n const ageMs = NOW_MS - createdMs;\n if (ageMs < THIRTY_MINUTES_MS) continue;\n\n result.push({\n json: {\n radium_incident_id1: t.radium_incident_id1 ?? t.id ?? t.ticket_id,\n age_minutes: Math.floor(ageMs / 60000),\n status: statusRaw,\n created_on: created,\n },\n });\n}\n\nreturn result;\n”
},
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
-1760,
280
],
“id”: “47b47c70-1912-4756-bf4c-d81eb6fd545d”,
“name”: “Code”,
“alwaysOutputData”: false
},
{
“parameters”: {
“conditions”: {
“options”: {
“caseSensitive”: true,
“leftValue”: “”,
“typeValidation”: “strict”,
“version”: 2
},
“conditions”: [
{
“id”: “69f637ba-02e3-4d92-a306-e67059a183f5”,
“leftValue”: “={{ $json.status }}”,
“rightValue”: “new”,
“operator”: {
“type”: “string”,
“operation”: “equals”,
“name”: “filter.operator.equals”
}
},
{
“id”: “931bb843-f4fb-4a6e-94d0-ab52e3ff271d”,
“leftValue”: “={{ $json.age_minutes }}”,
“rightValue”: 30,
“operator”: {
“type”: “number”,
“operation”: “gte”
}
}
],
“combinator”: “and”
},
“options”: {}
},
“type”: “n8n-nodes-base.if”,
“typeVersion”: 2.2,
“position”: [
-1560,
280
],
“id”: “ab567324-a52c-46b7-8f93-e59d4bea5ac7”,
“name”: “If”
},
{
“parameters”: {
“jsCode”: “return items.map(item => {\n const id = String(\n item.json.radium_incident_id1 ??\n item.json.Radium_ticket_id ??\n item.json.ticket_id ??\n item.json.id\n ).trim();\n\n return {\n json: {\n Radium_Ticket: ‘ITSM’,\n Radium_ticket_id: id,\n email_type: ‘ITSM_NEW_TICKET_ALERT’,\n ticket_id: item.json.ticket_id ?? id,\n created_on: item.json.created_on,\n age_minutes: item.json.age_minutes,\n dedup_id: id\n }\n };\n});\n”
},
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
-1300,
260
],
“id”: “143f536b-f443-4a0a-acc6-7f246e15bc7d”,
“name”: “Code1”
},
{
“parameters”: {
“options”: {
“reset”: false
}
},
“type”: “n8n-nodes-base.splitInBatches”,
“typeVersion”: 3,
“position”: [
-660,
100
],
“id”: “0685fbd5-9a33-49fa-aaf4-6494feee0a3b”,
“name”: “Loop Over Items”
},
{
“parameters”: {
“requestMethod”: “POST”,
“url”: “={{$node["Radium Authentication"].json["url"]}}/send_mail”,
“allowUnauthorizedCerts”: true,
“options”: {},
“bodyParametersUi”: {
“parameter”: [
{
“name”: “toList”,
“value”: “={{ $json.to }}”
},
{
“name”: “subject”,
“value”: “={{ $json.subject }}”
},
{
“name”: “email_type”,
“value”: “={{ $json["emailType"] }}”
},
{
“name”: “message”,
“value”: “={{ $json.body }}”
},
{
“name”: “email_server_id”,
“value”: “1”
}
]
},
“headerParametersUi”: {
“parameter”: [
{
“name”: “Authorization”,
“value”: “={{$node["Radium Authentication"].json["token"]}}”
}
]
}
},
“id”: “edd21cbb-99b7-414b-930f-cbae8794acc4”,
“name”: “Sending Email2”,
“type”: “n8n-nodes-base.httpRequest”,
“typeVersion”: 2,
“position”: [
-420,
100
],
“alwaysOutputData”: true,
“continueOnFail”: true
},
{
“parameters”: {
“values”: {
“string”: [
{
“name”: “subject”,
“value”: “ITSM Ticket Alert”
},
{
“name”: “emailType”,
“value”: “={{ $json.email_type }}”
},
{
“name”: “to”,
“value”: “[email protected]”
},
{
“name”: “=body”,
“value”: “=\nHello Team,
\nThis is an automated notification to inform you that a support ticket has been open for more than 30 minutes.
\n\nTicket Details:
\n• Ticket ID: {{$json["Radium_ticket_id"]}}
\n• Opened On: {{$json["created_on"]}}
\n• Open Duration: {{$json["age_minutes"]}} minutes
\n\nKindly review the ticket at the earliest and take necessary action.
\n\nRegards,
\nITSM Automation System
\nNote: This is a system-generated email. Please do not reply.\n”
},
{
“name”: “dedup_id”,
“value”: “=\n={{ \n String(\n $json.radium_incident_id1 ??\n $json.Radium_ticket_id ??\n $json.id ??\n $json.ticket_id\n ).trim()\n}}\n”
}
]
},
“options”: {}
},
“id”: “7cfc4886-0346-47a3-aed2-22558d942255”,
“name”: “Set prams email2”,
“type”: “n8n-nodes-base.set”,
“typeVersion”: 1,
“position”: [
-820,
260
]
},
{
“parameters”: {
“functionCode”: “const staticData = this.getWorkflowStaticData(‘global’);\nif (!staticData.sentTickets) {\n staticData.sentTickets = {};\n}\n\n// Optional: purge entries older than 7 days\nconst now = Date.now();\nconst TTL = 7 * 24 * 60 * 60 * 1000;\nfor (const [k, ts] of Object.entries(staticData.sentTickets)) {\n if (typeof ts === ‘number’ && (now - ts > TTL)) delete staticData.sentTickets[k];\n}\n\nreturn items.filter(item => {\n const id = String(item.json.dedup_id || ‘’).trim();\n return id && !staticData.sentTickets[id];\n});\n”
},
“id”: “7622f2fc-0efe-43aa-a4a4-798dcd4a945e”,
“name”: “Function2”,
“type”: “n8n-nodes-base.function”,
“typeVersion”: 1,
“position”: [
40,
240
]
},
{
“parameters”: {
“functionCode”: “const staticData = this.getWorkflowStaticData(‘global’);\n\nif (!staticData.sentTickets) {\n staticData.sentTickets = {};\n}\n\nreturn items.filter(item => {\n const dedupId = String(item.json.dedup_id).trim();\n return !staticData.sentTickets[dedupId];\n});”
},
“id”: “677f505e-a7b5-4d5b-9bbe-21e54e08bc68”,
“name”: “Function1”,
“type”: “n8n-nodes-base.function”,
“typeVersion”: 1,
“position”: [
-1040,
260
]
},
{
“parameters”: {
“conditions”: {
“options”: {
“caseSensitive”: true,
“leftValue”: “”,
“typeValidation”: “strict”,
“version”: 2
},
“conditions”: [
{
“id”: “20898851-bc34-40b7-abb0-913c82e34138”,
“leftValue”: “={{ $json.status }}”,
“rightValue”: “success”,
“operator”: {
“type”: “string”,
“operation”: “equals”
}
}
],
“combinator”: “and”
},
“options”: {}
},
“type”: “n8n-nodes-base.if”,
“typeVersion”: 2.2,
“position”: [
0,
0
],
“id”: “7a7e80f6-e884-4c02-8fd5-c83f6b246dbb”,
“name”: “If1”
},
{
“parameters”: {
“rule”: {
“interval”: [
{
“field”: “minutes”
}
]
}
},
“type”: “n8n-nodes-base.scheduleTrigger”,
“typeVersion”: 1.2,
“position”: [
-2440,
280
],
“id”: “99fcb4ab-0d7e-4e75-bda5-d34bbca51e39”,
“name”: “Schedule Trigger”
}
],
“connections”: {
“Get Credential list Request”: {
“main”: [
[
{
“node”: “Code”,
“type”: “main”,
“index”: 0
}
]
]
},
“Radium Authentication”: {
“main”: [
[
{
“node”: “Get Credential list Request”,
“type”: “main”,
“index”: 0
}
]
]
},
“Code”: {
“main”: [
[
{
“node”: “If”,
“type”: “main”,
“index”: 0
}
]
]
},
“If”: {
“main”: [
[
{
“node”: “Code1”,
“type”: “main”,
“index”: 0
}
]
]
},
“Code1”: {
“main”: [
[
{
“node”: “Function1”,
“type”: “main”,
“index”: 0
}
]
]
},
“Loop Over Items”: {
“main”: [
,
[
{
“node”: “Sending Email2”,
“type”: “main”,
“index”: 0
}
]
]
},
“Sending Email2”: {
“main”: [
[
{
“node”: “If1”,
“type”: “main”,
“index”: 0
},
{
“node”: “Loop Over Items”,
“type”: “main”,
“index”: 0
}
]
]
},
“Set prams email2”: {
“main”: [
[
{
“node”: “Loop Over Items”,
“type”: “main”,
“index”: 0
}
]
]
},
“Function1”: {
“main”: [
[
{
“node”: “Set prams email2”,
“type”: “main”,
“index”: 0
}
]
]
},
“If1”: {
“main”: [
[
{
“node”: “Function2”,
“type”: “main”,
“index”: 0
}
]
]
},
“Schedule Trigger”: {
“main”: [
[
{
“node”: “Radium Authentication”,
“type”: “main”,
“index”: 0
}
]
]
}
},
“pinData”: {},
“meta”: {
“instanceId”: “56618ac74fc1653fa13a004decd583a5fc421e12ac60e59c391259dc6bd565ce”
}
}>
Describe the problem/error/question
What is the error message (if any)?
Please share your workflow
(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
Share the output returned by the last node
Information on your n8n setup
- n8n version:
- Database (default: SQLite):
- n8n EXECUTIONS_PROCESS setting (default: own, main):
- Running n8n via (Docker, npm, n8n cloud, desktop app):
- Operating system:

