How to Use Jev in n8n Workflows (Decision Nodes That Don't Break)
TL;DR: In n8n, Jev becomes the decision node your automation can trust. One HTTP Request node calls the OpenAI-compatible OpenRouter endpoint, a small Code node parses the structured
{answer, confidence, rationale}response, and IF nodes branch on the answer plus a confidence threshold. Failures go down an explicit fallback path instead of breaking the run. Node-by-node setup below.
The workflow at a glance
Trigger (webhook / schedule / new record)
|
v
Set node (build the question text from input fields)
|
v
HTTP Request node -> OpenRouter chat/completions (model: Jev)
|
+--> HTTP error --> Retry (built-in, 2-3 tries, backoff)
| |
| +--> still failing --> Fallback path (notify / default action)
|
v
Code node (parse choices[0].message.content as JSON)
|
+--> invalid JSON --> Fallback path
|
v
IF node (confidence >= 0.85 ?)
|
+--> yes --> branch on answer (e.g. route, tag, approve)
|
+--> no --> Fallback path (human queue with rationale)
Every exit leads somewhere defined. That is the whole trick: the decision node either decides confidently or hands off.
HTTP Request node configuration
| Field | Value |
|---|---|
| Method | POST |
| URL | https://openrouter.ai/api/v1/chat/completions |
| Authentication | Header auth: Authorization: Bearer <OPENROUTER_API_KEY> (store the key in n8n credentials, not in the node) |
| Body (JSON) | {"model":"typesafe/jev-1.13","temperature":0,"messages":[{"role":"system","content":"Answer yes, no, or unclear."},{"role":"user","content":"{{ $json.question }}"}]} |
| Retry on fail | Enabled, 2-3 attempts, with backoff |
| Timeout | ~30 seconds |
The model id used here is typesafe/jev-1.13 — confirm the exact model slug on the OpenRouter model page before going live.
Parsing node (Code node, JavaScript)
// Input: HTTP Request node output from OpenRouter
const raw = $input.first().json;
let parsed;
try {
// example fixture:
// {"answer":"yes","confidence":0.97,"rationale":"..."}
parsed = JSON.parse(raw.choices[0].message.content);
} catch (e) {
return [{ json: { branch: "fallback", reason: "invalid-json", raw } }];
}
const lowConfidence = parsed.confidence < 0.85;
if (lowConfidence) {
return [{ json: { branch: "fallback", reason: "low-confidence", ...parsed } }];
}
return [{ json: { branch: parsed.answer, ...parsed } }];
Downstream IF nodes now switch on $json.branch — clean values like yes, no, or fallback, never scraped prose.
Wiring the fallback path
The fallback branch should do three things: record the raw response and rationale, notify a human (email, Slack, ticket), and optionally take a safe default action so the run completes. The ticket triage and sentiment case study shows a fallback wired to a support queue in exactly this style.
For the channel itself — OpenRouter versus the official API — see the API channels guide, and for your first call from scratch see the first API call guide. Official API endpoints and fields should always be verified against the typesafe.ai documentation.
Applies to Jev 1.13.
Testing the workflow before production
Before you route real traffic through your Jev decision node, run the workflow against pinned sample data inside n8n so you can inspect every branch without touching live systems.
Create four test fixtures. In n8n, open the HTTP Request node, switch to the Output tab, and use Pin Data to freeze a specific response. Build one fixture for each logical path your Code node must handle:
| Fixture | answer | confidence | Expected branch |
|---|---|---|---|
| Clear yes | "yes" | 0.97 | yes |
| Clear no | "no" | 0.91 | no |
| Low confidence | "yes" | 0.72 | fallback (low-confidence) |
| Invalid JSON | "not valid json" | — | fallback (invalid-json) |
How to pin data in n8n. Click the node, open the Output panel, paste a fixture that matches the raw OpenRouter response shape ({"choices":[{"message":{"content":"{...}"}}]}), then click the Pin icon. When you execute the workflow manually (Execute Workflow button in the top bar), n8n uses the pinned data instead of hitting the real endpoint — your API quota stays untouched.
Run with Manual Execution for each fixture. After pinning, click Execute Workflow and check every downstream node’s output panel. Confirm that:
yesandnofixtures reach the correct downstream branch with$json.branchset toyesorno.- The low-confidence fixture routes to the fallback path with
reason: "low-confidence"present. - The invalid-JSON fixture routes to fallback with
reason: "invalid-json".
Record the expected path before you move to the next fixture. A simple table or a comment in the workflow description works — n8n lets you add sticky notes directly on the canvas. Having the expected outcome written down makes it obvious when a later change to the Code node silently breaks a branch.
Once all four fixtures pass, unpin the data, run a single live call against a known question, and compare the result with your recorded expectation. Only then is the node ready for production traffic. For the fields and format the model returns, see the confidence and fallback guide and the first API call guide.
Handling rate limits, timeouts and cost in n8n
Running Jev inside an automated workflow means the node may fire many times in quick succession. Three operational concerns come up repeatedly: back-pressure when the API returns 429, long-running requests that stall the workflow, and per-run cost.
Rate limit back-off (HTTP 429). n8n’s HTTP Request node has a built-in Retry On Fail toggle under the Settings tab. Enable it, set Max Tries to 3, and set Wait Between Tries to at least 2000 ms. For burst scenarios — a batch job that calls Jev for every row in a spreadsheet — add a Split In Batches node before the HTTP Request node and set Batch Size to a value that fits comfortably within the per-minute request budget shown on your OpenRouter dashboard. A Split In Batches node of size 5 means at most 5 parallel HTTP Request executions at any moment; adjust down if you still see 429 errors. The exact request limits depend on your OpenRouter tier — check typesafe.ai documentation for current quota details.
Timeout and retry together. In the HTTP Request node, set Timeout (under Settings) to 30 000 ms (30 s). If the model call takes longer than that, n8n treats it as an error and the Retry On Fail logic kicks in automatically. Combine this with the fallback path described in the parsing section: after three failed attempts the workflow routes to the fallback branch rather than hanging indefinitely.
| n8n control | Node / field | Recommended value |
|---|---|---|
| Retry | HTTP Request → Settings → Retry On Fail | Enabled, 3 tries, 2 s wait |
| Timeout | HTTP Request → Settings → Timeout | 30 000 ms |
| Concurrency cap | Split In Batches → Batch Size | 5 (or lower) |
Keeping cost down. Two levers available inside the HTTP Request body help reduce token usage per call. First, set "temperature": 0 — the workflow already does this in the example body above; deterministic sampling also means you can safely cache repeated identical questions at the workflow layer. Second, keep the system prompt short and direct (the example uses only 9 words). A shorter system prompt means fewer input tokens on every call, which adds up across thousands of workflow executions. For a full breakdown of cost and latency trade-offs see the cost and latency guide.
Common mistakes and how to avoid them
Building the workflow is straightforward; the issues that cause silent failures in production are nearly always small, easy-to-miss details.
Comparing confidence as a string instead of a number. When n8n passes JSON fields between nodes, it sometimes serialises values as strings depending on how the data arrived. If you write $json.confidence >= 0.85 in an IF node’s Value 1 field and the value arrives as the string "0.97", n8n evaluates string comparison — "0.97" >= 0.85 is true in JavaScript’s loose comparison but "0.12" >= 0.85 is also true because "0" sorts after 0. Always cast explicitly in the Code node:
const confidence = Number(parsed.confidence);
const lowConfidence = isNaN(confidence) || confidence < 0.85;
This makes the threshold check immune to string coercion and undefined.
Forgetting try/catch in the Code node. If JSON.parse throws and there is no catch, n8n marks the entire node execution as failed and the run stops. The Code node example in this page wraps the parse in a try/catch that returns a fallback item — copy that pattern exactly. A bare JSON.parse(raw.choices[0].message.content) without a guard is the single most common source of unexpected workflow crashes when working with LLM outputs.
Putting the API key directly in the node instead of n8n Credentials. Any API key typed into a node field is stored in the workflow JSON in plain text and appears in export files, execution logs, and team-shared workflow templates. Instead, create an n8n Credential of type Header Auth, set the name to Authorization and the value to Bearer <YOUR_KEY>, then select that credential in the HTTP Request node’s Authentication dropdown. The key is then encrypted at rest and never appears in workflow exports.
Not alerting on the fallback branch. A fallback path that silently swallows low-confidence or failed responses feels robust during testing but masks real problems in production. Wire the fallback branch to at least one notification node — a Send Email node, a Slack node, or an HTTP Request to a webhook — so you know when confidence is trending downward or the API is unreachable. For troubleshooting patterns when the fallback fires more than expected, see the troubleshooting guide.
FAQ
- How do I call Jev from n8n? An HTTP Request node posting to
https://openrouter.ai/api/v1/chat/completionswith header auth, the model id, and your question in the messages array. - How do I read the structured answer? A Code node parses
choices[0].message.contentas JSON, then the workflow branches on theanswerandconfidencefields. - What does the error branch do? Built-in retries for transient failures; low-confidence, invalid JSON, or repeated failures go to a fallback path — a human queue or safe default — so the run never dies silently.