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.

Entry
HTTP Request
Answer
Exit
  • Execute + Data
The usual shape: the entry supplies data, the request goes out, a template parses the answer.

What you configure

FieldValuesNote
MethodGET, POST, PUT, PATCH, DELETE, HEADGET and HEAD send no body, whatever sits in Body
URLhttp/httpstemplated
HeadersJSON objectthe whole field is templated, not just the values
Query ParametersJSON objectnumbers and booleans are stringified for you
Body Typenone · json · text · formform is application/x-www-form-urlencoded, written as a JSON object
Bodystringtemplated; for json it must be valid JSON after substitution
Auth Typenone · bearer · basic · custom headerfills the Authorization header for you
Timeout1…120 seconds, 30 by defaulta plan may lower the ceiling, never raise it
Max Response Bytes1 KiB…10 MB, 1 MB by defaulta longer response is truncated
Follow Redirectsonevery hop is re-checked
Parse JSON Responseonthe body is decoded only if the server declared JSON
Fail on 4xx/5xxonturn 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 SettingsSecrets, 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.

FieldWhat is inside
status_codethe response code as a number
oktrue for 2xx
bodyparsed JSON when the server sent JSON and parsing is on; otherwise a string
textthe raw response text, always
headersresponse headers
urlthe final address after every redirect
elapsed_msround-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.

HTTP Request
Answer
Service unavailable
Exit
  • Execute + Data
The error and success outputs exclude each other: exactly one fires, so both branches may safely meet at one exit.

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

Fetch WebpageT

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

websearchopenrouter_web_search
How it attachesagent tool onlyboth a graph step and an agent tool
SourceDuckDuckGosearch on OpenRouter's side, together with a model call
What it returnstitle, short snippet, linkthe model's answer plus sources with text excerpts
Pricefreecredits per search
When to take it"find me a link", then fetch_webpage reads itwhen 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.

Web SearchT
AI Agent
Fetch WebpageT
  • Extension
The free pair: the agent searches and immediately reads what it found. Both attach with an extension link.

What next