Push air-quality readings from your devices to MyAQI over HTTP. We ingest them into our Apache Kafka pipeline and return enriched, hyperlocal data. We can also build a custom adapter to your own format, provided it carries the mandatory fields.
⬇ Download the API spec (Markdown)Every request must carry a per-device API token issued by MyAQI during onboarding. Send it as a Bearer token in the Authorization header:
imei.Authorization header over HTTPS — never exposed in URLs or logs.?apitoken=<apitoken> on a GET. Discouraged (tokens in URLs can leak into logs/proxies); HTTPS only.401 Unauthorized. Token not matching the payload imei → 403 Forbidden.| Method | URL | Body | Use |
|---|---|---|---|
| POST preferred | https://devices.myaqi.org/readings | JSON | New integrations; single or batch |
| GET supported | http(s)://devices.myaqi.org/readings?… | query params | Simple / legacy devices; one reading |
Success: 200 OK / 202 Accepted. Errors: 401 bad/missing token, 403 token/imei mismatch, 400 malformed or missing mandatory field.
| Field | Type | Unit | Req. | Notes |
|---|---|---|---|---|
imei | string | — | Yes | Device id (<=30 chars); is a unique id for each device. |
lat | number | degrees | Yes | Latitude, e.g. 18.55348. |
lon | number | degrees | Yes | Longitude, e.g. 73.807503. |
timestamp | string | ISO 8601 | Yes | YYYY-MM-DDThh:mm:ss.sssZ (UTC, ms). |
pm1 | number | µg/m³ | No | PM1.0. |
pm25 | number | µg/m³ | No | PM2.5. |
pm10 | number | µg/m³ | No | PM10. |
so2 | number | µg/m³ | No | Sulphur dioxide. |
no2 | number | µg/m³ | No | Nitrogen dioxide (NOx accepted in lieu). |
co | number | ppm | No | Carbon monoxide. |
co2 | number | ppm | No | Carbon dioxide. |
hcho | number | µg/m³ | No | Formaldehyde. |
temp | number | °C | No | Temperature (Celsius). |
humid | number | g/m³ | No | Humidity. |
alt | number | m | No | Altitude (AGL). |
rssi_4g | number | dBm | No | 4G signal; negative (e.g. -75). |
rssi_5g | number | dBm | No | 5G signal; negative. |
bat | number | % | No | Battery level, 0–100. |
Measurement values are JSON numbers (e.g. 33.0, not "33.0"); only imei and timestamp are strings. Optional fields may be omitted (preferred) or sent as null — never as empty strings. New fields may be added over time; unknown fields are ignored.
To conserve battery, cache readings and upload several at once (e.g. every 5–15 min). Send identity once and an array of time-stamped readings.
imei required at top level. lat/lon once at top level (stationary device) or per reading. Each readings element needs a timestamp.
For simple or legacy devices. Prefer HTTPS; prefer the Authorization header over the apitoken query parameter.
Omit optional parameters entirely (don’t send empty so2=). Colons in the timestamp are percent-encoded (%3A) in a raw URL.
Authorization: Bearer <apitoken> preferred.imei, lat, lon, timestamp (batch: timestamp per reading; identity at top level).Z.null; never empty strings.rssi_4g/rssi_5g negative.POST /readings returns one of these HTTP status codes. Always read the status code and the JSON status field; for a batch, also read the per-item results array.
| HTTP | status | Meaning |
|---|---|---|
| 200 | success | Full success. A single reading was saved, or every reading in a batch was saved. |
| 202 | partial | Partial batch. Some readings were saved and some failed — inspect results to see which. |
| 400 | error | Request rejected: missing/invalid fields, bad timestamp, empty readings array, more than 50 readings, non-JSON body, or every reading in a batch failed validation. Nothing is saved. |
| 401 | error | The Authorization: Bearer token is missing or not valid. |
| 500 | error | The server failed while saving. For a batch, returned only when nothing was saved and the failure was a server error. |
Success — 200
Failure — 400 (a required field is missing)
Every item carries its index, a per-item status, and the saved record under data (stored field names such as pm25conc). Two readings shown; data abbreviated.
Good readings are saved; each failed reading returns its own message and the original data it was sent, so you can fix and resend only that one. Here reading index 1 was missing its timestamp.
A batch may contain at most 50 readings. Over the limit the whole request is rejected and nothing is saved.
202 partial, re-send only the items whose per-item status is error (their original payload is echoed back under data). On 400 or 500, nothing was saved — retry the whole request after fixing the issue. On 401, refresh or re-issue the token; do not retry blindly.