airsofia APIairsofia.info ↗
Access real-time and historical air quality data from the global Sensor.Community network. Filter by country, sensor type, or geographic area via 7 endpoints.
What is the airsofia API?
This API exposes 7 endpoints for querying real-time and historical air quality sensor data from the Sensor.Community global network, covering thousands of sensors worldwide. You can retrieve current readings filtered by geographic area using get_current_sensors_by_area, pull country-wide snapshots, filter by sensor model, or fetch a specific sensor's latest measurements. Each reading includes location coordinates, sensor metadata, and one or more sensordatavalues fields for pollutant and environmental metrics.
curl -X GET 'https://api.parse.bot/scraper/c89a4243-25eb-47a7-a92c-c6773bde0e4c/get_current_sensors_by_area?radius=10&latitude=48.8566&longitude=2.3522' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace sensor-community-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: Sensor.Community SDK — monitor air quality data globally."""
from parse_apis.sensor_community_air_quality_api import (
SensorCommunity, SensorModel, CountryCode, DataType, SensorNotFound
)
client = SensorCommunity()
# Search sensors by geographic area (Paris, 10km radius)
for reading in client.sensorreadings.by_area(latitude="48.8566", longitude="2.3522", radius="10", limit=5):
print(reading.id, reading.timestamp, reading.location.country)
# Filter by country using the CountryCode enum
for reading in client.sensorreadings.by_country(country_code=CountryCode.BG, limit=3):
print(reading.sensor.sensor_type.name, reading.location.latitude)
# Filter by sensor model
reading = client.sensorreadings.by_type(sensor_type=SensorModel.SDS011, limit=1).first()
if reading:
for dv in reading.sensordatavalues:
print(dv.value_type, dv.value)
# Drill into a specific sensor's latest readings
if reading:
sensor = client.sensor(id=reading.sensor.id)
for r in sensor.latest_readings(limit=3):
print(r.timestamp, r.sensordatavalues)
# Typed error handling for a sensor that doesn't exist
try:
for r in client.sensor(id=9999999).latest_readings(limit=1):
print(r.id)
except SensorNotFound as exc:
print(f"Sensor not found: {exc.sensor_id}")
# List archive files for historical data
archive = client.archivedirectories.list_files(year="2024", date="2024-01-15")
print(archive.url, len(archive.files))
print("exercised: sensorreadings.by_area / by_country / by_type / sensor.latest_readings / archivedirectories.list_files")
Fetches current sensor readings filtered by geographic area using a lat/lon center point and radius in kilometers. Returns an array of sensor reading objects including location, sensor metadata, and measurement values. Paginates as a single page; all matching sensors within the radius are returned in one response.
| Param | Type | Description |
|---|---|---|
| radius | string | Search radius in kilometers. |
| latitude | string | Latitude of the center point. |
| longitude | string | Longitude of the center point. |
{
"type": "object",
"fields": {
"data": "array of SensorReading objects, each containing id, timestamp, location, sensor metadata, and sensordatavalues"
},
"sample": {
"data": {
"data": [
{
"id": 29626277242,
"sensor": {
"id": 77100,
"pin": "7",
"sensor_type": {
"id": 27,
"name": "SHT31",
"manufacturer": "Sensirion AG"
}
},
"location": {
"id": 66602,
"indoor": 0,
"country": "FR",
"altitude": "42.3",
"latitude": "48.922",
"longitude": "2.414",
"exact_location": 0
},
"timestamp": "2026-06-11 03:40:57",
"sampling_rate": null,
"sensordatavalues": [
{
"id": 69051971019,
"value": "10.30",
"value_type": "temperature"
},
{
"id": 69051971020,
"value": "83.64",
"value_type": "humidity"
}
]
}
]
},
"status": "success"
}
}About the airsofia API
Current Sensor Data
Three endpoints cover live sensor snapshots. get_current_sensors_by_area accepts latitude, longitude, and radius (in kilometers) to return all sensors within that circle. get_current_sensors_by_country takes a two-letter country_code (e.g. BG, DE, RU) and returns all active sensors in that country. get_current_sensors_by_type filters the global feed by sensor model name — supported values include SDS011, BME280, BMP280, DHT22, PMS5003, and SPS30. All three return arrays of objects containing id, timestamp, location, sensor metadata, and sensordatavalues.
Single-Sensor and Map Endpoints
get_sensor_latest_readings takes a numeric sensor_id and returns recent reading objects for that specific device — useful for dashboards tracking individual nodes. get_map_overview_data returns a large global array of sensor data points and accepts a data_type parameter of either dust (particulate matter) or temp (temperature), matching the two primary measurement classes the network tracks.
Combined Filtering and Archives
get_sensors_by_multiple_filters combines country_code, sensor_type, and area parameters (latitude, longitude, radius) in a single call; at least one filter must be provided, and area filters require all three coordinate fields together. For historical data, get_archive_files accepts a required year and an optional date in YYYY-MM-DD format, returning an object with an url pointing to the archive directory and a files array listing available CSV filenames for download.
The airsofia API is a managed, monitored endpoint for airsofia.info — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when airsofia.info changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official airsofia.info API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Map real-time particulate matter readings across a city using
get_current_sensors_by_areawith a center coordinate and radius. - Compare PM2.5 and PM10 levels across countries by iterating
get_current_sensors_by_countrywith different country codes. - Track a specific community sensor over time using
get_sensor_latest_readingswith its numeric sensor ID. - Build sensor-type coverage reports by querying
get_current_sensors_by_typefor SDS011 versus PMS5003 deployments. - Populate a global air quality map layer with
get_map_overview_datausingdustortempas the data type. - Download historical CSV archives for offline analysis via
get_archive_fileswith a specific year and date folder. - Cross-filter by both country and sensor model using
get_sensors_by_multiple_filtersto narrow results for regional studies.
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does Sensor.Community have an official developer API?+
What does `sensordatavalues` contain in the response objects?+
sensordatavalues array where each entry represents one measured quantity — for example P1 and P2 for particulate matter from a dust sensor, or temperature and humidity from a BME280. The fields present depend on the sensor model attached to that node.Can I retrieve sensor readings at a specific historical timestamp rather than from archive files?+
get_archive_files, but does not support querying by arbitrary historical timestamp. You can fork this API on Parse and revise it to add an endpoint that queries a specific date-range from the archive data.Does `get_map_overview_data` cover all sensor measurement types?+
data_type parameter accepts only dust (particulate matter) and temp (temperature). Other sensor value types such as humidity, pressure, or noise are not exposed through this endpoint. You can fork the API on Parse and revise it to add an endpoint covering additional measurement categories.Are there any limitations on geographic area queries?+
get_current_sensors_by_area or the area filter in get_sensors_by_multiple_filters, all three parameters — latitude, longitude, and radius — must be provided together; omitting any one of them will not produce a valid area filter. The radius unit is kilometers, and very large radii may return a significant number of sensor objects depending on network density in that region.