api-reference
REST API
Sensors

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:

ParameterTypeDescription
searchstringSearch in name, description, external_id, or provider name
sensor_typestringFilter by sensor type (e.g. buoy)
statusstringFilter by status (e.g. active)
providerstringFilter by provider slug
data_typesstringComma-separated canonical params (e.g. air_temperature_c,pm2_5_ug_per_m3). Returns sensors that collect any of these.
min_latnumberBounding box south edge (use with min_lon, max_lat, max_lon for map viewport)
min_lonnumberBounding box west edge
max_latnumberBounding box north edge
max_lonnumberBounding box east edge
latnumberCenter latitude (use with lon for radius filter)
lonnumberCenter longitude
radius_kmnumberRadius in km around center (default 50; only with lat/lon)
pagenumberPage number (default: 1)
limitnumberItems per page (default: 20)
minimalbooleanIf true, each sensor has only id, name, latitude, longitude, sensor_type (smaller payload for maps/large lists).
fieldsstringComma-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:

ParameterTypeDescription
data_formatstringcleaned (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:

ParameterTypeDescription
daysnumberLast N days (e.g. 30); computes since/until
sincestringISO datetime lower bound (optional)
untilstringISO datetime upper bound (optional)
limitnumberMax records per page (default 100, max 500)
pagenumberPage number (default 1)
data_formatstringcleaned (default) or raw — see Get Latest Reading
parameterstringComma-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=500 for 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_c to find sensors that measure temperature.
  • data_format — Use cleaned (default) for normalized measurements with consistent units, or raw for 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_c in celsius).
  • parameter — Filter readings to specific parameters: ?parameter=air_temperature_c returns 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 UUID
  • sensor_external_id — e.g. NDBC station id
  • sensor_name — display name
  • feed_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:

ToolDescription
list_sensorsList 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_servicesResolve which service backs a sensor. Arguments: sensor_id (UUID or external_id) or feed_id.
sensor_cleaned_streamFetch data for a sensor or feed. Arguments: sensor_id or feed_id, optional data_format (cleaned | raw), days, since, until, limit.
sensor_last_readingGet 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

MethodPathDescription
GET/api/v1/sensorsList sensors (filters, pagination)
GET/api/v1/sensors/typesDistinct sensor types
GET/api/v1/sensors/statusesDistinct statuses
GET/api/v1/sensors/registryRegistry list (ids, feeds, services)
GET/api/v1/sensors/:idSensor by UUID or external_id
GET/api/v1/sensors/:id/readings/latestLatest reading (measurements, timestamp, location)
POST/api/v1/sensors/:id/mcpMCP for one sensor (UUID only)
POST/api/v1/sensors/registry/mcpMCP for registry tools

All authenticated requests require the x-api-key header.