PureAir Air Quality API
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.
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:
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"
{
"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.
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
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.
| Parameter | Type | Description |
|---|---|---|
| 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
Returns all active alpine collection stations with their location metadata, current operational status, and sensor capabilities.
curl https://api.pureair.dev/v1/stations \ -H "Authorization: Bearer YOUR_API_KEY"
{
"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
Fetch the latest readings for multiple stations in a single request. Accepts a JSON body with a peaks array. Maximum 20 stations per call.
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
| Event | Trigger |
|---|---|
| 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:
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 status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing or invalid Bearer token. |
| 403 | forbidden | Token lacks the required scope. |
| 404 | station_not_found | Unknown station ID. |
| 422 | invalid_metric | One or more metrics not supported by this station. |
| 429 | rate_limit_exceeded | Free tier: 60 req/min. Paid: 1,000 req/min. |
| 503 | station_offline | Station is not reporting. Try another or check /v1/stations. |