{ "kind": "open-flow-workflow", "version": 1, "name": "Notify Slack of New ServiceNow Incidents", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_dfff5e79ac1c5bd7": { "name": "Run on demand", "kind": "start", "inputDefs": [] }, "n_1a06f73352e2f87b": { "name": "Every five minutes", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "*/5 * * * *", "timezone": "UTC" } ] }, "n_b8b5fa8b1db8ca78": { "inputs": { "instanceUrl": { "kind": "value", "value": "https://YOUR_INSTANCE.service-now.com" } }, "name": "Prepare the incident query", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "instanceUrl" } ], "outputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "instanceUrl" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" } ], "name": "Prepare the incident query", "moduleId": "n_acec59cfda34e1fd", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_e74f3edf3a22913d": { "inputs": { "url": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_b8b5fa8b1db8ca78", "output": "url" } ] }, "auth.username": { "kind": "unset" }, "auth.password": { "kind": "unset" } }, "name": "Read recent incidents", "onError": "error", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "url" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.username" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "auth.password" } ], "outputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "statusCode" }, { "jsonSchema": { "type": "object", "additionalProperties": { "type": "string" } }, "nullable": false, "handle": "headers" } ], "name": "Read recent incidents", "executor": { "method": "GET", "query": { "mode": "fields", "names": [] }, "headers": { "mode": "fields", "names": [] }, "bodyFormat": "none", "authentication": { "type": "basic" }, "responseFormat": "json", "statusPolicy": "success", "kind": "http-request" } } }, "n_144cbf6ff065e8c2": { "inputs": {}, "name": "Did the request succeed?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "success", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_e74f3edf3a22913d", "output": "error", "system": true } }, "operator": "isNull" } ] } ] } ] }, "n_0efc1490ff5c1f42": { "inputs": { "channelId": { "kind": "value", "value": "YOUR_SLACK_CHANNEL_ID" }, "text": { "kind": "value", "value": "Issue connecting to ServiceNow. Please investigate the workflow error." } }, "name": "Send the connection alert", "kind": "task", "task": { "inputs": [ { "description": "The Slack conversation or channel ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The Slack conversation or channel ID." }, "nullable": false, "handle": "channelId" }, { "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text.", "jsonSchema": { "type": "string", "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text." }, "nullable": true, "handle": "text", "value": null }, { "description": "Slack Block Kit blocks to render in the message.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Slack Block Kit block object. Pass the block exactly as Slack documents it." }, "minItems": 1, "description": "Slack Block Kit blocks to render in the message." }, "nullable": true, "handle": "blocks", "value": null }, { "description": "Slack legacy attachments to include in the message.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Slack legacy attachment object. Prefer blocks for new messages when possible." }, "minItems": 1, "description": "Slack legacy attachments to include in the message." }, "nullable": true, "handle": "attachments", "value": null }, { "description": "Whether Slack should unfurl links in the message.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should unfurl links in the message." }, "nullable": true, "handle": "unfurlLinks", "value": null }, { "description": "Whether Slack should unfurl media in the message.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should unfurl media in the message." }, "nullable": true, "handle": "unfurlMedia", "value": null }, { "description": "Slack message metadata to attach to the message.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Slack message metadata to attach to the message." }, "nullable": true, "handle": "metadata", "value": null } ], "outputs": [ { "description": "The timestamp identifier of the posted message.", "jsonSchema": { "type": "string", "description": "The timestamp identifier of the posted message." }, "nullable": false, "handle": "ts" }, { "description": "The channel ID where the message was posted.", "jsonSchema": { "type": "string", "description": "The channel ID where the message was posted." }, "nullable": false, "handle": "channelId" } ], "name": "Send the connection alert", "executor": { "kind": "connector", "action": "slack.post_message" } } }, "n_de8a93d0a6b1b333": { "inputs": { "body": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_e74f3edf3a22913d", "output": "body" } ] }, "instanceUrl": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_b8b5fa8b1db8ca78", "output": "instanceUrl" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_de8a93d0a6b1b333", "output": "state" } ] } }, "name": "Prepare the next incident", "kind": "task", "task": { "inputs": [ { "jsonSchema": {}, "nullable": true, "handle": "body" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "instanceUrl" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string", "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text." }, "nullable": true, "handle": "text" }, { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "count" } ], "name": "Prepare the next incident", "moduleId": "n_7618ae73870e345b", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_8173250e1ec255e9": { "inputs": {}, "name": "More incidents?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "send", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_de8a93d0a6b1b333", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_16ecf653765738b5": { "inputs": { "channelId": { "kind": "value", "value": "YOUR_SLACK_CHANNEL_ID" }, "text": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_de8a93d0a6b1b333", "output": "text" } ] } }, "name": "Send incident details", "kind": "task", "task": { "inputs": [ { "description": "The Slack conversation or channel ID.", "jsonSchema": { "type": "string", "minLength": 1, "description": "The Slack conversation or channel ID." }, "nullable": false, "handle": "channelId" }, { "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text.", "jsonSchema": { "type": "string", "description": "Plain text message content. When blocks are provided, Slack uses this as notification and accessibility fallback text." }, "nullable": true, "handle": "text", "value": null }, { "description": "Slack Block Kit blocks to render in the message.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Slack Block Kit block object. Pass the block exactly as Slack documents it." }, "minItems": 1, "description": "Slack Block Kit blocks to render in the message." }, "nullable": true, "handle": "blocks", "value": null }, { "description": "Slack legacy attachments to include in the message.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "A Slack legacy attachment object. Prefer blocks for new messages when possible." }, "minItems": 1, "description": "Slack legacy attachments to include in the message." }, "nullable": true, "handle": "attachments", "value": null }, { "description": "Whether Slack should unfurl links in the message.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should unfurl links in the message." }, "nullable": true, "handle": "unfurlLinks", "value": null }, { "description": "Whether Slack should unfurl media in the message.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should unfurl media in the message." }, "nullable": true, "handle": "unfurlMedia", "value": null }, { "description": "Slack message metadata to attach to the message.", "jsonSchema": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Slack message metadata to attach to the message." }, "nullable": true, "handle": "metadata", "value": null } ], "outputs": [ { "description": "The timestamp identifier of the posted message.", "jsonSchema": { "type": "string", "description": "The timestamp identifier of the posted message." }, "nullable": false, "handle": "ts" }, { "description": "The channel ID where the message was posted.", "jsonSchema": { "type": "string", "description": "The channel ID where the message was posted." }, "nullable": false, "handle": "channelId" } ], "name": "Send incident details", "executor": { "kind": "connector", "action": "slack.post_message" } } }, "n_ce7936ef2c9e944d": { "name": "Complete", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "integer" }, "nullable": false, "handle": "count" } ], "outputMappings": { "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_de8a93d0a6b1b333", "output": "count" } ] } } } }, "edges": [ { "source": "n_dfff5e79ac1c5bd7", "target": "n_b8b5fa8b1db8ca78" }, { "source": "n_1a06f73352e2f87b", "target": "n_b8b5fa8b1db8ca78" }, { "source": "n_b8b5fa8b1db8ca78", "target": "n_e74f3edf3a22913d" }, { "source": "n_e74f3edf3a22913d", "target": "n_144cbf6ff065e8c2" }, { "source": "n_144cbf6ff065e8c2", "target": "n_de8a93d0a6b1b333", "sourceHandle": "success" }, { "source": "n_144cbf6ff065e8c2", "target": "n_0efc1490ff5c1f42", "sourceHandle": "otherwise" }, { "source": "n_de8a93d0a6b1b333", "target": "n_8173250e1ec255e9" }, { "source": "n_8173250e1ec255e9", "target": "n_16ecf653765738b5", "sourceHandle": "send" }, { "source": "n_8173250e1ec255e9", "target": "n_ce7936ef2c9e944d", "sourceHandle": "otherwise" }, { "source": "n_16ecf653765738b5", "target": "n_de8a93d0a6b1b333" } ] } }, "modules": { "n_acec59cfda34e1fd": { "name": "Prepare the incident query", "imports": [], "source": "export default function window({instanceUrl}) {\n if(typeof instanceUrl!=='string'||!/^https:\\/\\/[a-z0-9-]+\\.service-now\\.com$/i.test(instanceUrl)||/YOUR_INSTANCE/i.test(instanceUrl))throw Error('Configure your ServiceNow HTTPS instance URL');\n const since=new Date(Date.now()-5*60*1000).toISOString().slice(0,19).replace('T',' ');\n return {instanceUrl,url:instanceUrl+'/api/now/table/incident?sysparm_query='+encodeURIComponent('sys_created_on>='+since)+'&sysparm_display_value=true&sysparm_limit=50'};\n}\n" }, "n_7618ae73870e345b": { "name": "Prepare the next incident", "imports": [], "source": "export default function next({body,instanceUrl,previousState}) {\n if(!body||!Array.isArray(body.result))throw Error('Invalid ServiceNow incident response');\n const list=body.result.slice().sort((a,b)=>String(a.number??'').localeCompare(String(b.number??'')));const index=previousState?.index??0;\n if(!Number.isInteger(index)||index<0||index>list.length)throw Error('Invalid incident position');\n if(index===list.length)return {state:{index},more:false,text:'',count:index};\n const i=list[index];if(typeof i?.sys_id!=='string'||!/^[a-f0-9]{32}$/i.test(i.sys_id)||typeof i.number!=='string'||!i.number)throw Error('Invalid incident identity');\n const esc=x=>String(x??'not available').replace(/&/g,'&').replace(//g,'>'),caller=typeof i.caller_id==='object'?i.caller_id?.display_value:i.caller_id;\n const text=`ServiceNow Incident Notification\\nIncident ID: ${esc(i.number)}\\nDescription: ${esc(i.short_description)}\\nSeverity: ${esc(i.severity)}\\nCaller: ${esc(caller)}\\nPriority: ${esc(i.priority)}\\nState: ${esc(i.incident_state)}\\nCategory: ${esc(i.category)}\\nDate Opened: ${esc(i.opened_at)}\\nView Incident: ${instanceUrl}/nav_to.do?uri=incident.do%3Fsys_id%3D${i.sys_id}`;\n if(text.length>40000)throw Error('Incident alert exceeds Slack message limit');return {state:{index:index+1},more:true,text,count:index};\n}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }