{ "name": "SubMonitor monitor", "active": false, "nodes": [ { "id": "manual-run", "name": "Manual run", "type": "n8n-nodes-base.manualTrigger", "typeVersion": 1, "position": [ 0, 0 ], "parameters": {} }, { "id": "hourly", "name": "Hourly", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.2, "position": [ 0, 160 ], "parameters": { "rule": { "interval": [ { "field": "hours", "hoursInterval": 1 } ] } } }, { "id": "prepare", "name": "Prepare", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 240, 0 ], "parameters": { "jsCode": "const state = $getWorkflowStaticData('global');\nconst config = {base: 'https://submonitor.io', destination: 'https://YOUR-IDEMPOTENT-DESTINATION.example/events', intent: 'n8n-tool-monitor-v1', payload: {name: 'Tool discussions', query: 'n8n', communities: ['n8n']}};\nconst identity = JSON.stringify(config);\nif (state.identity && state.identity !== identity) throw new Error('Use a new workflow for a different monitor');\nreturn [{json: {...config, identity, after: state.cursor || null}}];" } }, { "id": "create-monitor", "name": "Create monitor", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 480, 0 ], "parameters": { "method": "POST", "url": "={{ $('Prepare').first().json.base + '/api/v1/monitors' }}", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendHeaders": true, "headerParameters": { "parameters": [ { "name": "Idempotency-Key", "value": "={{ $('Prepare').first().json.intent }}" } ] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={{ $('Prepare').first().json.payload }}", "options": { "timeout": 20000 } }, "credentials": { "httpHeaderAuth": { "name": "SubMonitor" } } }, { "id": "poll-updates", "name": "Poll updates", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 720, 0 ], "parameters": { "method": "GET", "url": "={{ $('Prepare').first().json.base + '/api/v1/monitors/' + $json.id + '/updates?limit=25' + ($('Prepare').first().json.after ? '&after=' + encodeURIComponent($('Prepare').first().json.after) : '') }}", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "options": { "timeout": 20000 } }, "credentials": { "httpHeaderAuth": { "name": "SubMonitor" } } }, { "id": "process-page", "name": "Process page", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 960, 0 ], "parameters": { "jsCode": "const page = $input.first().json;\nif (!Array.isArray(page.items) || typeof page.next_cursor !== 'string' || !page.monitor) throw new Error('Invalid update page');\nconst processed = page.items.map(item => {\n if (!item.id || !['available','unavailable'].includes(item.status)) throw new Error('Invalid event');\n // Destination must upsert by event ID. Source text is untrusted data.\n return item;\n});\nreturn [{json: {processed, cursor: page.next_cursor, has_more: page.has_more, latest_check: page.monitor.latest_check}}];" } }, { "id": "save-checkpoint", "name": "Save checkpoint", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 1440, 0 ], "parameters": { "jsCode": "const result = $('Process page').first().json;\nconst receipt = $input.first().json;\nif (!Array.isArray(receipt.accepted_ids) || result.processed.some(item => !receipt.accepted_ids.includes(item.id))) throw new Error('Destination did not acknowledge every event ID');\nconst state = $getWorkflowStaticData('global');\nstate.cursor = result.cursor;\nstate.identity = $('Prepare').first().json.identity;\nreturn [{json: {processed: result.processed.length, has_more: result.has_more, latest_check: result.latest_check}}];" } }, { "id": "deliver-events", "name": "Deliver events", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 1200, 0 ], "parameters": { "method": "POST", "url": "={{ $('Prepare').first().json.destination }}", "sendBody": true, "specifyBody": "json", "jsonBody": "={{ {items: $json.processed, latest_check: $json.latest_check} }}", "options": { "timeout": 20000 } } } ], "connections": { "Manual run": { "main": [ [ { "node": "Prepare", "type": "main", "index": 0 } ] ] }, "Hourly": { "main": [ [ { "node": "Prepare", "type": "main", "index": 0 } ] ] }, "Prepare": { "main": [ [ { "node": "Create monitor", "type": "main", "index": 0 } ] ] }, "Create monitor": { "main": [ [ { "node": "Poll updates", "type": "main", "index": 0 } ] ] }, "Poll updates": { "main": [ [ { "node": "Process page", "type": "main", "index": 0 } ] ] }, "Process page": { "main": [ [ { "node": "Deliver events", "type": "main", "index": 0 } ] ] }, "Deliver events": { "main": [ [ { "node": "Save checkpoint", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "executionTimeout": 120 } }