RESTful API
The RESTful API uses header-based authentication and resource-oriented URLs. Use it for backend jobs, services, and production-grade integrations.
Plan requirement
RESTful API access requires a Pro plan or higher.
Base URL
https://app.vwire.io/external/api/v1
Authentication
Create a User API Key in Dashboard -> Account -> API Keys -> New API Key.
Use that key on every request through the X-API-Key header:
X-API-Key: vwk_7f3a1c9e2b844d6fa913c5e28f01b774
User API keys are prefixed with vwk_.
GET /devices — List all devices
GET /external/api/v1/devices
X-API-Key: vwk_xxx
| Query param | Type | Description |
|---|---|---|
limit | number | Max results (default: 50, max: 100) |
offset | number | Pagination offset (default: 0) |
online | true | false | Filter by online status |
Response:
{
"success": true,
"data": [
{
"id": "uuid",
"name": "Greenhouse Sensor",
"description": null,
"hardwareType": "ESP32",
"isOnline": true,
"lastSeenAt": "2026-03-18T10:00:00.000Z",
"createdAt": "2026-01-01T00:00:00.000Z"
}
],
"meta": { "total": 5, "limit": 50, "offset": 0 }
}
GET /devices/:id — Get device details
GET /external/api/v1/devices/{deviceId}
X-API-Key: vwk_xxx
Response:
{
"success": true,
"data": {
"id": "uuid",
"name": "Greenhouse Sensor",
"description": null,
"hardwareType": "ESP32",
"isOnline": true,
"lastSeenAt": "2026-03-18T10:00:00.000Z",
"createdAt": "2026-01-01T00:00:00.000Z"
}
}
GET /devices/:id/pins — Get all pins
GET /external/api/v1/devices/{deviceId}/pins
X-API-Key: vwk_xxx
Response:
{
"success": true,
"data": [
{ "pin": "V0", "value": "23.5", "label": "Temperature", "updatedAt": "2026-03-18T10:00:00.000Z" },
{ "pin": "V1", "value": "1", "label": "Relay", "updatedAt": "2026-03-18T09:55:00.000Z" }
]
}
GET /devices/:id/pins/:pin — Get a single pin
GET /external/api/v1/devices/{deviceId}/pins/V0
X-API-Key: vwk_xxx
Response:
{
"success": true,
"data": {
"pin": "V0",
"value": "23.5",
"label": "Temperature",
"updatedAt": "2026-03-18T10:00:00.000Z"
}
}
PUT /devices/:id/pins/:pin — Set a pin value
PUT /external/api/v1/devices/{deviceId}/pins/V0
X-API-Key: vwk_xxx
Content-Type: application/json
{ "value": "25.0" }
Response:
{
"success": true,
"data": {
"pin": "V0",
"value": "25.0",
"delivered": true,
"updatedAt": "2026-03-18T10:05:00.000Z"
}
}
PATCH /devices/:id/pins — Batch update pins
PATCH /external/api/v1/devices/{deviceId}/pins
X-API-Key: vwk_xxx
Content-Type: application/json
{
"pins": [
{ "pin": "V0", "value": "25.0" },
{ "pin": "V1", "value": "0" }
]
}
Max 50 pins per request. Protected pins are skipped and returned with delivered: false.
Response:
{
"success": true,
"data": {
"updated": 2,
"results": [
{ "pin": "V0", "delivered": true },
{ "pin": "V1", "delivered": true }
]
}
}
GET /devices/:id/status — Device status
GET /external/api/v1/devices/{deviceId}/status
X-API-Key: vwk_xxx
Response:
{
"success": true,
"data": {
"deviceId": "uuid",
"isOnline": true,
"lastSeenAt": "2026-03-18T10:00:00.000Z",
"hardwareType": "ESP32",
"firmwareVersion": "1.2.0",
"ipAddress": "192.168.1.100"
}
}
GET /devices/:id/history/:pin — Pin history
GET /external/api/v1/devices/{deviceId}/history/V0
X-API-Key: vwk_xxx
| Query param | Description |
|---|---|
from | Start date in ISO 8601 format |
to | End date in ISO 8601 format |
limit | Max data points (default: 100, max: 1000) |
Response:
{
"success": true,
"data": [
{ "value": "23.5", "timestamp": "2026-03-18T10:00:00.000Z" },
{ "value": "22.8", "timestamp": "2026-03-18T09:55:00.000Z" }
],
"meta": { "count": 2, "pin": "V0" }
}
POST /devices/:id/notify — Send notification
POST /external/api/v1/devices/{deviceId}/notify
X-API-Key: vwk_xxx
Content-Type: application/json
{
"title": "Alert",
"message": "Temperature exceeded 30°C",
"priority": "high"
}
Response:
{
"success": true,
"data": { "notificationId": "uuid" }
}
Errors and rate limits
All errors follow this shape:
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid or expired API key."
}
}
| HTTP | Code | Meaning |
|---|---|---|
| 400 | INVALID_PIN / VALUE_TOO_LONG | Request payload is invalid |
| 401 | MISSING_API_KEY / INVALID_API_KEY | Invalid API key |
| 403 | PLAN_FEATURE_UNAVAILABLE | Plan upgrade required |
| 403 | PIN_LOCKED | Pin is protected by a Keypad widget lock |
| 404 | DEVICE_NOT_FOUND | Device not found or not owned by the API key owner |
| 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 |
Example
const deviceId = "your-device-uuid";
const apiKey = "vwk_your_api_key";
await fetch(`https://app.vwire.io/external/api/v1/devices/${deviceId}/pins/V0`, {
method: "PUT",
headers: {
"X-API-Key": apiKey,
"Content-Type": "application/json"
},
body: JSON.stringify({ value: "25.0" })
});