Skip to main content

Calibrated Data Download

Retrieve AI-calibrated PM2.5 and PM10 measurements at hourly or daily resolution. Calibrated data has been processed through AirQo's machine learning models to correct for environmental factors such as temperature and humidity, making it more suitable for analysis and reporting than raw readings.

Tier requirement

Requires a Standard Tier subscription or above.


Cohort ID filtering — coming soon

This endpoint does not yet accept cohort_id as a parameter. Filter by sites, device_names, or device_ids instead. Use the Metadata API to discover identifiers for your Cohort.

Grid ID filtering is supported via grid_ids, currently limited to a single Grid ID per request.

Endpoint​

POST https://api.airqo.net/api/v3/public/analytics/data-download?token=YOUR_SECRET_TOKEN
Content-Type: application/json

Request parameters​

ParameterTypeRequiredDescription
networkstringNoAlways "airqo" (default)
startDateTimestringYesStart timestamp (ISO 8601)
endDateTimestringYesEnd timestamp (ISO 8601)
datatypestringNo"calibrated" (default) for quality-controlled data
downloadTypestringNo"json" (default) or "csv"
frequencystringNo"hourly" or "daily" (default)
device_categorystringNoFilter by device type (e.g. "lowcost")
device_namesarrayNo*Specific device identifiers
device_idsarrayNo*Specific device IDs (as returned by the Metadata API)
sitesarrayNo*Specific Site IDs
grid_idsarrayNo*A Grid ID — currently limited to one per request
pollutantsarrayNoe.g. ["pm2_5", "pm10"]
metaDataFieldsarrayNoe.g. ["latitude", "longitude"]
weatherFieldsarrayNoe.g. ["temperature", "humidity"]
cursorstringNoPagination cursor from previous response

* Provide exactly one of sites, device_names, device_ids, or grid_ids.


Example request — hourly calibrated data​

curl -X POST "https://api.airqo.net/api/v3/public/analytics/data-download?token=YOUR_SECRET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"network": "airqo",
"datatype": "calibrated",
"downloadType": "json",
"startDateTime": "2025-01-01T00:00:00Z",
"endDateTime": "2025-01-02T00:00:00Z",
"device_category": "lowcost",
"sites": ["64f7b3e8c9d25a0013f2d456"],
"pollutants": ["pm2_5", "pm10"],
"metaDataFields": ["latitude", "longitude"],
"weatherFields": ["temperature", "humidity"],
"frequency": "hourly"
}'

Python:

import requests

token = 'YOUR_SECRET_TOKEN'

payload = {
"network": "airqo",
"datatype": "calibrated",
"downloadType": "json",
"startDateTime": "2025-01-01T00:00:00Z",
"endDateTime": "2025-01-31T23:59:59Z",
"sites": ["64f7b3e8c9d25a0013f2d456"],
"pollutants": ["pm2_5", "pm10"],
"metaDataFields": ["latitude", "longitude"],
"frequency": "hourly"
}

response = requests.post(
f"https://api.airqo.net/api/v3/public/analytics/data-download?token={token}",
json=payload
)
data = response.json()

for record in data['data']:
print(f"{record['datetime']} — {record['device_name']}: PM2.5 = {record['pm2_5']} μg/m³")

JavaScript:

const response = await fetch(
`https://api.airqo.net/api/v3/public/analytics/data-download?token=${token}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
network: 'airqo',
datatype: 'calibrated',
downloadType: 'json',
startDateTime: '2025-01-01T00:00:00Z',
endDateTime: '2025-01-31T23:59:59Z',
sites: ['64f7b3e8c9d25a0013f2d456'],
pollutants: ['pm2_5', 'pm10'],
metaDataFields: ['latitude', 'longitude'],
frequency: 'hourly'
})
}
);
const data = await response.json();

Example response​

{
"status": "success",
"message": "Data downloaded successfully",
"data": [
{
"site_name": "Kampala Road",
"device_name": "airqo_bx2847",
"datetime": "2025-01-01 10:00:00Z",
"pm2_5": 12.45,
"pm10": 15.32,
"latitude": 0.33,
"longitude": 32.56,
"temperature": 24.5,
"humidity": 65.4,
"network": "airqo",
"frequency": "hourly"
}
],
"metadata": {
"total_count": 500,
"has_more": false,
"next": null
}
}

The data array above is abbreviated to one record for readability — a real page returns up to total_count records.


Response fields​

FieldDescription
site_nameHuman-readable site name
device_nameDevice identifier
datetimeMeasurement timestamp
pm2_5Calibrated PM2.5 in μg/m³
pm10Calibrated PM10 in μg/m³
latitude / longitudeDevice location
temperatureAmbient temperature (°C)
humidityRelative humidity (%)
frequency"hourly" or "daily"
metadata.has_moreWhether more pages are available
metadata.nextCursor for the next page

Calibrated vs raw data​

AspectCalibratedRaw
Endpointdata-downloadraw-data
ProcessingML-corrected for temperature & humidityUnprocessed sensor output
ResolutionHourly or dailyMinute-level
Use caseAnalysis, dashboards, reportingAdvanced research, custom calibration
Data qualityHigher (validated)Lower (may have noise)

Pagination​

Use cursor-based pagination for large date ranges. See Pagination → for a complete walkthrough.

Rate limit

This endpoint accepts at most 10 requests per minute per client.