The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "modellogue-slack-relay",
"nodes": [
{
"parameters": {
"trigger": "message",
"channel": "={{ $env.SLACK_RELAY_CHANNEL_ID }}",
"options": {}
},
"type": "n8n-nodes-base.slackTrigger",
"typeVersion": 1,
"position": [
400,
300
],
"id": "9b2a14a0-0001-0001-0001-000000000001",
"name": "Slack Trigger",
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"notes": "Listens for new messages on the channel given by SLACK_RELAY_CHANNEL_ID. Bot Scopes required: channels:history, users:read."
},
{
"parameters": {
"jsCode": "// SR-132 read-direction buffer push.\n// Normalises the Slack event into the relay's RelayedSlackMessage\n// shape and pushes onto a ring buffer of the last 100 messages\n// in workflow-global Static Data.\nconst BUF_KEY = 'slackRelayBuffer';\nconst BUF_MAX = 100;\nconst sd = $getWorkflowStaticData('global');\nif (!Array.isArray(sd[BUF_KEY])) sd[BUF_KEY] = [];\n\n// Slack event payload shape varies by event subtype. We only relay\n// plain messages from real users; bot/edits/deletes are ignored to\n// keep the chat pane uncluttered.\nconst evt = $json;\nconst subtype = evt.subtype || null;\nif (subtype && subtype !== 'thread_broadcast') {\n return [];\n}\nif (!evt.ts || !evt.text || !evt.user) return [];\n\n// Display name resolution: Slack returns a user id (UXXX). The\n// trigger node may include user_profile depending on settings; if\n// not, the relay's polling consumer can fall back to the bare id.\nconst username =\n evt.user_profile?.display_name ||\n evt.user_profile?.real_name ||\n evt.user_profile?.name ||\n evt.user;\n\nconst entry = {\n ts: String(evt.ts),\n user: String(evt.user),\n username: String(username),\n text: String(evt.text),\n};\nsd[BUF_KEY].push(entry);\nif (sd[BUF_KEY].length > BUF_MAX) {\n sd[BUF_KEY] = sd[BUF_KEY].slice(-BUF_MAX);\n}\nreturn [{ json: entry }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
620,
300
],
"id": "9b2a14a0-0001-0001-0001-000000000002",
"name": "Push to Buffer"
},
{
"parameters": {
"httpMethod": "GET",
"path": "slack-relay",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
400,
600
],
"id": "9b2a14a0-0001-0001-0001-000000000003",
"name": "Webhook GET slack-relay",
"notes": "GET /webhook/slack-relay?since=<ts>. ModelLogue's slackRelay service polls this every 1.5s while a session is in REVIEW phase (ADR-017)."
},
{
"parameters": {
"jsCode": "// SR-132 read-direction buffer read.\n// Returns ring-buffer entries with ts strictly greater than ?since.\n// When ?since is omitted or empty, returns the whole buffer (the\n// client treats that as 'first poll, get current snapshot').\nconst BUF_KEY = 'slackRelayBuffer';\nconst sd = $getWorkflowStaticData('global');\nconst buf = Array.isArray(sd[BUF_KEY]) ? sd[BUF_KEY] : [];\n\nconst input = $input.first()?.json || {};\nconst sinceRaw = input.query?.since ?? '';\nconst since = parseFloat(String(sinceRaw));\n\nconst filtered = Number.isFinite(since)\n ? buf.filter((m) => parseFloat(m.ts) > since)\n : buf;\n\nreturn [{ json: { messages: filtered } }];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
620,
600
],
"id": "9b2a14a0-0001-0001-0001-000000000004",
"name": "Read Buffer"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json.messages }}",
"options": {
"responseHeaders": {
"entries": [
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
{
"name": "Access-Control-Allow-Methods",
"value": "GET, OPTIONS"
},
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type"
}
]
}
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
840,
600
],
"id": "9b2a14a0-0001-0001-0001-000000000005",
"name": "Respond GET"
}
],
"connections": {
"Slack Trigger": {
"main": [
[
{
"node": "Push to Buffer",
"type": "main",
"index": 0
}
]
]
},
"Webhook GET slack-relay": {
"main": [
[
{
"node": "Read Buffer",
"type": "main",
"index": 0
}
]
]
},
"Read Buffer": {
"main": [
[
{
"node": "Respond GET",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"tags": [
"modellogue",
"slack-relay",
"ur-017"
]
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
slackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
modellogue-slack-relay. Uses slackTrigger. Event-driven trigger; 5 nodes.
Source: https://github.com/sho1884/ModelLogue/blob/206db72223bccda9c5e31c5e92548c235cd28bf8/n8n/workflows/modellogue-slack-relay.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Vendorbot Form Filler. Uses executeCommand, gmail, telegram, slack. Event-driven trigger; 39 nodes.
Type in Slack. Walk away. Get a professional PDF report and a structured Excel fix sheet delivered to Google Drive and posted back in your Slack thread — fully automated, zero manual work.
Create-Issue-Linear-Slack. Uses linear, postgres, slackTrigger, httpRequest. Event-driven trigger; 33 nodes.
This workflow automates the full company enrichment pipeline: Simply import CSV company lists to Slack and save time on enrichment and CRM maintenance. It processes uploaded files, extracts company do
This workflow enables seamless, bidirectional communication between WhatsApp and Slack using n8n. It automates the reception, processing, and forwarding of messages (text, media, and documents) betwee