HTTP and the web
Four nodes in the “HTTP and web” group solve three different problems, and confusing them is expensive: http_request calls any API as a graph step, fetch_webpage lets an agent read a page behind a link, and websearch and openrouter_web_search search the internet — but the first is free and only gives titles with snippets, while the second costs credits and returns text excerpts alongside the model’s answer.
None of them needs a connection: there is no login and no server to remember. A third-party API key lives not in a connection but in a workspace secret and is substituted through a template.
http_request — the universal door outward
This is the one node that makes an arbitrary HTTP request: method, address, headers, query parameters, body. Anything the platform has no dedicated integration for is done with it — from an internal company service to an API we have never heard of.
- Execute + Data
What you configure
| Field | Values | Note |
|---|---|---|
| Method | GET, POST, PUT, PATCH, DELETE, HEAD | GET and HEAD send no body, whatever sits in Body |
| URL | http/https | templated |
| Headers | JSON object | the whole field is templated, not just the values |
| Query Parameters | JSON object | numbers and booleans are stringified for you |
| Body Type | none · json · text · form | form is application/x-www-form-urlencoded, written as a JSON object |
| Body | string | templated; for json it must be valid JSON after substitution |
| Auth Type | none · bearer · basic · custom header | fills the Authorization header for you |
| Timeout | 1…120 seconds, 30 by default | a plan may lower the ceiling, never raise it |
| Max Response Bytes | 1 KiB…10 MB, 1 MB by default | a longer response is truncated |
| Follow Redirects | on | every hop is re-checked |
| Parse JSON Response | on | the body is decoded only if the server declared JSON |
| Fail on 4xx/5xx | on | turn it off when a 404 is a normal answer for you |
Templates and secrets
The address, headers, parameters, body and the auth fields all go through the
template engine. So {{ inputs.input }},
{{ nodes.<id>.output.<field> }} and {{ secret.NAME }} all work in them.
URL https://api.example.com/v1/orders/{{ inputs.input.order_id }}
Headers {"X-Api-Key": "{{ secret.SHOP_API_KEY }}"}
Body {"comment": {{ nodes.llm_1.output | tojson }}}
The key lives in Settings → Secrets, not in the graph. This is not hygiene for its own sake: a graph can be exported, shown to a colleague or handed to the assistant, and a token pasted straight into its JSON travels with it.
What the node passes on
The response arrives as a single object. {{ nodes.<id>.output }} is that whole object.
| Field | What is inside |
|---|---|
| status_code | the response code as a number |
| ok | true for 2xx |
| body | parsed JSON when the server sent JSON and parsing is on; otherwise a string |
| text | the raw response text, always |
| headers | response headers |
| url | the final address after every redirect |
| elapsed_ms | round-trip time in milliseconds |
Here the error branch is on by default
On most nodes the on_error output is off and has to be enabled by hand (see
Node errors). On http_request it is on from the start — it is the only
node in the catalogue with that default, and the reason is the nature of the job.
Somebody else’s server answers 500, returns 429, goes silent until the timeout or drops
the connection. That is not a bug in your workflow, it is a normal, expected outcome of
calling somebody else’s infrastructure. With the branch off, the single most common
failure in the product would always end the same way: the whole run dies, the person in the
chat gets nothing, and the author finds out from the run list. With the branch on, you
decide — say “the service is unavailable, try later”, fall back to another source, mail
yourself.
- Execute + Data
What routes control into the error branch: a network failure, a timeout, and — while
Fail on 4xx/5xx is on — any non-2xx answer. Turn that toggle off when the status code
is data to you (a 404 meaning “no such customer”): the node then always takes the success
path and you branch on {{ nodes.<id>.output.ok }} with an ordinary condition.
The error branch receives an object with a code and a message. The author does see the remote’s own response text: the service behind that address is theirs, and its words are the diagnosis. It is never shown to the person in the chat.
Where the node will not go
Every outbound request from the platform goes through a guarded client. It resolves the
hostname and refuses if the address falls into a private range: loopback,
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, link-local 169.254.0.0/16 (the cloud
metadata address), multicast and reserved space. Redirects are followed manually and
re-checked on every hop — otherwise a public address answering 302 to
http://169.254.169.254/ would bypass the check entirely.
The restriction is not cosmetic: the URL field is a template, so part of it may come from a user’s message. Without this check a chatbot becomes a scanner of the internal network of the server it runs on.
fetch_webpage — page reading for an agent
This node has neither a run input nor a success output: it exists only as an agent
tool. Drop it on the canvas, drag tool_out into the extensions port of
ai_agent, and the model decides for itself when to open a link.
What it does: downloads the page, extracts the main content and converts the HTML to
Markdown, dropping navigation and markup. The model gets readable text rather than a
thousand-character <div>. The settings are a length limit (8000 characters by default, up
to 50,000), a timeout (20 seconds by default) and a cap on the raw response size. The limit
belongs to the author, not the model: the model cannot ask for more than you allowed.
Address checking is the same as for http_request: a link into the internal network is
rejected, and the model is told the address is not allowed rather than handed text from an
internal service.
Two searches, and they are not interchangeable
| websearch | openrouter_web_search | |
|---|---|---|
| How it attaches | agent tool only | both a graph step and an agent tool |
| Source | DuckDuckGo | search on OpenRouter's side, together with a model call |
| What it returns | title, short snippet, link | the model's answer plus sources with text excerpts |
| Price | free | credits per search |
| When to take it | "find me a link", then fetch_webpage reads it | when you need a coherent answer with citations |
websearch returns up to ten results (five by default) — enough for an agent to find the
right page and read it with fetch_webpage. That pair is the free replacement for paid
search, if you accept lower excerpt quality and more agent rounds.
openrouter_web_search is its own subject, with modes, engines and a way of counting
money: Web search.
- Extension
What next
Web search
Paid search: modes, engines, cost.
Agents and tools
How nodes attach to an agent with an extension link.
Templates
Substitution namespaces and the render-once rule.
Node errors
What arrives in the error branch and which codes exist.
Your own code
When an HTTP node is not enough and you need JavaScript.
Integrations: overview
Connections, secrets and who may change them.