← Blog
Integrations

n8n asks, Ragen answers. How to plug your company knowledge base into your automations

You have workflows in n8n and a knowledge base in Ragen. One step is missing: "ask our documentation". Now that assistant_id is optional, Ragen answers n8n's own OpenAI nodes. Three routes: an OpenAI credential with your own base URL, HTTP Request, and an MCP server for agents.

If you build automations in n8n, you know the moment. The workflow runs: a request arrives from a form, the data lands in the CRM, a notification goes to Slack. All of it except the one step that needs knowledge of your own company. Which procedure applies to this type of complaint. What we promised this customer in the contract. Whether we have approved this exception before.

That step usually goes back to a human. And there it stays, because the language model wired into n8n knows the internet, not your documents.

Ragen closes the gap as an HTTP endpoint. You configure an AI Assistant in the dashboard together with its documents and permissions, then call it from anywhere in the automation. Which assistant you are asking is recorded in the API key — which is what lets Ragen answer any client that speaks the OpenAI format, n8n’s own nodes included. Below are three ways to do it, from the simplest to the most autonomous.

Before you start: a scoped key and your instance address

Two things to have to hand. The full procedure is in the Quickstart; this is the short version.

The API key and its scope. Ragen dashboard, Settings → API keys → Create API Key. As you create it you pick a Scope: Whole knowledge base or One assistant. The first, which is the default, answers from documents that belong to no assistant — the same set the chat sees with no assistant selected. The second answers from the documents of the AI Assistant you name. The key is shown once; after you close the dialog only a masked preview remains. While you are there it is worth switching on Debug mode: every API conversation is then saved as a thread under the project’s API threads tab, question and answer together. While you are still building the workflow that saves a lot of guessing.

The scope is a boundary, not a default. This is the one thing in the model that catches people out. The assistant_id field has not gone away, it has become optional — and if you do send it, it has to agree with the key. A key issued for assistant A that receives a request for assistant B answers 403, not an answer from B. A whole-knowledge-base key refuses every assistant_id, including a valid one. So the simplest approach is to leave the field out and let the key decide: one key per workflow or per team, rather than one key and an id pasted into every node. The full matrix of what a key of a given scope may read and change is in the authentication documentation.

The instance address. Ragen is self-hosted, so there is no single public host. The documentation calls it RAGEN_BASE_URL and it ends in /v1. Locally that is http://localhost:3001/v1. If n8n and Ragen sit on the same Docker network, use the service name — http://ragen-api:3001/v1, for instance — and do not expose that traffic to the internet.

Put the key into n8n as its own credential, not into the body of a node. In the HTTP Request node: Authentication → Generic Credential Type → Header Auth, header name Authorization, value Bearer sk-.... That way the key does not leak into a workflow export or into execution logs.

Route 1: HTTP Request to /v1/chat

The shortest path to a working workflow. One question, one answer, no conversation history.

An HTTP Request node, method POST, URL http://ragen-api:3001/v1/chat, authentication as above, Send Body on, Body Content Type: JSON, body entered as JSON:

{
  "content": "{{ $json.question }}",
  "context": "{{ $json.ticketBody }}"
}

The response is as simple as it gets:

{
  "text": "Under the returns procedure the customer has 30 days from delivery..."
}

In the next node you reach it through {{ $json.text }}.

There is no assistant_id here, because the key answers that question. You can add it if you prefer to be explicit, but then it has to name exactly the assistant the key was issued for.

The content field takes between 1 and 10,000 characters and is the actual question. The context field is optional, holds up to 20,000 characters, and exists to attach material that is not in the knowledge base: the body of an email, a ticket description, the contents of a page. content drives the search across your documents; context only adds background to the answer.

Field details, error codes and the streaming format are in the Chat API reference. Do not switch streaming on in n8n — the node waits for the whole response anyway, and you would have to stitch the SSE events together yourself.

The documentation names /v1/chat/completions as the default choice for a new integration, and rightly so: sooner or later you will want conversation history or a usage report. /v1/chat stays the simpler way when the question is one question and that is the end of it.

This route is enough for most automations: triaging a request, a first-line support reply, summarising a document into the CRM, checking a procedure before approving an application.

Route 2: /v1/chat/completions and n8n’s own OpenAI nodes

The second endpoint speaks the OpenAI format and gives you what /v1/chat does not: conversation history, a per-request system prompt, a choice of model, temperature, a token limit and a usage report. The full specification is in the Chat Completions reference.

Now that assistant_id is optional, this endpoint can be called by a client that only knows the OpenAI format — which means you no longer need the HTTP Request node to connect Ragen at all. In an OpenAI Account credential you put the Ragen key as the API Key and your instance address as the Base URL (http://ragen-api:3001/v1). From then on OpenAI Chat Model, Basic LLM Chain and the plain OpenAI node talk to your knowledge base instead of to OpenAI, without a single field set by hand.

The model field in n8n fills its list from GET /v1/models, which Ragen serves. You get the intersection of three things: the model catalogue, whatever the model gateway in your installation actually serves, and whatever the organisation’s administrator has permitted. If you prefer, switch the field to typing an id by hand — both modes work.

One limitation worth knowing about up front. The AI Agent node adds a tools field to the request, because that is how an agent works in LangChain. Ragen refuses tools, tool_choice and response_format with a 400, and it does so deliberately: tool selection lives on the project, through MCP integrations, not in the body of a single request. Plain model nodes do not send that field and work unchanged. If you need an agent that decides for itself when to reach for your knowledge, route 3 is for that.

When you want to compose the request yourself — because you keep conversation history in your own database, or assemble the system prompt from variables — HTTP Request is still the shortest way. Same node, URL .../v1/chat/completions, body:

{
  "model": "gpt-5.4",
  "temperature": 0.2,
  "messages": [
    {
      "role": "system",
      "content": "Answer in at most three sentences. If the documents do not contain the answer, say: no basis in the documentation."
    },
    { "role": "user", "content": "What is our SLA on critical tickets?" },
    { "role": "assistant", "content": "Four working hours." },
    { "role": "user", "content": "{{ $json.question }}" }
  ]
}

The response has the standard OpenAI structure, so you pull the text out through {{ $json.choices[0].message.content }} and token usage through {{ $json.usage.total_tokens }}. The second one is worth recording — into a sheet or a table, say: after two weeks you have the real cost of the workflow instead of an estimate.

A few things that will save you debugging time:

  • The question is the last user message. Earlier messages are conversation history, and system instructions are appended to the project’s instructions rather than replacing them.
  • The messages array holds between 1 and 100 messages. If you keep history in a database, trim it on your side.
  • The remaining standard OpenAI parameters — top_p, stop, seed, presence_penalty and the rest of that list — are accepted and validated, even where some of them do not change the answer today. The point is that a client speaking the OpenAI format should not have to strip its request first.
  • You can leave assistant_id out or send it. Sent, it has to agree with the key’s scope, otherwise you get a 403.

If you would rather write code, on self-hosted n8n you can also use the Code node with the official @webamigos/ragen-sdk-ts SDK, once you have added it to NODE_FUNCTION_ALLOW_EXTERNAL.

Route 3: the MCP server, when the agent is the one asking

The first two routes assume you decide when to reach into the knowledge base. With an agent in n8n that decision belongs to the model, and Ragen is one of the tools on its list.

Ragen exposes an MCP server at $RAGEN_MCP_URL/mcp (Streamable HTTP transport, port 3300 by default), authenticated with the same API key in an Authorization: Bearer header. In n8n you connect it with an MCP Client Tool node attached to an AI Agent, using Bearer authentication. Newer n8n versions let you pick the transport; older ones accept an SSE endpoint only, so if the node shows nothing but an “SSE Endpoint” field, update n8n.

The agent’s own model stays with your provider. Here Ragen is a tool, not a model, so the tools limitation described in route 2 does not apply to this path.

The agent then gets three tools:

  • ragen_chat — send a question and get back an answer grounded in the documents,
  • ragen_search_knowledge_base — search the knowledge base and get back document fragments only, with no answer generated,
  • ragen_list_assistants — list the assistants visible to your key, with their ids.

None of them needs an assistant_id: the field is optional and the key’s scope makes the decision, exactly as on the REST side. A key issued for one assistant answers from it without being asked, and ragen_list_assistants then returns that one only.

There is one trap here worth warning the agent about in its own instructions. A whole-knowledge-base key will list every assistant the organisation owns, but it cannot answer from any of them: it refuses every call naming an assistant with a 403. A model that dutifully calls ragen_list_assistants first and then ragen_chat with the id it found walks straight into that 403. With a key like that, simply leave assistant_id out.

Client configuration, example calls and the response format are covered in the MCP server documentation.

MCP calls always come back whole, never streamed. If your agent handles several sources at once, spell out in its instructions when it should reach for Ragen: “send questions about procedures, contracts and internal documentation to ragen_chat”. Without that the model will happily answer from its own memory, which is exactly what you were trying to avoid.

When you do not want an answer, only the fragments

There is a fourth variant. The POST /v1/search endpoint searches the knowledge base and returns a prepared context block together with the ids of the source files, with no call to the generating model:

{
  "query": "termination terms of the framework agreement",
  "max_results": 5
}

The response gives you context and file_ids. The same material goes to the model in an ordinary conversation; here the decision about what happens next is your workflow’s. It comes out cheaper and faster, and the result is predictable: when you are comparing, classifying, or merely checking whether the documents say anything on a subject at all, generating sentences is a step you do not need. The same tool is available to agents as ragen_search_knowledge_base.

Limits and errors

Four things worth keeping in mind during the integration.

Limits are counted per IP address. 20 requests a minute for /v1/chat and 10 for /v1/chat/completions, because behind each one sits a full RAG pipeline: a search across the documents, a rerank of the results and a model call. Your n8n instance usually leaves from a single address, so all your workflows share that budget at once. When you process a list, put in a Loop Over Items and a Wait node rather than firing a hundred requests in a loop. Per-team limits work separately from this: if a team has an rpm or tpm set in the dashboard, a workflow will hit those regardless of the per-IP limit.

429 and 502 are transient. In the node’s settings switch on Retry On Fail and set Max Tries to 3. Wait Between Tries is a single fixed-delay field, so waiting progressively longer with a random spread is something you build yourself: a loop with a Wait node and a delay computed from the attempt number. Worth remembering either way that retrying patches a single stumble but does not raise the limit. If 429 keeps coming back, three attempts a few seconds apart land in the same window, and the answer is spreading the requests out rather than retrying harder. 401 and 403 are not transient: the first means a bad key, the second a deactivated key or a request outside the key’s scope, and retrying will not help either. The text of a 403 says plainly which of the two it is.

The default timeout is often too short. A response from the full pipeline can take a dozen seconds or more, particularly with longer documents. Set the node’s Timeout option deliberately — 60,000 ms, for example.

A question should be a question. Dropping an entire email into content, signature and thread history included, ruins the search, because half the text is noise. Pull out the question itself and pass the rest in context.

What to choose

ScenarioRoute
n8n’s own nodes, with no request composed by handan OpenAI credential with Ragen’s Base URL
A new integration, the default choice: conversation history, a system prompt, a choice of model, a usage reportPOST /v1/chat/completions
A single question and nothing more, a simpler request bodyPOST /v1/chat
An agent that decides for itself when to reach for company knowledgethe MCP server, MCP Client Tool node
Document fragments only, for further processingPOST /v1/search

What they have in common is that you do the configuration once, in the dashboard: documents, permissions, the assistant’s instructions, the choice of model, and — as of recently — what a key has access to. The workflows in n8n only ask. When a new document lands in the knowledge base or a procedure changes, you touch none of them.

Ragen is open source software under the Apache 2.0 licence, so you can run this whole API yourself and try it against your own documents before you decide anything. The code is on GitHub and the documentation at docs.ragen.ai.


If you already have processes in n8n and you are wondering which of them would gain most from access to company knowledge, we are happy to go through it on specifics. Book a free consultation.

Frequently asked questions

Can I point n8n's OpenAI node at Ragen? +

Yes. The assistant_id field is optional, and which AI Assistant you are asking is decided by the API key's scope. An OpenAI credential with your instance as its base URL and a Ragen key is enough. One exception: the AI Agent node adds a tools field to the request, which Ragen refuses with a 400 — agents have their own route, through the MCP server.

How does Ragen know which assistant I am asking if I do not send assistant_id? +

From the API key. When you create a key you pick a scope: one AI Assistant, or the whole knowledge base. The scope is a boundary rather than a default — a key issued for one assistant refuses a request naming a different one with a 403, and a knowledge-base key refuses any assistant_id at all.

How many requests per minute will the Ragen API take? +

Limits are counted per IP address: 20 requests a minute for /v1/chat and 10 for /v1/chat/completions. A whole n8n instance usually leaves from one address, so all your workflows share that budget. Per-team limits — rpm and tpm — apply separately, if an administrator has set them.

Can I query the knowledge base without generating an answer? +

Yes. The /v1/search endpoint returns a prepared context block and the ids of the source files, with no language-model call. It is faster and cheaper whenever your workflow makes the decision anyway.