REST API - Sensors
Sensor data and management endpoints. Use these to list sensors, get details, and run MCP protocol requests against a specific sensor or the sensors registry.
Try it out
List Sensors
Get all sensors with optional filters and pagination.
Endpoint: GET /api/v1/sensors
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
search | string | Search in name, description, external_id, or provider name |
sensor_type | string | Filter by sensor type (e.g. buoy) |
status | string | Filter by status (e.g. active) |
provider | string | Filter by provider slug |
data_types | string | Comma-separated canonical params (e.g. air_temperature_c,pm2_5_ug_per_m3). Returns sensors that collect any of these. |
min_lat | number | Bounding box south edge (use with min_lon, max_lat, max_lon for map viewport) |
min_lon | number | Bounding box west edge |
max_lat | number | Bounding box north edge |
max_lon | number | Bounding box east edge |
lat | number | Center latitude (use with lon for radius filter) |
lon | number | Center longitude |
radius_km | number | Radius in km around center (default 50; only with lat/lon) |
page | number | Page number (default: 1) |
limit | number | Items per page (default: 20) |
minimal | boolean | If true, each sensor has only id, name, latitude, longitude, sensor_type (smaller payload for maps/large lists). |
fields | string | Comma-separated field names to return per sensor (e.g. id,latitude,longitude,sensor_type). Unknown keys are ignored. If both minimal and fields are set, minimal wins. |
Map / region filters: Pass either a bounding box (min_lat, min_lon, max_lat, max_lon) or a center + radius (lat, lon, optional radius_km). Only sensors with a location are returned when using these filters.
Response:
{
"sensors": [
{
"id": "uuid",
"external_id": "46108",
"name": "NDBC Station 46108",
"description": "Ocean observation station",
"sensor_type": "buoy",
"status": "active",
"data_types": ["wind_speed_ms", "air_temperature_c", "water_temperature_c", "air_pressure_hpa"],
"deployment_date": "2020-01-15",
"decommissioned_date": null,
"latitude": 37.5,
"longitude": -122.5,
"provider_id": "uuid",
"provider_name": "NOAA",
"provider_slug": "noaa",
"feed_id": "uuid",
"feed_name": "NDBC Buoys",
"connected_service": "ndbc"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"total_pages": 5
}
}Reduced payload: For map views or large result sets, use ?minimal=true or ?fields=id,latitude,longitude,sensor_type (or any comma-separated subset of the full field list). The response envelope stays the same (sensors + pagination); only the properties on each sensor item change.
Example with ?minimal=true:
{
"sensors": [
{
"id": "uuid",
"name": "NDBC Station 46108",
"latitude": 37.5,
"longitude": -122.5,
"sensor_type": "buoy"
}
],
"pagination": { "page": 1, "limit": 20, "total": 100, "total_pages": 5 }
}Example with ?fields=id,latitude,longitude,sensor_type:
{
"sensors": [
{
"id": "uuid",
"latitude": 37.5,
"longitude": -122.5,
"sensor_type": "buoy"
}
],
"pagination": { "page": 1, "limit": 20, "total": 100, "total_pages": 5 }
}Get Sensor Types
Get distinct sensor types used in the catalog.
Endpoint: GET /api/v1/sensors/types
Response: Array of strings, e.g. ["buoy", "weather_station"].
Get Sensor Statuses
Get distinct status values used in the catalog.
Endpoint: GET /api/v1/sensors/statuses
Response: Array of strings, e.g. ["active", "inactive", "maintenance"].
Sensors Registry
List sensors with registry-oriented fields: id, external_id, name, sensor_type, status, data_types, latitude, longitude, provider_slug, feed_id, connected_service. Same query parameters as List Sensors, including data_types filter and map filters: bounding box (min_lat, min_lon, max_lat, max_lon) or center + radius (lat, lon, radius_km).
Endpoint: GET /api/v1/sensors/registry
Response:
{
"sensors": [
{
"id": "uuid",
"external_id": "46108",
"name": "NDBC Station 46108",
"sensor_type": "buoy",
"status": "active",
"data_types": ["wind_speed_ms", "air_temperature_c", "water_temperature_c", "air_pressure_hpa"],
"provider_slug": "noaa",
"feed_id": "uuid",
"connected_service": "ndbc"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 100,
"total_pages": 5
}
}Get Latest Reading
Get the most recent reading from a sensor (timestamp, measurements, location).
Endpoint: GET /api/v1/sensors/:id/readings/latest
Parameters: id — sensor UUID (with dashes) or provider external id (e.g. 46108).
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
data_format | string | cleaned (default) — normalized measurements; raw — original source payload |
Response:
{
"sensor_id": "uuid",
"external_id": "46108",
"name": "NDBC Station 46108",
"service_id": "ndbc",
"reading": {
"id": "uuid",
"timestamp": "2025-02-02T12:00:00.000Z",
"measurements": [
{ "parameter": "air_temperature_c", "value": 15.3, "unit": "celsius", "unit_original": "celsius" },
{ "parameter": "wind_speed_ms", "value": 5.2, "unit": "m/s", "unit_original": "m/s" }
],
"location": { "type": "Point", "coordinates": [-122.5, 37.5] }
},
"provenance": {
"sensor_id": "uuid",
"service_id": "ndbc",
"source_id": "46108"
}
}Measurements may be an array (canonical format) or a flat object depending on source. Use data_format=raw to get the original payload from the source API.
Returns 404 if the sensor has no feed or no readings.
Get Sensor Readings (Time Series)
Get time series readings for a sensor: last N days, specific date range, or all data with pagination.
Endpoint: GET /api/v1/sensors/:id/readings
Parameters: id — sensor UUID (with dashes) or provider external id (e.g. 46108).
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
days | number | Last N days (e.g. 30); computes since/until |
since | string | ISO datetime lower bound (optional) |
until | string | ISO datetime upper bound (optional) |
limit | number | Max records per page (default 100, max 500) |
page | number | Page number (default 1) |
data_format | string | cleaned (default) or raw — see Get Latest Reading |
parameter | string | Comma-separated param names (e.g. air_temperature_c) — filter measurements to these only |
Usage examples:
- Last 30 days:
?days=30 - Date range:
?since=2025-01-01T00:00:00Z&until=2025-01-31T23:59:59Z - Raw data:
?data_format=raw - Only temperature:
?parameter=air_temperature_c - All data: no params, or
?page=1&limit=500for pagination
Response:
{
"sensor_id": "uuid",
"external_id": "46108",
"name": "NDBC Station 46108",
"readings": [
{
"id": "uuid",
"timestamp": "2025-02-01T12:00:00.000Z",
"measurements": [
{ "parameter": "air_temperature_c", "value": 15.3, "unit": "celsius", "unit_original": "celsius" }
],
"location": { "type": "Point", "coordinates": [-122.5, 37.5] }
}
],
"provenance": {
"sensor_id": "uuid",
"service_id": "ndbc",
"source_id": "46108"
},
"pagination": {
"page": 1,
"limit": 100,
"total": 250,
"total_pages": 3
}
}Returns 404 if the sensor is not found or has no feed. Returns 200 with empty readings if no data in the requested range.
Get Sensor Details
Get a single sensor by UUID or by external ID (e.g. NDBC station id).
Endpoint: GET /api/v1/sensors/:id
Parameters: id — sensor UUID (with dashes) or provider external id (e.g. 46108).
Response:
{
"id": "uuid",
"external_id": "46108",
"name": "NDBC Station 46108",
"description": "Ocean observation station",
"sensor_type": "buoy",
"status": "active",
"data_types": ["wind_speed_ms", "air_temperature_c", "water_temperature_c", "air_pressure_hpa"],
"deployment_date": "2020-01-15",
"decommissioned_date": null,
"latitude": 37.5,
"longitude": -122.5,
"provider_id": "uuid",
"provider_name": "NOAA",
"provider_slug": "noaa",
"feed_id": "uuid",
"feed_name": "NDBC Buoys",
"connected_service": "ndbc"
}Data Normalization Summary
Sensors and readings use a canonical format for cross-service comparison. See Data Normalization for full details.
data_types— Each sensor/feed lists canonical parameter IDs it collects (e.g.air_temperature_c,pm2_5_ug_per_m3). Use?data_types=air_temperature_cto find sensors that measure temperature.data_format— Usecleaned(default) for normalized measurements with consistent units, orrawfor the original source payload.- Measurements — Cleaned data uses
[{parameter, value, unit, unit_original}]so Purple Air, AirNow, and NDBC can be compared directly (e.g.air_temperature_cin celsius). parameter— Filter readings to specific parameters:?parameter=air_temperature_creturns only temperature measurements.
Sensor MCP Endpoint
Run MCP protocol (JSON-RPC 2.0) against one sensor. The API looks up the sensor’s feed and connected service, then forwards MCP messages to that service. The sensor’s identity is injected as context so tools can use sensor_external_id (e.g. NDBC station id) when arguments like station_id are omitted.
Endpoint: POST /api/v1/sensors/:id/mcp
Constraints: :id must be the sensor UUID (not external_id). Use GET /api/v1/sensors or GET /api/v1/sensors/registry to resolve UUIDs.
Headers: x-api-key, Content-Type: application/json
Body: JSON-RPC 2.0 message, e.g. initialize, tools/list, tools/call.
Context injected when calling tools via this endpoint:
sensor_id— sensor UUIDsensor_external_id— e.g. NDBC station idsensor_name— display namefeed_slug— feed slug when available
Example — initialize:
curl -X POST http://localhost:3001/api/v1/sensors/{sensor-uuid}/mcp \
-H "x-api-key: dev-key-12345" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"docs","version":"1.0.0"}}}'Example — list tools:
curl -X POST http://localhost:3001/api/v1/sensors/{sensor-uuid}/mcp \
-H "x-api-key: dev-key-12345" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'Example — call tool (e.g. NDBC latest observation):
curl -X POST http://localhost:3001/api/v1/sensors/{sensor-uuid}/mcp \
-H "x-api-key: dev-key-12345" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"ndbc.latest_observation","arguments":{}}}'When using the sensor MCP endpoint, tools backed by the sensor’s connected_service (e.g. NDBC) receive the above context; station_id can be omitted and the service may use sensor_external_id.
Interactive tester: The tester below supports both service-level and sensor-level MCP. Enter a Sensor UUID (from List Sensors or Sensors Registry) to call POST /api/v1/sensors/:id/mcp; leave Sensor ID blank to use POST /api/v1/services/:id/mcp.
MCP Protocol Tester
Protocol Flow
Sensors Registry MCP
Run MCP protocol against the sensors registry (catalog-wide tools). This endpoint does not target a single sensor; it exposes tools to list sensors, resolve connected services, and fetch cleaned streams.
Endpoint: POST /api/v1/sensors/registry/mcp
Headers: x-api-key, Content-Type: application/json
Body: JSON-RPC 2.0 message.
Tools:
| Tool | Description |
|---|---|
list_sensors | List sensors with optional filters: sensor_type, provider, status, data_types, latitude, longitude, radius_km, limit, page. Returns id, external_id, name, sensor_type, status, data_types, provider_slug, feed_id, connected_service. |
sensor_connected_services | Resolve which service backs a sensor. Arguments: sensor_id (UUID or external_id) or feed_id. |
sensor_cleaned_stream | Fetch data for a sensor or feed. Arguments: sensor_id or feed_id, optional data_format (cleaned | raw), days, since, until, limit. |
sensor_last_reading | Get the most recent reading from a sensor (timestamp, measurements, location). Arguments: sensor_id or feed_id. |
Example — list tools:
curl -X POST http://localhost:3001/api/v1/sensors/registry/mcp \
-H "x-api-key: dev-key-12345" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Example — call list_sensors:
curl -X POST http://localhost:3001/api/v1/sensors/registry/mcp \
-H "x-api-key: dev-key-12345" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_sensors","arguments":{"provider":"noaa","limit":5}}}'Example — call sensor_last_reading:
curl -X POST http://localhost:3001/api/v1/sensors/registry/mcp \
-H "x-api-key: dev-key-12345" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"sensor_last_reading","arguments":{"sensor_id":"46108"}}}'Summary
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/sensors | List sensors (filters, pagination) |
| GET | /api/v1/sensors/types | Distinct sensor types |
| GET | /api/v1/sensors/statuses | Distinct statuses |
| GET | /api/v1/sensors/registry | Registry list (ids, feeds, services) |
| GET | /api/v1/sensors/:id | Sensor by UUID or external_id |
| GET | /api/v1/sensors/:id/readings/latest | Latest reading (measurements, timestamp, location) |
| POST | /api/v1/sensors/:id/mcp | MCP for one sensor (UUID only) |
| POST | /api/v1/sensors/registry/mcp | MCP for registry tools |
All authenticated requests require the x-api-key header.