Simple API
The Simple API uses query parameters for authentication and simple request shapes. It is intended for environments where sending custom headers is inconvenient.
Simple API access requires a Pro plan or higher.
The Simple API is disabled by default for every device.
Before calling any Simple API endpoint, open Dashboard -> Devices -> select your device -> Device Settings and enable Simple API for that device.
The device token is sent in the URL, so it can appear in logs or monitoring tools. Enable it only when needed and prefer the RESTful API for server-side integrations.
Base URL
https://app.vwire.io/external/api
Authentication
Pass your device token as the token query parameter on every request. You can copy the token from Dashboard -> Devices -> select your device -> Device Settings -> Auth Token.
Device tokens are prefixed with iot_:
iot_**********
If the per-device toggle is off, the API returns:
{
"success": false,
"error": {
"code": "SIMPLE_API_DISABLED",
"message": "The Simple API is disabled for this device. Enable it in the VWire dashboard under Device Settings."
}
}
GET /get — Read a pin
GET /external/api/get?token=TOKEN&pin=V0
| Param | Required | Description |
|---|---|---|
token | ✅ | Device auth token |
pin | ✅ | Pin name: V0-V255, D0-D255, A0-A255 |
Response:
{
"success": true,
"pin": "V0",
"value": "23.5",
"updatedAt": "2026-03-18T10:00:00.000Z"
}
value is null only when the pin exists but has no stored value yet. If the pin has never been recorded, the endpoint returns 404 PIN_NOT_FOUND.
Examples:
curl "https://app.vwire.io/external/api/get?token=iot_xxx&pin=V0"
import requests
r = requests.get(
"https://app.vwire.io/external/api/get",
params={"token": "iot_xxx", "pin": "V0"},
)
print(r.json()["value"])
HTTPClient http;
http.begin("https://app.vwire.io/external/api/get?token=iot_xxx&pin=V0");
int code = http.GET();
String body = http.getString();
GET /update — Write a pin
GET /external/api/update?token=TOKEN&pin=V0&value=1
| Param | Required | Description |
|---|---|---|
token | ✅ | Device auth token |
pin | ✅ | Pin name |
value | ✅ | Value to set (see payload limits) |
This stores the value, writes a history point, updates open dashboards in real time, and sends the command to the device immediately if it is online.
Response:
{
"success": true,
"pin": "V0",
"value": "1",
"delivered": true
}
delivered: true means the command was published to the online device immediately. false means the value was stored but could not be delivered right away.
Examples:
curl "https://app.vwire.io/external/api/update?token=iot_xxx&pin=V0&value=1"
import requests
r = requests.get(
"https://app.vwire.io/external/api/update",
params={"token": "iot_xxx", "pin": "V0", "value": "1"},
)
print(r.json()["delivered"])
String url = "https://app.vwire.io/external/api/update?token=iot_xxx&pin=V1&value=1";
http.begin(url);
http.GET();
GET /get-all — Read all pins
GET /external/api/get-all?token=TOKEN
Returns all recorded pin values for the device as a JSON object.
Response:
{
"success": true,
"deviceId": "uuid",
"pins": {
"V0": { "value": "23.5", "label": "Temperature", "updatedAt": "2026-03-18T10:00:00.000Z" },
"V1": { "value": "1", "label": "Relay", "updatedAt": "2026-03-18T09:55:00.000Z" },
"A0": { "value": "512", "label": null, "updatedAt": "2026-03-18T09:50:00.000Z" }
}
}
import requests
r = requests.get(
"https://app.vwire.io/external/api/get-all",
params={"token": "iot_xxx"},
)
pins = r.json()["pins"]
for pin, data in pins.items():
print(f"{pin} = {data['value']}")
GET /is-online — Check device status
GET /external/api/is-online?token=TOKEN
Response:
{
"success": true,
"deviceId": "uuid",
"isOnline": true,
"lastSeenAt": "2026-03-18T10:01:00.000Z",
"statusChangedAt": "2026-03-18T09:00:00.000Z"
}
POST /notify — Send a notification
POST /external/api/notify?token=TOKEN
Content-Type: application/json
Body:
{
"title": "Alert",
"message": "Temperature exceeded 30°C",
"priority": "high"
}
| Field | Type | Required | Default |
|---|---|---|---|
message | string (max 500) | ✅ | — |
title | string (max 100) | ❌ | "Device Notification" |
priority | low | normal | high | ❌ | "normal" |
Response:
{
"success": true,
"notificationId": "uuid"
}
import requests
requests.post(
"https://app.vwire.io/external/api/notify",
params={"token": "iot_xxx"},
json={"title": "Alert", "message": "Temp > 30°C", "priority": "high"},
)
POST /batch-update — Write multiple pins
POST /external/api/batch-update?token=TOKEN
Content-Type: application/json
Body:
{
"pins": [
{ "pin": "V0", "value": "23.5" },
{ "pin": "V1", "value": "1" },
{ "pin": "A0", "value": "512" }
]
}
Max 50 pins per request. Locked pins are skipped.
Response:
{
"success": true,
"updated": 3,
"results": [
{ "pin": "V0", "delivered": true },
{ "pin": "V1", "delivered": true },
{ "pin": "A0", "delivered": false }
]
}
import requests
requests.post(
"https://app.vwire.io/external/api/batch-update",
params={"token": "iot_xxx"},
json={"pins": [{"pin": "V0", "value": "23.5"}, {"pin": "V1", "value": "1"}]},
)
Errors and rate limits
All errors follow this shape:
{
"success": false,
"error": {
"code": "INVALID_TOKEN",
"message": "Invalid device token."
}
}
| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_PIN / VALUE_TOO_LARGE | Request payload is invalid or exceeds pin size limit |
| 401 | MISSING_TOKEN / INVALID_TOKEN | Auth failed |
| 403 | SIMPLE_API_DISABLED | Enable Simple API in the device settings before using token-based calls |
| 403 | PLAN_FEATURE_UNAVAILABLE | Plan upgrade required |
| 403 | PIN_LOCKED | Pin is protected by a Keypad widget lock |
| 404 | PIN_NOT_FOUND | Pin has no recorded value |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests |
Rate limit headers are included on every response:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1710756060
| Plan | Requests per minute | Requests per day |
|---|---|---|
| Free | No access | — |
| Pro | 60 | 10,000 |
| Pro Plus | 300 | 100,000 |
| Enterprise | 1,000 | Unlimited |