{ "kind": "open-flow-workflow", "version": 1, "name": "High-Revenue HubSpot Companies to Slack", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_2f5e7b8484817904": { "name": "Every five minutes", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "*/5 * * * *", "timezone": "UTC" } ] }, "n_9ced4b4a75b0587e": { "inputs": {}, "name": "Set the five-minute window", "kind": "task", "task": { "inputs": [], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "HubSpot CRM search filter group." }, "maxItems": 5, "description": "HubSpot filter groups used to narrow the search." }, "nullable": true, "handle": "filterGroups" } ], "name": "Set the five-minute window", "moduleId": "n_091a6fa32885aa30", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_270c25ed37da02cf": { "inputs": { "filterGroups": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9ced4b4a75b0587e", "output": "filterGroups" } ] }, "sorts": { "kind": "value", "value": [ "-hs_lastmodifieddate" ] }, "properties": { "kind": "value", "value": [ "name", "website", "annualrevenue", "numberofemployees" ] }, "limit": { "kind": "value", "value": 100 }, "after": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_99e6a3b9333657b5", "output": "after" } ] } }, "name": "Find recently modified companies", "kind": "task", "task": { "inputs": [ { "description": "Full-text query applied to the HubSpot CRM search.", "jsonSchema": { "type": "string", "description": "Full-text query applied to the HubSpot CRM search." }, "nullable": true, "handle": "query", "value": null }, { "description": "HubSpot filter groups used to narrow the search.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": {}, "additionalProperties": true, "description": "HubSpot CRM search filter group." }, "maxItems": 5, "description": "HubSpot filter groups used to narrow the search." }, "nullable": true, "handle": "filterGroups", "value": null }, { "description": "HubSpot sort expressions.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "HubSpot sort expression." }, "description": "HubSpot sort expressions." }, "nullable": true, "handle": "sorts", "value": null }, { "description": "Property names to include in the returned record payload.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "HubSpot property name." }, "description": "Property names to include in the returned record payload." }, "nullable": true, "handle": "properties", "value": null }, { "description": "Property names to include with their value history.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "HubSpot property name." }, "description": "Property names to include with their value history." }, "nullable": true, "handle": "propertiesWithHistory", "value": null }, { "description": "Associated object types to include in the response.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "HubSpot associated object type." }, "description": "Associated object types to include in the response." }, "nullable": true, "handle": "associations", "value": null }, { "description": "Maximum number of records to return.", "jsonSchema": { "type": "integer", "minimum": 1, "maximum": 200, "description": "Maximum number of records to return." }, "nullable": true, "handle": "limit", "value": null }, { "description": "Paging cursor returned by a previous search request.", "jsonSchema": { "type": "string", "minLength": 1, "description": "Paging cursor returned by a previous search request." }, "nullable": true, "handle": "after", "value": null } ], "outputs": [ { "description": "Records returned by the search request.", "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "HubSpot record identifier." }, "archived": { "type": "boolean", "description": "Whether the record is archived." }, "createdAt": { "type": "string", "description": "Timestamp when the record was created." }, "updatedAt": { "type": "string", "description": "Timestamp when the record was last updated." }, "properties": { "type": "object", "additionalProperties": { "description": "Property value." }, "description": "HubSpot properties keyed by property name." }, "propertiesWithHistory": { "type": "object", "additionalProperties": { "description": "Property history payload." }, "description": "HubSpot property histories keyed by property name." }, "associations": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Associations returned by HubSpot when requested." } }, "additionalProperties": true, "description": "HubSpot CRM record returned by the MCP server." }, "description": "Records returned by the search request." }, "nullable": false, "handle": "results" }, { "description": "Paging information returned by HubSpot.", "jsonSchema": { "type": "object", "properties": { "nextAfter": { "type": "string", "description": "Cursor for the next search request when another page is available." } }, "additionalProperties": true, "description": "Paging information returned by HubSpot." }, "nullable": true, "handle": "paging" }, { "description": "Raw MCP response payload.", "jsonSchema": { "description": "Raw MCP response payload." }, "nullable": true, "handle": "raw" } ], "name": "Find recently modified companies", "executor": { "kind": "connector", "action": "hubspot.search_companies" } } }, "n_99e6a3b9333657b5": { "inputs": { "results": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_270c25ed37da02cf", "output": "results" } ] }, "paging": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_270c25ed37da02cf", "output": "paging" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_99e6a3b9333657b5", "output": "state" } ] } }, "name": "Collect company pages", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string", "description": "HubSpot record identifier." }, "archived": { "type": "boolean", "description": "Whether the record is archived." }, "createdAt": { "type": "string", "description": "Timestamp when the record was created." }, "updatedAt": { "type": "string", "description": "Timestamp when the record was last updated." }, "properties": { "type": "object", "additionalProperties": { "description": "Property value." }, "description": "HubSpot properties keyed by property name." }, "propertiesWithHistory": { "type": "object", "additionalProperties": { "description": "Property history payload." }, "description": "HubSpot property histories keyed by property name." }, "associations": { "type": "object", "properties": {}, "additionalProperties": true, "description": "Associations returned by HubSpot when requested." } }, "additionalProperties": true, "description": "HubSpot CRM record returned by the MCP server." }, "description": "Records returned by the search request." }, "nullable": false, "handle": "results" }, { "jsonSchema": { "type": "object", "properties": { "nextAfter": { "type": "string", "description": "Cursor for the next search request when another page is available." } }, "additionalProperties": true, "description": "Paging information returned by HubSpot." }, "nullable": true, "handle": "paging" }, { "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", "minLength": 1 }, "nullable": false, "handle": "after" } ], "name": "Collect company pages", "moduleId": "n_70fb2a57a6550c63", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_1e60d7e3c4428979": { "inputs": {}, "name": "More company pages?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_99e6a3b9333657b5", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_4a112a74a1ad6b86": { "inputs": { "state": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_99e6a3b9333657b5", "output": "state" } ] } }, "name": "Prepare high-revenue alerts", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "messages" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "hasMessages" } ], "name": "Prepare high-revenue alerts", "moduleId": "n_c7cbf28e8afe18ad", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_98ecb64a1dc08b44": { "inputs": {}, "name": "Any qualifying companies?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_4a112a74a1ad6b86", "output": "hasMessages" } }, "operator": "isTrue" } ] } ] } ] }, "n_23482fbf53151af8": { "inputs": { "userIds": { "kind": "value", "value": [ "YOUR_SLACK_USER_ID" ] } }, "name": "Open sales rep DM", "kind": "task", "task": { "inputs": [ { "description": "The single Slack user to include in the DM.", "jsonSchema": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "The Slack user ID." }, "minItems": 1, "maxItems": 1, "description": "The single Slack user to include in the DM." }, "nullable": false, "handle": "userIds" }, { "description": "Whether Slack should avoid creating a new conversation.", "jsonSchema": { "type": "boolean", "description": "Whether Slack should avoid creating a new conversation." }, "nullable": true, "handle": "preventCreation", "value": null } ], "outputs": [ { "description": "The opened Slack conversation ID.", "jsonSchema": { "type": "string", "description": "The opened Slack conversation ID." }, "nullable": false, "handle": "channelId" }, { "description": "A normalized Slack conversation record.", "jsonSchema": { "type": "object", "properties": { "channelId": { "type": "string", "description": "The unique identifier of the conversation." }, "name": { "type": [ "string", "null" ], "description": "The name of the conversation when available." }, "type": { "type": "string", "enum": [ "public_channel", "private_channel", "im", "mpim", "unknown" ], "description": "The normalized Slack conversation type." }, "isArchived": { "type": [ "boolean", "null" ], "description": "Whether the conversation is archived." }, "isPrivate": { "type": [ "boolean", "null" ], "description": "Whether the conversation is private." }, "isMember": { "type": [ "boolean", "null" ], "description": "Whether the connected Slack identity is a member." }, "memberCount": { "type": "integer", "description": "The member count when Slack provides it." }, "topic": { "type": [ "string", "null" ], "description": "The conversation topic." }, "purpose": { "type": [ "string", "null" ], "description": "The conversation purpose." }, "userId": { "type": "string", "description": "The linked user identifier for IM conversations." }, "locale": { "type": "string", "description": "The locale returned by Slack when requested." }, "created": { "type": "integer", "description": "Creation time as a Unix timestamp in seconds when Slack provides it." }, "updated": { "type": "integer", "description": "Last settings update time, passed through as Slack returns it. Slack documents epoch milliseconds for channels (unlike created) and a Unix timestamp for legacy IM and MPIM objects." }, "creatorId": { "type": "string", "description": "The user who created the conversation when Slack provides it." }, "isShared": { "type": "boolean", "description": "Whether the conversation is shared with another workspace." }, "isExtShared": { "type": "boolean", "description": "Whether the conversation is shared with an external organization." }, "isOrgShared": { "type": "boolean", "description": "Whether the conversation is shared between workspaces of the same Enterprise organization." }, "contextTeamId": { "type": "string", "description": "The ID of the workspace the conversation is within when Slack provides it." }, "lastRead": { "type": "string", "description": "The last-read message timestamp when Slack provides it." }, "unreadCount": { "type": "integer", "description": "The unread message count when Slack provides it." } }, "required": [ "channelId", "name", "type", "isArchived", "isPrivate", "isMember", "topic", "purpose" ], "additionalProperties": false, "description": "A normalized Slack conversation record." }, "nullable": false, "handle": "conversation" } ], "name": "Open sales rep DM", "executor": { "kind": "connector", "action": "slack.open_conversation" } } }, "n_dd8426df716c1737": { "inputs": { "messages": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_4a112a74a1ad6b86", "output": "messages" } ] }, "previousState": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd8426df716c1737", "output": "state" } ] }, "channelId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_23482fbf53151af8", "output": "channelId" } ] } }, "name": "Prepare next alert", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "messages" }, { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": true, "handle": "previousState" }, { "jsonSchema": { "type": "string", "description": "The opened Slack conversation ID." }, "nullable": false, "handle": "channelId" } ], "outputs": [ { "jsonSchema": { "type": "object", "additionalProperties": true }, "nullable": false, "handle": "state" }, { "jsonSchema": { "type": "boolean" }, "nullable": false, "handle": "more" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "text" }, { "jsonSchema": { "type": "string", "minLength": 1 }, "nullable": false, "handle": "channelId" } ], "name": "Prepare next alert", "moduleId": "n_48fbef1a0d79fba6", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_5640ec62d17a2a44": { "inputs": {}, "name": "More alerts?", "kind": "condition", "matchMode": "first", "cases": [ { "output": "yes", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_dd8426df716c1737", "output": "more" } }, "operator": "isTrue" } ] } ] } ] }, "n_9c605c3133f62869": { "inputs": { "channelId": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd8426df716c1737", "output": "channelId" } ] }, "text": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_dd8426df716c1737", "output": "text" } ] } }, "name": "Notify the sales rep", "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": "Notify the sales rep", "executor": { "kind": "connector", "action": "slack.post_message" } } } }, "edges": [ { "source": "n_2f5e7b8484817904", "target": "n_9ced4b4a75b0587e" }, { "source": "n_9ced4b4a75b0587e", "target": "n_270c25ed37da02cf" }, { "source": "n_270c25ed37da02cf", "target": "n_99e6a3b9333657b5" }, { "source": "n_99e6a3b9333657b5", "target": "n_1e60d7e3c4428979" }, { "source": "n_1e60d7e3c4428979", "target": "n_270c25ed37da02cf", "sourceHandle": "yes" }, { "source": "n_1e60d7e3c4428979", "target": "n_4a112a74a1ad6b86", "sourceHandle": "otherwise" }, { "source": "n_4a112a74a1ad6b86", "target": "n_98ecb64a1dc08b44" }, { "source": "n_98ecb64a1dc08b44", "target": "n_23482fbf53151af8", "sourceHandle": "yes" }, { "source": "n_23482fbf53151af8", "target": "n_dd8426df716c1737" }, { "source": "n_dd8426df716c1737", "target": "n_5640ec62d17a2a44" }, { "source": "n_5640ec62d17a2a44", "target": "n_9c605c3133f62869", "sourceHandle": "yes" }, { "source": "n_9c605c3133f62869", "target": "n_dd8426df716c1737" } ] } }, "modules": { "n_091a6fa32885aa30": { "name": "Set the five-minute window", "imports": [], "source": "export default function windowFilter(){return {filterGroups:[{filters:[{propertyName:'hs_lastmodifieddate',operator:'GTE',value:String(Date.now()-300000)}]}]};}\n" }, "n_70fb2a57a6550c63": { "name": "Collect company pages", "imports": [], "source": "export default function collectLeads({results,paging,previousState}){\n const state=previousState??{records:[],seen:[]};if(!Array.isArray(results)||!Array.isArray(state.records)||!Array.isArray(state.seen))throw Error('Invalid HubSpot page');\n const cursor=paging?.nextAfter??null;if(cursor!==null&&(typeof cursor!=='string'||!cursor||state.seen.includes(cursor)))throw Error('Invalid or repeated HubSpot cursor');\n const records=[...state.records,...results];if(records.length>=10000)throw Error('HubSpot search result limit reached; no notifications sent');\n return {state:{records,seen:cursor?[...state.seen,cursor]:state.seen},more:cursor!==null,after:cursor??'unused'};\n}\n" }, "n_c7cbf28e8afe18ad": { "name": "Prepare high-revenue alerts", "imports": [], "source": "export default function prepareLeads({state}){\n if(!Array.isArray(state?.records))throw Error('Invalid HubSpot results');const messages=[],esc=x=>String(x).replace(/&/g,'&').replace(//g,'>');\n for(const r of state.records){const p=r?.properties;if(!p||typeof p!=='object'||Array.isArray(p))throw Error('Missing company properties');const raw=p.annualrevenue;if((typeof raw!=='string'&&typeof raw!=='number')||!String(raw).trim()||!Number.isFinite(Number(raw)))throw Error('Company has invalid annual revenue');const revenue=parseInt(String(raw),10);if(!Number.isFinite(revenue))throw Error('Company has invalid annual revenue');if(revenue<=5000000)continue;for(const k of ['name','website','numberofemployees'])if((typeof p[k]!=='string'&&typeof p[k]!=='number')||!String(p[k]).trim())throw Error('Qualifying company has missing details');const text=`New high-quality lead 🤑\\n*Company Name*: ${esc(p.name)} \\n*Website*: ${esc(p.website)}\\n*Revenue*: ${esc(raw)}\\n*Number of employees*: ${esc(p.numberofemployees)}`;if(text.length>4000)throw Error('Slack message too long');messages.push({text});}return {messages,hasMessages:messages.length>0};\n}\n" }, "n_48fbef1a0d79fba6": { "name": "Prepare next alert", "imports": [], "source": "export default function nextMessage({messages,previousState,channelId}){if(typeof channelId!=='string'||!channelId)throw Error('Invalid Slack conversation');const index=previousState?.index??0;if(!Array.isArray(messages)||!Number.isInteger(index)||index<0||index>messages.length)throw Error('Invalid message state');return index===messages.length?{state:{index},more:false,text:'',channelId}:{state:{index:index+1},more:true,text:messages[index].text,channelId};}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }