This workflow follows the Datatable → HTTP Request recipe pattern — see all workflows that pair these two integrations.
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": "52 - TOOL - get_business_memory",
"nodes": [
{
"parameters": {
"content": "## Read local business memory\nReads only the SQLite-backed business research exposed by the local chat gateway. With no domain it returns the most recently updated saved domains; with a domain it returns that domain only.",
"height": 240,
"width": 540,
"color": 4
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-640,
-280
],
"id": "95200000-0000-4000-8000-000000000001",
"name": "Memory tool explanation"
},
{
"parameters": {
"inputSource": "workflowInputs",
"workflowInputs": {
"values": [
{
"name": "sessionId",
"type": "string"
},
{
"name": "requestId",
"type": "string"
},
{
"name": "domain",
"type": "string"
}
]
}
},
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1.2,
"position": [
-500,
20
],
"id": "95200000-0000-4000-8000-000000000002",
"name": "Tool Input"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"language": "javaScript",
"jsCode": "const sessionId = typeof $json.sessionId === 'string' ? $json.sessionId.trim() : '';\nconst requestId = typeof $json.requestId === 'string' ? $json.requestId.trim() : '';\nconst rawDomain = typeof $json.domain === 'string' ? $json.domain.trim() : '';\nconst uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nlet domain = '';\nlet error = null;\nif (!uuidPattern.test(sessionId) || !uuidPattern.test(requestId)) {\n error = { code: 'INVALID_SESSION', message: 'The memory request needs a valid conversation and request ID.' };\n}\nif (!error && rawDomain) {\n // n8n Code nodes run in a vm sandbox that has no URL global, so the host is\n // parsed with string operations only. The URL constructor throws a\n // ReferenceError here, which a catch block reports as an invalid domain.\n let host = rawDomain.toLowerCase();\n const schemeMatch = host.match(/^([a-z][a-z0-9+.-]*):\\/\\//);\n if (schemeMatch) {\n host = ['http', 'https'].includes(schemeMatch[1]) ? host.slice(schemeMatch[0].length) : '';\n }\n host = host.split('/')[0].split('?')[0].split('#')[0];\n const portMatch = host.match(/^(.*):([0-9]*)$/);\n if (portMatch) {\n host = portMatch[1];\n }\n host = host.replace(/\\.$/, '').replace(/^www\\./, '');\n const labels = host.split('.');\n if (host === '' || host.length > 253 || host.includes('@') || host.includes('[') || host.includes(']') || host.includes(' ') || labels.length < 2 || labels.some((label) => !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label))) {\n error = { code: 'INVALID_DOMAIN', message: 'Use a complete saved business domain such as example.com.' };\n } else {\n domain = host;\n }\n}\nconst proposedInput = { sessionId, requestId, domain };\nreturn { json: { valid: error === null, ...proposedInput, proposedInput, ...(error ? { response: { ok: false, error } } : {}) } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-260,
20
],
"id": "95200000-0000-4000-8000-000000000003",
"name": "Validate Memory Input"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "95200000-0000-4000-8000-000000000004",
"leftValue": "={{ $json.valid }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
-20,
20
],
"id": "95200000-0000-4000-8000-000000000005",
"name": "Input Is Valid?"
},
{
"parameters": {
"url": "={{ 'http://127.0.0.1:3000/api/business-memory' + ($('Validate Memory Input').item.json.domain ? '?domain=' + encodeURIComponent($('Validate Memory Input').item.json.domain) : '') }}",
"options": {
"timeout": 10000
}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
240,
-60
],
"id": "95200000-0000-4000-8000-000000000006",
"name": "Read Local Business Memory",
"onError": "continueRegularOutput"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"language": "javaScript",
"jsCode": "const input = $('Validate Memory Input').first().json;\nconst memories = Array.isArray($json.memories) ? $json.memories : null;\nconst response = memories\n ? { ok: true, domain: input.domain || null, count: memories.length, memories, message: memories.length ? 'Saved business research loaded from local memory.' : 'No saved business research was found for that domain.' }\n : { ok: false, error: { code: 'BUSINESS_MEMORY_UNAVAILABLE', message: String($json.error?.message ?? 'Saved business research is not available right now.') } };\nreturn { json: { ...input, response } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
500,
-60
],
"id": "95200000-0000-4000-8000-000000000007",
"name": "Shape Memory Result"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"language": "javaScript",
"jsCode": "const input = $('Validate Memory Input').first().json;\nconst response = $json.response ?? { ok: false, error: { code: 'BUSINESS_MEMORY_UNAVAILABLE', message: 'Saved business research is not available right now.' } };\nreturn { json: { occurredAt: new Date().toISOString(), sessionId: input.sessionId, requestId: input.requestId, toolName: 'get_business_memory', proposedInput: JSON.stringify(input.proposedInput ?? {}), result: JSON.stringify(response), error: response.ok === false ? String(response.error?.message ?? 'Tool failed') : '', response } };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
760,
20
],
"id": "95200000-0000-4000-8000-000000000008",
"name": "Prepare Audit"
},
{
"parameters": {
"resource": "row",
"operation": "insert",
"dataTableId": {
"__rl": true,
"value": "tool_audit",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"occurredAt": "={{ $json.occurredAt }}",
"sessionId": "={{ $json.sessionId }}",
"requestId": "={{ $json.requestId }}",
"toolName": "={{ $json.toolName }}",
"proposedInput": "={{ $json.proposedInput }}",
"result": "={{ $json.result }}",
"error": "={{ $json.error }}"
},
"matchingColumns": [],
"schema": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"type": "n8n-nodes-base.dataTable",
"typeVersion": 1.1,
"position": [
1000,
20
],
"id": "95200000-0000-4000-8000-000000000009",
"name": "Write Tool Audit",
"onError": "continueRegularOutput"
},
{
"parameters": {
"mode": "runOnceForEachItem",
"language": "javaScript",
"jsCode": "const prepared = $('Prepare Audit').item.json;\nconst response = { ...prepared.response };\nif (!Number.isInteger($json.id)) response.auditWarning = 'The tool result could not be written to the local audit table.';\nreturn { json: response };"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1240,
20
],
"id": "95200000-0000-4000-8000-000000000010",
"name": "Return Tool Result"
}
],
"connections": {
"Tool Input": {
"main": [
[
{
"node": "Validate Memory Input",
"type": "main",
"index": 0
}
]
]
},
"Validate Memory Input": {
"main": [
[
{
"node": "Input Is Valid?",
"type": "main",
"index": 0
}
]
]
},
"Input Is Valid?": {
"main": [
[
{
"node": "Read Local Business Memory",
"type": "main",
"index": 0
}
],
[
{
"node": "Prepare Audit",
"type": "main",
"index": 0
}
]
]
},
"Read Local Business Memory": {
"main": [
[
{
"node": "Shape Memory Result",
"type": "main",
"index": 0
}
]
]
},
"Shape Memory Result": {
"main": [
[
{
"node": "Prepare Audit",
"type": "main",
"index": 0
}
]
]
},
"Prepare Audit": {
"main": [
[
{
"node": "Write Tool Audit",
"type": "main",
"index": 0
}
]
]
},
"Write Tool Audit": {
"main": [
[
{
"node": "Return Tool Result",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"executionTimeout": 30,
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "all",
"saveExecutionProgress": true,
"saveManualExecutions": true
},
"versionId": "95200000-0000-4000-8000-000000000100",
"meta": {
"templateCredsSetupCompleted": false,
"phase": 9,
"testedWithN8n": "2.30.5",
"toolRisk": "read",
"authorization": "automatic-current-context-read",
"dataSource": "local-sqlite-business-memory"
},
"id": "phase9GetBusinessMemory",
"tags": [
{
"id": "tagAgentCanDo",
"name": "What your agent can do"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
52 - TOOL - get_business_memory. Uses executeWorkflowTrigger, httpRequest, dataTable. Event-driven trigger; 9 nodes.
Source: https://github.com/drsamdonegan/ai-solopreneur/blob/main/optional-skills/domain-research/workflows/52-tool-get-business-memory.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.
62 - TOOL - read_competitor_posts. Uses executeWorkflowTrigger, httpRequest, dataTable. Event-driven trigger; 23 nodes.
How It Works This sub-workflow uploads files to Dropbox and returns a direct download link:
50 - TOOL - start_domain_research. Uses executeWorkflowTrigger, httpRequest, dataTable. Event-driven trigger; 18 nodes.
51 - TOOL - complete_domain_research. Uses executeWorkflowTrigger, httpRequest, dataTable. Event-driven trigger; 9 nodes.
02_LLM_Pipeline v1.0. Uses executeWorkflowTrigger, httpRequest, seaTable. Event-driven trigger; 65 nodes.