{ "name": "openclaw-action", "nodes": [ { "id": "webhook-openclaw-action", "name": "Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -700, 40 ], "parameters": { "httpMethod": "POST", "path": "openclaw-action", "authentication": "none", "responseMode": "responseNode", "options": {} } }, { "id": "route-action", "name": "route-action", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ -420, 40 ], "parameters": { "mode": "runOnceForEachItem", "language": "javaScript", "jsCode": "const body = $json.body ?? {};\nconst action = body.action ?? '';\nconst args = body.args ?? {};\nconst requestId = body.request_id ?? '';\nconst now = new Date().toISOString();\nconst workflowStaticData = $getWorkflowStaticData('global');\nconst maxLogEntries = 200;\n\nlet route = 'respond';\nlet statusCode = 400;\nlet responseBody = {\n ok: false,\n request_id: requestId,\n error: { code: 'unknown_action', message: 'action is not supported' },\n};\nlet notifyText = '';\n\nif (action === 'append_log') {\n if (typeof args.text === 'string' && args.text.length > 0) {\n statusCode = 200;\n const record = {\n ts: now,\n source: 'openclaw-action',\n request_id: requestId,\n text: args.text,\n meta: typeof args.meta === 'object' && args.meta !== null ? args.meta : undefined,\n };\n const actionLog = Array.isArray(workflowStaticData.actionLog) ? workflowStaticData.actionLog : [];\n actionLog.push(record);\n if (actionLog.length > maxLogEntries) {\n actionLog.splice(0, actionLog.length - maxLogEntries);\n }\n workflowStaticData.actionLog = actionLog;\n responseBody = {\n ok: true,\n request_id: requestId,\n result: {\n action: 'append_log',\n status: 'logged',\n preview: { text: args.text },\n sink: {\n type: 'workflow-static-data',\n key: 'actionLog',\n retained_entries: maxLogEntries,\n },\n },\n };\n } else {\n responseBody = {\n ok: false,\n request_id: requestId,\n error: { code: 'invalid_request', message: 'required args are missing' },\n };\n }\n} else if (action === 'get_logs') {\n const actionLog = Array.isArray(workflowStaticData.actionLog) ? workflowStaticData.actionLog : [];\n const rawLimit = Number.isFinite(Number(args.limit)) ? Number(args.limit) : 20;\n const limit = Math.max(1, Math.min(50, Math.trunc(rawLimit) || 20));\n const entries = actionLog.slice(-limit).reverse();\n statusCode = 200;\n responseBody = {\n ok: true,\n request_id: requestId,\n result: {\n action: 'get_logs',\n status: 'ok',\n count: entries.length,\n total_retained: actionLog.length,\n retained_entries: maxLogEntries,\n entries,\n },\n };\n} else if (action === 'notify') {\n if (typeof args.message === 'string' && args.message.length > 0) {\n route = 'notify';\n statusCode = 200;\n const title = typeof args.title === 'string' ? args.title : '';\n notifyText = title ? `🔔 ${title}\\n${args.message}` : `🔔 ${args.message}`;\n responseBody = {\n ok: true,\n request_id: requestId,\n result: {\n action: 'notify',\n status: 'sent',\n preview: { title, message: args.message },\n targets: ['telegram', 'discord'],\n },\n };\n } else {\n responseBody = {\n ok: false,\n request_id: requestId,\n error: { code: 'invalid_request', message: 'required args are missing' },\n };\n }\n}\n\nreturn {\n json: {\n route,\n status_code: statusCode,\n response_body: responseBody,\n notify_text: notifyText,\n },\n};" } }, { "id": "route-dispatch", "name": "route-dispatch", "type": "n8n-nodes-base.switch", "typeVersion": 3.4, "position": [ -120, 40 ], "parameters": { "mode": "rules", "rules": { "values": [ { "conditions": { "options": { "caseSensitive": true, "typeValidation": "strict", "version": 2 }, "conditions": [ { "leftValue": "={{$json.route}}", "rightValue": "notify", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "renameOutput": true, "outputKey": "notify" } ] }, "options": { "fallbackOutput": "extra", "renameFallbackOutput": "respond" } } }, { "id": "send-telegram-notification", "name": "Send Telegram Notification", "type": "n8n-nodes-base.telegram", "typeVersion": 1.2, "position": [ 160, 40 ], "parameters": { "chatId": "8367012007", "text": "={{$json.notify_text}}", "additionalFields": {} }, "credentials": { "telegramApi": { "id": "aox4dyIWVSRdcH5z", "name": "Telegram Bot (OpenClaw)" } } }, { "id": "send-discord-notification", "name": "Send Discord Notification", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [ 460, 40 ], "parameters": { "authentication": "predefinedCredentialType", "nodeCredentialType": "httpHeaderAuth", "method": "POST", "url": "https://discord.com/api/v10/channels/425781661268049931/messages", "sendBody": true, "specifyBody": "json", "jsonBody": "={{ { content: $node[\"route-action\"].json[\"notify_text\"] } }}", "options": {} }, "credentials": { "httpHeaderAuth": { "id": "UgPqYcoCNNIgr55m", "name": "Discord Bot Auth" } } }, { "id": "respond-openclaw-action", "name": "Respond to Webhook", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.5, "position": [ 760, 40 ], "parameters": { "respondWith": "json", "responseBody": "={{$node[\"route-action\"].json[\"response_body\"]}}", "options": { "responseCode": "={{$node[\"route-action\"].json[\"status_code\"]}}" } } } ], "connections": { "Webhook": { "main": [ [ { "node": "route-action", "type": "main", "index": 0 } ] ] }, "route-action": { "main": [ [ { "node": "route-dispatch", "type": "main", "index": 0 } ] ] }, "route-dispatch": { "main": [ [ { "node": "Send Telegram Notification", "type": "main", "index": 0 } ], [ { "node": "Respond to Webhook", "type": "main", "index": 0 } ] ] }, "Send Telegram Notification": { "main": [ [ { "node": "Send Discord Notification", "type": "main", "index": 0 } ] ] }, "Send Discord Notification": { "main": [ [ { "node": "Respond to Webhook", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" }, "staticData": null, "meta": { "templateCredsSetupCompleted": false, "note": "After import, set Webhook authentication to Header Auth and bind a local credential using x-openclaw-secret. This asset ships append_log + get_logs via workflow static data plus Telegram/Discord notify fan-out." }, "active": false, "versionId": "openclaw-action-v6" }