# New Version of the PurpleAir API on July 18th

**URL:** <https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251>\
**Category:** API\
**Created:** [July 14, 2022, 6:44pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251 "2022-07-14T18:44:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![PurpleAir](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/purpleair/32/176_2.png) [@PurpleAir](https://community.purpleair.com/u/PurpleAir)\
**Post date:** [July 14, 2022, 6:44pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/1 "2022-07-14T18:44:11Z")

</div>

Dear PurpleAir API Users,

We are excited to let you know that we will be releasing a new version of the PurpleAir API on July 18, 2022. This new API provides access to historic data that is now hosted on Google’s BigQuery. It is important to note this update provides **no functional changes** to our current API at [https://api.purpleair.com](https://api.purpleair.com), but rather adds new history endpoints.

**What updates will the new version have?**  
We added features that provide access to historical data. You’ll find documentation within the API site explaining how to use these new endpoints.

Before the 18th, you may test them here: [https://june2022.api.purpleair.com](https://june2022.api.purpleair.com). This preview URL will go away, so please be sure only to use it until the main URL is updated.

**What do you need to do?**  
If you use ThingSpeak for historic data, you will need to migrate your code to use the PurpleAir API instead. The ThingSpeak service will stop working in or around August 2022. We encourage you to get familiar with and switch to the new API’s history endpoints as soon as possible before ThingSpeak is no longer available.

**Rollback capability.**  
If you experience any issues with the new version, for a limited time, the previous version of the API will be available at [https://rollback.api.purpleair.com](https://rollback.api.purpleair.com).

**Look out for future announcements.**  
We are currently updating our API Terms of Service and Attribution guidelines. Please look out for an announcement in the coming weeks.

> Aug 18, 2022 Update: Access to the historical API has been restricted. You can learn more at the following article: [(Outdated) Historical API Endpoints are now Restricted](https://community.purpleair.com/t/historical-api-endpoints-are-now-restricted/1557).

---

<div class="post-metadata">

**Author:** ![Lance](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/lance/32/422_2.png) [@Lance](https://community.purpleair.com/u/Lance)\
**Post date:** [July 21, 2022, 3:26am UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/3 "2022-07-21T03:26:07Z")

</div>

My colleagues and I used the old API site to download more than 14,000 PurpleAir sites in Washington, Oregon, and California covering the years 2017-2021. (77 million hourly outdoor values and 20 million hourly indoor values). We compared them to the regulatory monitors in the three states to get a calibration factor. We found both the Plantower proprietary algorithms (CF\_1 and CF\_ATM) to be useless, reading zero an unacceptably high fraction of the time and also overestimating the actual PM2.5 by 40-90%. Instead we created our own algorithm (called ALT-CF3) available as a “conversion factor” on the PurpleAir map page and “PM2.5 alt” at the API site.

An important finding was that the PA-I and PA-II monitors had identical calibration factors, despite having different sensor models.

> **[Calibration of PurpleAir PA-I and PA-II Monitors Using Daily Mean PM 2.5...](https://pubmed.ncbi.nlm.nih.gov/35808235/)**
>
> Large quantities of real-time particle data are becoming available from low-cost particle monitors. However, it is crucial to determine the quality of these measurements. The largest network of monitors in the United States is maintained by the...

---

<div class="post-metadata">

**Author:** ![joerg](https://avatars.discourse-cdn.com/v4/letter/j/49beb7/32.png) [@joerg](https://community.purpleair.com/u/joerg)\
**Post date:** [July 21, 2022, 10:03pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/4 "2022-07-21T22:03:12Z")

</div>

That’s interesting data, thanks Lance. So if I understand that correctly and want to use the CF 3.4 values that you propose, is it correct that I would simply need to multiply the “pm2.5\_alt” value from the PurpleAir API by a factor of 1.12 to get this CF 3.4 number? Thanks!

I’ll certainly keep an eye on the differences versus nearby official records.

---

<div class="post-metadata">

**Author:** ![Lance](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/lance/32/422_2.png) [@Lance](https://community.purpleair.com/u/Lance)\
**Post date:** [July 21, 2022, 10:39pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/5 "2022-07-21T22:39:06Z")

</div>

Joerg–

You are correct.

---

<div class="post-metadata">

**Author:** ![Jasmine\_Bootman](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/jasmine_bootman/32/369_2.png) [@Jasmine\_Bootman](https://community.purpleair.com/u/Jasmine_Bootman)\
**Post date:** [July 22, 2022, 6:34pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/6 "2022-07-22T18:34:12Z")

</div>

Will this document [Using PurpleAir Data - Google Docs](https://docs.google.com/document/d/15ijz94dXJ-YAZLi9iZ_RaBwrZ4KtYeCy08goGBwnbCU/edit)  
and the FAQS be updated also?

---

<div class="post-metadata">

**Author:** ![Ethan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/ethan/32/177_2.png) [@Ethan](https://community.purpleair.com/u/Ethan)\
**Post date:** [July 22, 2022, 6:50pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/7 "2022-07-22T18:50:09Z")

</div>

Good question. All of the relevant data from this document can now be found in the community forums at the following links (all that is excluded is how to use ThingSpeak and the JSON URLs).

[https://api.purpleair.com/](https://api.purpleair.com/)

> [@Download Data with the Sensor Data Download Tool](https://community.purpleair.com/t/download-data-with-the-sensor-data-download-tool/316):
>
> This method of downloading data is no longer available. We have created a new download tool that uses the PurpleAir API. More information is available here: [PurpleAir Data Download Tool](https://community.purpleair.com/t/purpleair-data-download-tool/3787). The “Sensor data download tool” page allows users to download PurpleAir sensor data. You can read about how to access this tool [here](https://community.purpleair.com/t/download-sensor-data/100). Depending on how this page was accessed, there will be a vertical list of at least one sensor that you can download data from. Each sensor has two channels (A and B). Each chann…

> [@SD Card File Headers](https://community.purpleair.com/t/sd-card-file-headers/279):
>
> The following items written in bold are the headers of the SD card data that PurpleAir sensors log. What follows are their descriptions. UTCDateTime : The Date and time derived from the Real-Time Clock and synced with NTP where possible (in UTC). mac\_address : The Date and time derived from the Real-Time Clock and synced with NTP where possible (in UTC). firmware\_ver : Firmware version of the control board. hardware : Hardware type the control board has detected. current\_temp\_f : Current te…

> [@How to Calculate the US EPA PM2.5 AQI](https://community.purpleair.com/t/how-to-calculate-the-us-epa-pm2-5-aqi/877):
>
> The following code is used to calculate the US EPA PM2.5 AQI from a Raw PM 2.5 value. It is written in JavaScript. The US EPA PM2.5 AQI is calculated using the EPA’s breakpoints as described in this link: [AQI Breakpoints | Air Quality System | US EPA](https://aqs.epa.gov/aqsweb/documents/codetables/aqi_breakpoints.html). The AQI equation can be found on here: [https://forum.airnowtech.org/t/the-aqi-equation/169](https://forum.airnowtech.org/t/the-aqi-equation/169). var AQI = aqiFromPM(pm25value); function aqiFromPM(pm) { if (isNaN(pm)) return "-"; if (pm == undefined) return "-"; if (pm \< 0) return pm; …

The document will likely stay. We will update it so that links like these will be mentioned near the top or throughout.

---

<div class="post-metadata">

**Author:** ![ewalks](https://avatars.discourse-cdn.com/v4/letter/e/838e76/32.png) [@ewalks](https://community.purpleair.com/u/ewalks)\
**Post date:** [July 26, 2022, 5:53pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/8 "2022-07-26T17:53:29Z")

</div>

2 questions:

1. Lat, Long, and Altitude are all null when I pull them using the new API. Has anyone else has this issue? Will these fields be added soon?
2. Do you have plans to extend the timeframes for pulling historical data? It would be helpful if I could pull at least 4 days worth of real-time/2-min data.

Thanks.

---

<div class="post-metadata">

**Author:** ![eliang](https://avatars.discourse-cdn.com/v4/letter/e/85e7bf/32.png) [@eliang](https://community.purpleair.com/u/eliang)\
**Post date:** [July 26, 2022, 7:49pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/9 "2022-07-26T19:49:32Z")

</div>

I second this: is it possible to retrieve more than 3 days worth of historical data with the API? Or do we just have to manually download it ourselves?

---

<div class="post-metadata">

**Author:** ![Chloe\_CTDEEP](https://avatars.discourse-cdn.com/v4/letter/c/f19dbf/32.png) [@Chloe\_CTDEEP](https://community.purpleair.com/u/Chloe_CTDEEP)\
**Post date:** [July 26, 2022, 7:57pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/10 "2022-07-26T19:57:26Z")

</div>

The number of days of data you can retrieve at a time depends on the average you use:

Real-time: 2 days  
10 Minute : 3 days  
30 minute: 7 days  
1 hr: 14 days  
6hr: 90 days  
1 day: 1 year

---

<div class="post-metadata">

**Author:** ![Jasmine\_Bootman](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/jasmine_bootman/32/369_2.png) [@Jasmine\_Bootman](https://community.purpleair.com/u/Jasmine_Bootman)\
**Post date:** [July 27, 2022, 2:50pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/11 "2022-07-27T14:50:59Z")

</div>

I thought this was posted but am having trouble recalling where. If one was to loop, a call for real-time data, do you know if there is a limit?  
Such as 26 PurpleAir sensors, looped to call real-time data for a month period?

---

<div class="post-metadata">

**Author:** ![masoud\_ghahremanloo](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/masoud_ghahremanloo/32/895_2.png) [@masoud\_ghahremanloo](https://community.purpleair.com/u/masoud_ghahremanloo)\
**Post date:** [July 29, 2022, 5:05pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/12 "2022-07-29T17:05:24Z")

</div>

Hi, I’m using the Python example mentioned at ([Making API Calls in Other Languages](https://community.purpleair.com/t/making-api-calls-in-other-languages/181)) to download 1440 minutes-averaged historical data over the CONUS in 2021. I’m downloading historical data from all stations one by one in a for loop.  
This is the URL I’m using in function “getSensorData” to download one station:  
“[https://api.purpleair.com/v1/sensors/131075/history?start\_timestamp=1609459200&end\_timestamp=1640995199&average=1440&fields=pm2.5\_atm](https://api.purpleair.com/v1/sensors/131075/history?start_timestamp=1609459200&end_timestamp=1640995199&average=1440&fields=pm2.5_atm)”  
I ran the code and it used to download data, however, it’s now unable to get data and I get error “JSONDecodeError: Expecting value”.  
Can anyone help me please?

After the function, I use below codes to retrieve data from JSON.  
D = getSensorData(sensor\_index) # sensor\_index is 131075 here  
One\_Sensor\_Info = D.json()

The error raises in line “One\_Sensor\_Info = D.json()”

Thanks in advance,  
Masoud

---

<div class="post-metadata">

**Author:** ![Ethan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/ethan/32/177_2.png) [@Ethan](https://community.purpleair.com/u/Ethan)\
**Post date:** [July 29, 2022, 6:55pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/13 "2022-07-29T18:55:09Z")

</div>

Hi @masoud_ghahremanloo, try removing the “sensor\_index” field from your request, as that is not a valid field. It will return by default.

---

<div class="post-metadata">

**Author:** ![masoud\_ghahremanloo](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/masoud_ghahremanloo/32/895_2.png) [@masoud\_ghahremanloo](https://community.purpleair.com/u/masoud_ghahremanloo)\
**Post date:** [July 29, 2022, 7:32pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/14 "2022-07-29T19:32:57Z")

</div>

Dear Ethan, Thanks for the prompt response. There was a mistake in typing my question and I typed it again. I appreciate it if you can check it again.

---

<div class="post-metadata">

**Author:** ![Ethan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/ethan/32/177_2.png) [@Ethan](https://community.purpleair.com/u/Ethan)\
**Post date:** [July 29, 2022, 7:54pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/15 "2022-07-29T19:54:13Z")

</div>

No worries, thank you for that correction. I believe the error occurs due to the time you are trying to collect data. You are most likely receiving this status 400 error message, “10 minute average history maximum time span is three (3) days.” To display error messages, I believe you can print “D.text” to the terminal.  
​  
​If you go up a few comments, you can see one that includes the [date ranges](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/10) you can collect data for.

---

<div class="post-metadata">

**Author:** ![masoud\_ghahremanloo](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/masoud_ghahremanloo/32/895_2.png) [@masoud\_ghahremanloo](https://community.purpleair.com/u/masoud_ghahremanloo)\
**Post date:** [July 29, 2022, 8:10pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/16 "2022-07-29T20:10:23Z")

</div>

Dear Ethan. Thanks for checking.  
I’m averaging in 1440 minutes (one day) in 2021 and the I think I can collect data up to 1 year this way.  
I think the problem is with the line  
One\_Sensor\_Info = D.json()  
in the code.

---

<div class="post-metadata">

**Author:** ![masoud\_ghahremanloo](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/masoud_ghahremanloo/32/895_2.png) [@masoud\_ghahremanloo](https://community.purpleair.com/u/masoud_ghahremanloo)\
**Post date:** [July 29, 2022, 10:32pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/17 "2022-07-29T22:32:21Z")

</div>

Dear Ethan,  
When I use “report = response.text”, I can see data (copied below) in the report. However the JSON file for the request is not working when I use “One\_Sensor\_Info = response.json()” or “One\_Sensor\_Info = json.loads(response.text)” and I get the error “JSONDecodeError: Expecting ‘,’ delimiter”.  
I also realized that when I use “request” to pull data from PurpleAir servers, sometimes I get PM2.5 concentrations for that station, and sometimes not (for the same station). It seems that servers sometimes reject to send PM2.5 concentrations to users and data is empty.  
Your help is really appreciated.

Code:  
my\_api\_read\_key = \*\*\*  
my\_url = “[https://api.purpleair.com/v1/sensors/131075/history?start\_timestamp=1609459200&end\_timestamp=1640995199&average=1440&fields=pm2.5\_atm](https://api.purpleair.com/v1/sensors/131075/history?start_timestamp=1609459200&end_timestamp=1640995199&average=1440&fields=pm2.5_atm)”  
my\_headers = {‘X-API-Key’:my\_api\_read\_key}  
response = requests.get(my\_url, headers=my\_headers)

Report when using “response.text”:  
{  
“api\_version” : “V1.0.11-0.0.31”,  
“time\_stamp” : 1659125099,  
“sensor\_index” : 131075,  
“start\_timestamp” : 1609459200,  
“end\_timestamp” : 1640995199,  
“average” : 1440,  
“fields” : [“time\_stamp”,“pm2.5\_atm”],  
“data” : [  
[1637539200,0.07100000000000001],  
[1636329600,26.014499999999998],  
[1636416000,8.312],  
[1637625600,0.0985],  
[1632960000,6.6129999999999995],  
[1640563200,0.931],  
[1640649600,0.003],  
[1636502400,9.3415],  
[1640736000,0.012],  
[1637712000,3.3129999999999997],  
[1639526400,0.005],  
[1640908800,0.9864999999999999],  
[1636588800,12.782],  
[1637798400,0.11449999999999999],  
[1635552000,6.789999999999999],  
[1632873600,132.8795],  
[1639612800,1.091],  
[1636675200,0.002],  
[1635638400,11.1025],  
[1640822400,0.14300000000000002],  
[1639699200,6.1475],  
[1639180800,3.084],  
[1635724800,22.256],  
[1638316800,33.7545],  
[1639785600,1.8485],  
[1639267200,2.933],  
[1635811200,23.795499999999997],  
[1638576000,36.642],  
[1639353600,8.370000000000001],  
[1638403200,32.629],  
[1635897600,12.027000000000001],  
[1639440000,2.186],  
[1638489600,37.06],  
[1640131200,31.3755],  
[1639008000,15.281],  
[1638144000,20.4955],  
[1638662400,40.46],  
[1635984000,28.668],  
[1639872000,7.476],  
[1638230400,24.055500000000002],  
[1637366400,30.5925],  
[1640217600,23.9145],  
[1636070400,18.8625],  
[1639958400,26.6905],  
[1638748800,37.7275],  
[1636156800,29.5425],  
[1640304000,1.311],  
[1638835200,16.0155],  
[1640044800,35.442],  
[1637193600,29.832],  
[1640390400,0.739],  
[1637452800,33.583],  
[1636848000,0.637],  
[1636243200,23.899],  
[1638921600,10.093499999999999],  
[1637280000,38.045],  
[1636934400,10.901499999999999],  
[1640476800,0.14900000000000002],  
[1638057600,3.851],  
[1639094400,0.531],  
[1637971200,0.472],  
[1637020800,24.1075]

---

<div class="post-metadata">

**Author:** ![wawzat](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/wawzat/32/219_2.png) [@wawzat](https://community.purpleair.com/u/wawzat)\
**Post date:** [August 1, 2022, 8:45pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/18 "2022-08-01T20:45:24Z")

</div>

Is the Thingspeak historical endpoint deactivated already?

---

<div class="post-metadata">

**Author:** ![masoud\_ghahremanloo](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/masoud_ghahremanloo/32/895_2.png) [@masoud\_ghahremanloo](https://community.purpleair.com/u/masoud_ghahremanloo)\
**Post date:** [August 1, 2022, 10:21pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/20 "2022-08-01T22:21:25Z")

</div>

As I know, it’s been deactivated.

---

<div class="post-metadata">

**Author:** ![wawzat](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/wawzat/32/219_2.png) [@wawzat](https://community.purpleair.com/u/wawzat)\
**Post date:** [August 1, 2022, 11:18pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/21 "2022-08-01T23:18:22Z")

</div>

If true it’s unfortunate for me that they didn’t provide more time when both services would be available. A number of programs I’ve written will take time to rewrite not only due to the API change but the data is in one file now vs four.

---

<div class="post-metadata">

**Author:** ![Ethan](https://sea2.discourse-cdn.com/flex020/user_avatar/community.purpleair.com/ethan/32/177_2.png) [@Ethan](https://community.purpleair.com/u/Ethan)\
**Post date:** [August 2, 2022, 2:38pm UTC](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251/22 "2022-08-02T14:38:35Z")

</div>

No, the ThingSpeak API has not been deactivated. We do not have an exact date of when it will end, but it is expected to be sometime this month (August).

[Next page](https://community.purpleair.com/t/new-version-of-the-purpleair-api-on-july-18th/1251.md?page=2)
