The Sensors API bridges your ESP32 hardware and the Surqo platform. Devices push readings over HTTP, and the server automatically computes the Vapour Pressure Deficit (VPD) from air temperature and humidity using the Magnus equation before persisting the record. Every saved reading is immediately broadcast to all WebSocket clients subscribed to that farm, enabling live dashboard updates without polling. Historical data is queryable as a time series for any metric over a rolling window of up to one year, and a 24-hour stats endpoint returns per-metric min / max / avg / trend summaries.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ricardomb-tech/surqo/llms.txt
Use this file to discover all available pages before exploring further.
Ingest a sensor reading
POST /api/v1/sensors/reading — Auth required — Rate limit: 120 requests / minute
Accepts a reading from an ESP32 (or any HTTP client) and saves it to the database. If both air_temp_c and air_humidity_pct are provided, vpd_kpa is calculated automatically. When farm_id is supplied, the reading is broadcast to the WebSocket live feed for that farm.
Request body
Unique identifier of the physical device. Maximum 100 characters (e.g.
"ESP32-CAMPO-001").UUID of the farm this reading belongs to. The farm must be owned by the authenticated user. When omitted the reading is stored without a farm association and WebSocket broadcast is skipped.
Volumetric soil moisture as a percentage. Valid range:
0–100.Soil temperature in degrees Celsius. Valid range:
-10–80.Air temperature in degrees Celsius. Valid range:
-10–60. Used together with air_humidity_pct to compute vpd_kpa.Relative air humidity as a percentage. Valid range:
0–100. Used together with air_temp_c to compute vpd_kpa.UV radiation index. Valid range:
0–20.Battery voltage in millivolts (e.g.
3820).Wi-Fi signal strength in dBm (e.g.
-62).Firmware version string reported by the device.
Ingestion channel. Defaults to
"http". The system also accepts "mqtt" internally.Response 201
Returns a SensorReadingResponse object.
Unique reading identifier.
Device identifier as submitted.
Associated farm UUID, or
null if no farm was specified.Computed Vapour Pressure Deficit in kilopascals.
null if air_temp_c or air_humidity_pct were not provided.Stored soil moisture value.
Stored soil temperature.
Stored air temperature.
Stored air humidity.
Stored UV index.
Stored battery voltage.
Stored signal strength.
Stored firmware version.
Ingestion channel as persisted (always
"http" for this endpoint).ISO 8601 timestamp of when the reading was recorded.
Example
Response 201
Get time series
GET /api/v1/sensors/timeseries/{farm_id} — Auth required
Returns a list of {timestamp, value} data points for a single metric over a rolling time window. Ideal for charting historical trends.
UUID of the farm to query.
Number of hours of history to return. Range:
1–8760 (up to one year). Defaults to 24.Sensor metric to return. Defaults to
"soil_moisture_pct".Accepted values:soil_moisture_pctsoil_temp_cair_temp_cair_humidity_pctuv_indexvpd_kpa
Response 200
Returns an array of TimeseriesPoint objects in ascending chronological order.
ISO 8601 timestamp of the reading.
Metric value at that timestamp.
null if the sensor did not report this field in that reading.Response 200
Get latest reading for a device
GET /api/v1/sensors/latest/{device_id} — Auth required
Returns the most recent reading recorded for a specific device. If the reading is linked to a farm, the farm must belong to the authenticated user.
The device identifier string (e.g.
"ESP32-CAMPO-001").404 if no readings exist for the device. Returns 403 if the associated farm belongs to a different user.
Get 24h stats
GET /api/v1/sensors/stats/{farm_id} — Auth required
Returns aggregate statistics computed from the last 24 hours of sensor data for a farm. Each metric includes its minimum, maximum, average, and a directional trend comparing the first and last reading in the window.
UUID of the farm to query.
Response 200
Farm UUID as a string.
Stats window in hours (always
24).Metrics always included when data is available:
soil_moisture_pct, air_temp_c, air_humidity_pct, vpd_kpa.Response 200
If there are no sensor readings in the last 24 hours the response body is
{"error": "Sin datos en las últimas 24h"} with status 200.Live WebSocket feed
WS /api/v1/sensors/ws/live/{farm_id}
Subscribe to a real-time stream of sensor readings for a farm. The connection is authenticated via a JWT passed as a query parameter — the WebSocket protocol does not support Authorization headers during the handshake.
UUID string of the farm to subscribe to.
A valid JWT token for the authenticated user. The server validates this before accepting the connection.
Connection flow
- Client opens the WebSocket with
?token=<jwt>. - Server validates the token and verifies the farm is owned by the user.
- On successful connection, the server immediately sends the last recorded reading as an
initialmessage. - Every subsequent sensor reading ingested via
POST /api/v1/sensors/readingfor this farm is broadcast as asensor_readingmessage.
Message types
- initial
- sensor_reading
Sent once immediately after the connection is accepted. Contains the full
SensorReadingResponse payload of the most recent reading.Close codes
| Code | Meaning |
|---|---|
4001 | Authentication failed — token missing, invalid, or expired. |
4002 | Invalid farm UUID — the farm_id path parameter is not a valid UUID. |
4003 | Access denied — the farm does not belong to the authenticated user. |