n8n
n8n is a workflow automation platform with an AI Agent node. The agent can
act, but it has no memory across executions: every workflow run starts from
zero. Korely adds that memory. Attach HTTP Request nodes to your AI Agent
workflow and point them at https://api.korely.ai/v1 with your
API key (kor_live_...).
The agent saves what matters at the end of a conversation and finds it
again on the next run, the next day, or from a different workflow.
This guide uses the n8n HTTP Request node. It is built in, it works on n8n Cloud and on self-hosted n8n, and it sends JSON over HTTPS, which is what the Korely REST API expects. On a self-hosted n8n you can also install the Korely community node, described next.
The Korely community node (self-hosted n8n)
In a self-hosted n8n, open Settings, then
Community Nodes, then Install, and
enter n8n-nodes-korely. Without the panel, run
cd ~/.n8n/nodes && npm install n8n-nodes-korely and
restart n8n. The package is on
npm.
The node covers Memory (Add, Search), Context (Get) and Fact (List, with
As Of; Write; Close; Correct). Its credential asks for the address next
to the key, and Test calls the address with the key, so
a key pointed at the wrong server fails the test instead of the first
run. A kor_live_ key pointed at your own install is told
that keys of the hosted service begin with kor_live_ and do
not work there.
n8n Cloud installs only verified community nodes, and this one is not
verified yet (n8n's public listing of verified nodes had no entry for
n8n-nodes-korely on 1 November 2026). On n8n Cloud, follow the
HTTP Request steps below. We checked the node's operations and its
credential in the published package (version 0.1.0); we did not run it
inside n8n.
Whose memory a write is. Every write names a
user_id or an agent_id
(why). In the node, Memory Add
and Fact Write need an End User ID or an
Agent ID under Additional Fields: with neither, the node
stops before sending and names the fields (n8n-nodes-korely 0.1.1). A
workflow built with 0.1.0 that wrote with neither stops after you update,
against an older Korely server too, until one is filled in. This change is
in the package's changelog; we did not run 0.1.1 inside n8n. The HTTP
Request steps below already send both.
What you get
- Memory across executions. Each n8n execution starts
empty. With Korely attached, the agent saves decisions, summaries and
facts with
POST /v1/memories, and any later run can recall them withGET /v1/context, which returns a context block of the facts that are true now plus the best-matching memories. - Memory across workflows. The memory store is shared. A chat workflow saves a memory; a scheduled digest workflow reads it; the Korely dashboard shows it to you so you can inspect what agents have stored.
- The whole REST API. Store memories, search them by meaning, get a context block, read facts, and manage agents and end users, all with ordinary HTTP calls from n8n nodes.
Prerequisites
You need a Korely API key (kor_live_...). Sign up at
korely.ai. A Hobby account is free and is enough for this
guide.
Step 1: store the credential
In n8n, create a Header Auth credential (or use a generic HTTP credential) with:
Name: AuthorizationValue: Bearer kor_live_YOUR_KEYYou will reference this credential in every HTTP Request node that calls Korely, keeping the key out of individual nodes.
Step 2: build the workflow
The smallest memory-enabled agent uses four nodes:
Chat Trigger ──▶ Recall node ──▶ AI Agent ──▶ Save node ──▶ (reply) │ Chat Model: your model- Add a Chat Trigger node.
-
Add an HTTP Request node called Recall.
Point it at
GET /v1/context. It returns one block with the facts that are true now plus the relevant memories, ready to drop into a prompt.user_idis the end user, andtoken_budgetis the size limit of the block:Method: GETURL: https://api.korely.ai/v1/contextAuthentication: Header Auth → select your Korely credentialQuery params: query = {{ $json.chatInput }}user_id = {{ $json.sessionId }}token_budget = 800 -
Add an AI Agent node. In its system message, inject
the pre-formatted
contextblock from the previous node:You have persistent memory. Here is what is known about the user:{{ $('Recall').item.json.context }}Use this context before answering. When the conversation produces adecision or durable fact, the workflow will save it automatically. -
Add a second HTTP Request node called Save,
wired after the AI Agent:
Method: POSTURL: https://api.korely.ai/v1/memoriesAuthentication: Header Auth → select your Korely credentialSend Body: onBody Content Type: JSONSpecify Body: Using Fields BelowBody fields: content = {{ $('AI Agent').item.json.output }}user_id = {{ $('Chat Trigger').item.json.sessionId }}agent_id = n8n-chat
n8n builds the JSON from the fields, so a reply with quotes or line breaks still sends a valid body. If you prefer Using JSON, make the whole body one expression that returns an object:
{{ JSON.stringify({content: $('AI Agent').item.json.output,user_id: $('Chat Trigger').item.json.sessionId,agent_id: "n8n-chat"}) }}Never paste an expression inside a quoted JSON string (
"content": "{{ ... }}"): the first quote or newline in the text breaks the JSON, and the call returns422.
Step 3: smoke-test the connection
Verify the credential and endpoint are wired correctly before connecting a full agent. In a standalone HTTP Request node:
# from your terminal, the same call the node makescurl -X POST https://api.korely.ai/v1/memories/search \ -H "Authorization: Bearer kor_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "test", "limit": 3}'
A 200 response with a results array confirms the key works
and the endpoint is reachable. Then trigger the workflow from the Chat
Trigger panel and check that the Save node returns a memory
id.
Make the agent use memory on its own
The pattern above is fixed: the workflow always recalls and always saves. You can instead let the agent signal when something is worth saving. Add this to the agent's system message:
You have persistent memory through Korely.- Prior context retrieved from memory is in your system prompt.- When a conversation produces a decision, a summary, or a durable fact, say [SAVE] at the end of your reply so the workflow persists it.- Never ask permission to search or save. Just do it.
In n8n, add an IF node after the AI Agent that checks
whether the output contains [SAVE], and route only those
branches to the Save HTTP Request node.
Example: save in one run, recall in the next
Two separate executions of the same workflow. In the first, the Save node
stores the memory. The next day the same chat user comes back and the
Recall node finds it. Nothing passes between the runs except Korely.
Recall only finds what was saved under the same user_id, so
the session id you use for it has to identify the same person across
conversations. The output below is an example, and your facts will differ.
# Execution 1, Tuesday
You › We picked the Berlin venue for the team offsite. October
14 to 16, budget 6,000 EUR, Dana owns the agenda.
→ Save node POST /v1/memories
body: {
"content": "Offsite decision: Berlin, Oct 14-16. Budget: 6,000
EUR. Agenda owner: Dana.",
"user_id": "session-abc123",
"agent_id": "n8n-chat"
}
← {"id": "mem_7c3e91a2...", "content": "Offsite decision: ..."}
Agent › Saved the offsite decision: Berlin, October 14-16,
6,000 EUR budget, Dana on the agenda. Anything else to capture?
# Execution 2, Wednesday, same chat user
You › Where did we land on the offsite?
→ Recall node GET /v1/context
params: query=offsite venue decision user_id=session-abc123 token_budget=800
← {"context": "_The facts below are a compact profile of the user;
[...]_\n\n## Known facts\n- offsite has_agenda_owner Dana (since
2026-06-16) [planned, not done]\n- offsite has_budget 6000 EUR
(since 2026-06-16) [planned, not done]\n- offsite takes_place_in
Berlin (since 2026-06-16) [planned, not done]\n\n## Relevant
memories\n_A time in square brackets [...]_\n- [2026-06-16]
Offsite decision: Berlin, Oct 14-16. Budget: 6,000 EUR. Agenda
owner: Dana.",
"sources": ["fct_e18a...", "fct_7380...", "fct_3e88...",
"mem_7c3e91a2..."], "degraded": false, "degraded_parts": [], ...}
Agent › You decided on Berlin, October 14 to 16, with a 6,000
EUR budget. Dana owns the agenda. Want me to create a task to
book the venue? /v1/context assembles its block from stored facts and
memories. Facts that a newer one replaced are closed and do not appear. No
language model runs on Korely's side when you read; your agent's chat model
does the reasoning. Reads are cheap for us, so every plan allows at least
100 times more queries than writes per month (see the
pricing page). A fact can take about ten seconds
to appear after the write (extraction),
so a second run seconds after the first may not see it yet.
When you want raw search hits
GET /v1/context suits most agents: one block to drop into a
prompt. When you want individual scored memories to rank, filter or show
yourself, call POST /v1/memories/search. It compares meaning
and returns a results array, each item a
{ id, score, snippet, user_id, agent_id, metadata }
object:
curl -X POST https://api.korely.ai/v1/memories/search \ -H "Authorization: Bearer kor_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "offsite", "user_id": "USER", "limit": 5}'
In n8n, take the snippet field before joining the hits into a
prompt, because the items are objects, not strings:
{{ $('Search').item.json.results.map(r => r.snippet).join('\n') }}.
Beyond chat
Nothing here needs a chat. Replace the Chat Trigger with any other trigger and the same HTTP Request nodes work:
- Schedule Trigger: a nightly agent calls
GET /v1/memorieson a user and saves a digest summary back withPOST /v1/memories. - Webhook or email trigger: before drafting a reply,
the agent searches past context for the sender's name with
POST /v1/memories/search. - Form trigger: intake forms become structured memories
keyed by
user_id, retrievable in any later workflow.
Troubleshooting
| Symptom | Fix |
|---|---|
| HTTP 401 Unauthorized |
Body has "code": "invalid_key" and a message that says
why: send it in the header Authorization: Bearer kor_live_...
when the header is missing, a key of this install is kor_live_
followed by 43 characters when the value is malformed (for
example wrapped in quotes or mistyped), and no live key matches
it (unknown, revoked or expired) when the key is unknown,
revoked or expired. Branch on code, not on the words.
Check the Authorization header is exactly
Bearer kor_live_YOUR_KEY with no extra spaces or
quotes. Verify the credential is selected in the HTTP Request node.
|
| HTTP 429 Too Many Requests |
The body tells you which limit you hit:
"code": "quota_exceeded", with limit,
used and resets_at in the body, means you
have spent your monthly writes or queries (the message says which;
10% grace included). There is no
Retry-After on a quota 429, so retrying in the same
month will not help: stop the workflow until resets_at,
top up the month's writes on a paid plan, or upgrade. A burst rate-limit 429 does carry a
Retry-After header (integer seconds), add a Wait node
for that many seconds before retrying.
"code": "agent_cap_exceeded", with limit
and used, means a new agent_id (such as
n8n-chat) is past your plan's named agents
(2 on Hobby): reuse an existing
agent_id, leave it out, delete one with
DELETE /v1/agents/{agent_id}, or upgrade. Hobby allows
25,000 queries and
250 writes per month.
|
| Search returns empty results on first run |
No memories exist yet for that user_id. The first
run saves; the second run recalls. Check the Save node executed
successfully and returned a memory id.
|
| Agent answers without using retrieved context | Make sure the Recall node output is interpolated into the AI Agent's system message, not just passed as user input. The agent ignores context it cannot see in the prompt. |
| HTTP 422 Unprocessable Entity |
The request body is missing a required field. Check that
content is present for writes, and query
for searches. The response body names the field:
{"code":"invalid_request","message":"content: Field required"}.
|
For the full REST endpoint reference, see the
API reference. For how facts,
supersession and time work, see
temporal facts.
Something not working? Email
[email protected] with your n8n
version (Cloud or self-hosted) and a screenshot of the HTTP Request
node settings. We read every message.