The HTTP Requests tool turns your dashboard into a built-in API client — like a mini Postman that lives inside Virtuino Cloud. You can call any public REST API, test it live, and then have the server run it automatically (on a schedule or when a field changes) and feed the response straight into your fields and scripts.
https://httpbin.org — a request inspector that echoes back exactly what it received (great for verifying params, auth, headers and body).https://api.open-meteo.com — a free weather API (no key required) used for the two complete real-world examples.Every request you build has the same top section, regardless of the tabs you fill in:
| Field | What it does |
|---|---|
| title | A friendly name shown in the list (e.g. Athens weather). Has no effect on the call. |
| method | The HTTP verb: GET POST PUT PATCH DELETE. GET retrieves data; POST/PUT/PATCH send a body; DELETE removes. |
| url | The full endpoint, starting with http:// or https://. |
| Test | Runs the request immediately through the server and shows the live response below — without saving. |
Below the URL there are four tabs that shape the request: Params, Authorization, Headers and Body. The second top-level tab, automation, is covered in section 7.
Query parameters are the ?key=value&key2=value2 part of a URL. Instead of typing them by hand, add them as rows here — each enabled row is appended to the URL, correctly URL-encoded.
| Column | Meaning |
|---|---|
| (checkbox) | Include this row in the request. Uncheck to keep a param without sending it. |
| Key | Parameter name (e.g. latitude). |
| Value | Parameter value (e.g. 37.98). |
GET https://httpbin.org/get
Params:
| Key | Value |
|---|---|
| city | Athens |
| units | metric |
Press Test. httpbin echoes the parameters it received under args:
{
"args": {
"city": "Athens",
"units": "metric"
},
"url": "https://httpbin.org/get?city=Athens&units=metric"
}
args match what you typed, the Params tab is working. The final url shows exactly what was called.Many APIs require credentials. Choose the type and the tool builds the correct header for you. The credentials are stored with the request and sent on every (manual or automatic) run.
The default. Nothing is added. Use it for open APIs like Open-Meteo.
Adds the header Authorization: Bearer <token>. This is the most common scheme for modern APIs (OAuth2, personal access tokens, etc.).
GET https://httpbin.org/bearer
Authorization: Bearer Token → token = my-secret-123
{
"authenticated": true,
"token": "my-secret-123"
}
Adds Authorization: Basic <base64(username:password)>. The tool does the Base64 encoding for you.
GET https://httpbin.org/basic-auth/admin/s3cret
Authorization: Basic Auth → username = admin, password = s3cret
{
"authenticated": true,
"user": "admin"
}
/basic-auth/admin/s3cret tells httpbin which credentials to accept. If you type the wrong username/password in the Auth tab, you get 401 Unauthorized — try it to see the failure case.Sends a custom header of your choice, e.g. X-API-Key: <value>. Set the header name and the value. Many weather/finance APIs use this style.
GET https://httpbin.org/headers
Authorization: API Key → header name = X-API-Key, value = abc123
{
"headers": {
"Host": "httpbin.org",
"X-Api-Key": "abc123"
}
}
?apikey=abc123). In that case leave Authorization on No Auth and add the key in the Params tab instead.Custom request headers, added as key/value rows (same layout as Params). Use them for content negotiation, custom tokens, or anything the API documents. Common examples:
| Header | Typical use |
|---|---|
Accept: application/json | Ask the server to return JSON. |
User-Agent: VirtuinoCloud | Identify your client. |
X-Custom-Token: ... | Any vendor-specific header. |
GET https://httpbin.org/headers
Headers:
| Key | Value |
|---|---|
| Accept | application/json |
| X-Demo | virtuino |
{
"headers": {
"Accept": "application/json",
"X-Demo": "virtuino",
"Host": "httpbin.org"
}
}
Authorization header. Anything you can do there you could also type manually in Headers — but the Auth tab is safer and clearer.The body is the payload you send to the server. It only applies to POST, PUT and PATCH — for GET/DELETE it is ignored. Choose one of four modes:
| Mode | What is sent | Content-Type set |
|---|---|---|
| none | No body. | — |
| JSON | A raw JSON document you type. | application/json |
| form-urlencoded | Key/value pairs encoded as a=1&b=2. | application/x-www-form-urlencoded |
| raw | Any plain text (XML, CSV, etc.). | none (set your own in Headers) |
POST https://httpbin.org/post
Body → JSON:
{
"device": "pump-1",
"command": "on",
"value": 42
}
httpbin returns what it parsed under json:
{
"json": { "device": "pump-1", "command": "on", "value": 42 },
"headers": { "Content-Type": "application/json" }
}
POST https://httpbin.org/post
Body → form-urlencoded:
| Key | Value |
|---|---|
| relay | 1 |
| duration | 30 |
{
"form": { "relay": "1", "duration": "30" }
}
The Test button sends the request immediately through the Virtuino server (never from your browser — that avoids CORS problems and applies our security checks). The results panel shows:
The logs button at the bottom of the editor shows the last 5 automatic runs (polling or trigger — not tests): when, how long it took, the status code or error, and the start of the response (up to 4000 characters). It is the first place to look when a saved request does not seem to do anything.
Switch to the automation tab to make the request run by itself on the server. There are three independent cards — enable any combination with the checkbox at the top of each.
Runs the request on a fixed schedule. Set the interval in minutes (1–1440, i.e. up to 24 hours). The server executes the request every interval and — if Store output is on — saves the response to your field.
Runs the request when one of your fields meets a condition. Pick a field, a condition, and a value:
| Condition | Fires when the field value is… |
|---|---|
| greater than > | strictly above the value |
| less than < | strictly below the value |
| greater or equal ≥ | at or above the value |
| less or equal ≤ | at or below the value |
| equal == | exactly equal |
| not equal != | anything except the value |
| changed | any time the value actually changes (the value box is ignored) |
changed fires on each genuine change of value. The comparison is numeric, like in rules.changed after a server restart: the first value only sets the starting point; the next different value fires.Pick the field where the raw response is written after each run (polling or trigger):
current/temperature_2m → field weather/temperature. For calculations or conditions, use a script with the output field as its trigger input. Both are shown in the worked examples below.
Goal: fetch the current temperature, humidity and wind for Athens every 15 minutes and keep each in its own field, with history — using only the HTTP Request and a JSON Splitter.
In Console → Fields create:
weather/raw — standard (non-historical): receives the whole response.weather/temperature, weather/humidity, weather/wind — historical: one number each, with history.GET https://api.open-meteo.com/v1/forecast?latitude=37.98&longitude=23.73¤t=temperature_2m,relative_humidity_2m,wind_speed_10m
(Equivalently, put the URL up to /forecast and add latitude, longitude, current in the Params tab.) Press Test — you should get something like:
{
"latitude": 37.98,
"longitude": 23.72,
"current": {
"time": "2026-06-20T10:00",
"interval": 900,
"temperature_2m": 27.8,
"relative_humidity_2m": 41,
"wind_speed_10m": 12.6
}
}
15 minutes. Open-Meteo updates its current values every 15 minutes ("interval": 900 seconds), so polling more often only repeats the same numbers.weather/raw. Save.In the dashboard, Tools → JSON Splitter → new splitter. Source field weather/raw, leave time path empty, and add three rows:
| Path in the JSON | Field |
|---|---|
current/temperature_2m | weather/temperature |
current/relative_humidity_2m | weather/humidity |
current/wind_speed_10m | weather/wind |
That's the whole pipeline: request → weather/raw → JSON Splitter → three fields, every 15 minutes. Put the three fields on widgets, or add a rule on weather/wind to be warned of strong wind.
Use a script instead of the JSON Splitter when you need more than copying numbers: a conversion, a condition, a calculated value. Steps 1–3 stay the same.
Tools → Scripts → add script, then map the fields:
| IO | JS variable | Field | Options |
|---|---|---|---|
| IN | raw | weather/raw | trg |
| OUT | temperature | weather/temperature | — |
| OUT | humidity | weather/humidity | — |
| OUT | wind | weather/wind | — |
let data;
try {
data = JSON.parse(inputs.raw.value);
} catch (e) {
return; // not JSON yet
}
const cur = data.current || {};
if (typeof cur.temperature_2m === 'number') outputs.temperature = cur.temperature_2m;
if (typeof cur.relative_humidity_2m === 'number') outputs.humidity = cur.relative_humidity_2m;
if (typeof cur.wind_speed_10m === 'number') outputs.wind = cur.wind_speed_10m;
A value that is missing from the response is simply not written, so its field keeps its last value. Extend the code as you need — for example write wind in Beaufort instead of km/h. See the Scripts guide for everything a script can do.
| Limit | Value | Why |
|---|---|---|
| Request timeout | 10 seconds | A slow/hanging endpoint is aborted so it can't block the server. |
| Polling interval | 1 minute min · 1440 (24 h) max | You choose the cadence per request, within these bounds. |
| Cooldown | 10 s per request | If the trigger field oscillates or changes many times per second, the request still runs at most once every 10 s — triggers in between are skipped — so it can never flood the external API. |
| Stage | Limit | What happens if exceeded |
|---|---|---|
| Response download | 1 MB | The request is rejected — request only the data you need from the API. |
| Stored to a standard field | 1 MB | Matches the download cap, so any response that downloaded also fits the field. |
| Stored to a historical field | 512 characters | Anything longer is rejected — see the warning below. |
| Saved in the execution logs | 4000 characters | The stored response is truncated (the live response itself is not). |
http/https URLs are allowed, and the hostname is DNS-resolved and checked — requests to private/loopback ranges (127.x, 10.x, 192.168.x, 169.254.x, 172.16–31.x, ::1) are rejected. You cannot use this tool to reach internal infrastructure.polling enabled · trigger enabled · stores output to a field.
Open the logs of the request first — they show every automatic run and its result. Then check that (1) the relevant card's checkbox in the automation tab is on and the request is saved; (2) for Store output, a field is selected; (3) for triggers, the field really updates, the condition is met, and the value does not come from a rule or over HTTP (7b).
Only successful responses (200–299) are stored. If the API answers with an error, the field keeps its last good value — the logs show the status code and the error message.
The script's input — or the splitter's source — must be the same field chosen in Store output, and for a script that input must have trg ticked. The script's icon must be green (active and complete mapping) — see Scripts — troubleshooting.
The output field is historical. Historical fields take at most 512 characters, so a JSON response is rejected — use a standard field for the raw response.
Leave Authorization on No Auth and add the key as a row in the Params tab (e.g. apikey = ...).
Virtuino Cloud — HTTP Requests Tool