PureAirDocs v1.4.2
API Reference GitHub Status

PureAir Air Quality API

REST · JSON Base URL: api.pureair.dev/v1 TLS 1.3 required EU-hosted

The PureAir Air Quality API gives your application real-time and historical atmospheric data captured directly at alpine collection stations — altitudes from 1,800 m to 4,200 m across the Alps, Pyrenees, and Carpathians. Every reading is validated against our ISO 16890-certified sensor network before it hits the wire.

This documentation covers API v1. If you are migrating from the legacy v0 REST API, see the migration guide.

NOTE — All endpoints return application/json. Timestamps are RFC 3339 in UTC. Concentrations are in µg/m³ unless otherwise noted.

Quickstart

Grab a free API key from the developer dashboard and make your first request in under a minute:

shell GET /v1/air-quality
curl -G https://api.pureair.dev/v1/air-quality \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d "peak=alpine-3000" \
  -d "metrics=pm25,pm10,o3,co2"
json 200 OK
{
  "station": "alpine-3000",
  "altitude_m": 3024,
  "sampled_at": "2026-06-11T08:14:00Z",
  "aqi": 4,
  "metrics": {
    "pm25":  { "value": 1.3,   "unit": "µg/m³" },
    "pm10":  { "value": 3.8,   "unit": "µg/m³" },
    "o3":    { "value": 68.1,  "unit": "µg/m³" },
    "co2":   { "value": 412.4, "unit": "ppm"    }
  },
  "certified": true
}

Authentication

All requests to api.pureair.dev require a Bearer token in the Authorization header. API keys are scoped and non-rotating by default; you can configure auto-rotation in the dashboard.

WARNING — Never embed your secret key in client-side code or public repositories. Use environment variables or a secrets manager. Keys exposed in public git history are automatically revoked within 10 minutes via our secret-scanner integration.

Scopes

Scope Description
read:realtime Access live sensor readings from all stations.
read:history Query archived readings up to 5 years back.
write:webhooks Register and manage webhook endpoints.
admin:keys Create, rotate, and revoke API keys (service accounts only).

API Reference

Get air quality reading

GET /v1/air-quality?peak={station_id}

Returns the latest validated reading for a given alpine station, optionally filtered to specific metrics. Readings are refreshed every 90 seconds from on-site sensors.

ParameterTypeDescription
peak* string Station ID from the stations list. Example: alpine-3000
metrics string[] Comma-separated list of metrics to include. Defaults to all available. Valid: pm25, pm10, o3, co2, no2, so2, humidity, temp.
format enum Response format. json (default) or csv.

List stations

GET /v1/stations

Returns all active alpine collection stations with their location metadata, current operational status, and sensor capabilities.

shell GET /v1/stations
curl https://api.pureair.dev/v1/stations \
  -H "Authorization: Bearer YOUR_API_KEY"
json 200 OK — truncated
{
  "stations": [
    {
      "id":         "alpine-3000",
      "name":       "Pic Blanc, Alpe d'Huez",
      "altitude_m": 3024,
      "lat":        45.0897,
      "lon":        6.0542,
      "region":     "Alps",
      "status":     "operational",
      "sensors":    ["pm25", "pm10", "o3", "co2", "no2"]
    },
    {
      "id":         "pyrenees-2900",
      "name":       "Pic du Midi de Bigorre",
      "altitude_m": 2877,
      "lat":        42.9368,
      "lon":        0.1411,
      "region":     "Pyrenees",
      "status":     "operational",
      "sensors":    ["pm25", "pm10", "o3", "co2"]
    }
    // … 14 more stations
  ],
  "total": 16
}

Batch readings

POST /v1/batch

Fetch the latest readings for multiple stations in a single request. Accepts a JSON body with a peaks array. Maximum 20 stations per call.

shell POST /v1/batch
curl -X POST https://api.pureair.dev/v1/batch \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "peaks":   ["alpine-3000", "pyrenees-2900", "carpathian-1800"],
    "metrics": ["pm25", "co2", "aqi"]
  }'

Webhooks

Subscribe to station events and receive an HTTP POST to your endpoint whenever a threshold is crossed or a sensor goes offline. Payloads are signed with HMAC-SHA256 using your webhook secret.

Event types

EventTrigger
aqi.threshold_exceeded Station AQI rises above your configured threshold.
station.offline A station has not reported for more than 10 minutes.
station.restored A previously offline station resumes reporting.
reading.certified A new ISO-certified batch reading is ready (every 6 h).

Signature verification

Every webhook delivery includes a X-PureAir-Signature header. Verify it to reject spoofed payloads:

javascript Verify HMAC-SHA256 signature
import crypto from 'crypto';

function verifySignature(rawBody, secret, header) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(header)
  );
}

FAQ

Which peaks are covered?

Version 1 covers 16 certified stations across three mountain ranges: the French and Italian Alps (alpine-*), the Pyrenees (pyrenees-*), and the Western Carpathians (carpathian-*). Expansion to the Dolomites and Tatra mountains is planned for Q3 2026. Fetch the live list via GET /v1/stations.

How real-time is the data?

Sensor readings are transmitted every 90 seconds over a dedicated low-latency satellite uplink. After transmission, data goes through automated QA (outlier rejection, cross-sensor consistency check) which typically adds 5–15 seconds of latency. The sampled_at field in the response reflects the on-sensor capture timestamp, not the delivery time.

Units and conversions

Particulate matter (pm25, pm10) is reported in µg/m³. Gases (o3, no2, so2) are in µg/m³ per WHO 2021 guidelines. CO₂ is in ppm. Temperature is in °C; humidity is 0–100 %. Pass &units=imperial to receive °F and µg/ft³.

Common errors

HTTP statusCodeMeaning
401unauthorizedMissing or invalid Bearer token.
403forbiddenToken lacks the required scope.
404station_not_foundUnknown station ID.
422invalid_metricOne or more metrics not supported by this station.
429rate_limit_exceededFree tier: 60 req/min. Paid: 1,000 req/min.
503station_offlineStation is not reporting. Try another or check /v1/stations.