• Github
  • Airthings Dashboard
  • Try the API

›GETTING STARTED

GETTING STARTED

  • Concepts
  • Data Access
  • API
  • Webhooks
  • Latest Additions

TUTORIALS

  • Node.js Setup Guide
  • Python & Flask Setup Guide
  • Receiving SMS Alerts
  • The making of a Grafana datasource
  • Integrate Airthings with Niagara 4

Getting Started with the Airthings API

Airthings API enables developers and partners to get access to the data of their devices, for use outside of the Airthings Platform.

Building apps

To be able to pull data from the Airthings cloud to your app, it needs to be registered with Airthings. Register new app. Once created, your app can:

  • List your devices
  • List your segments
  • Read your device sample's data
  • Add/register a new device

The read device data scope allows access to seeing data from the /devices endpoints. If you want to write/post to the API, the write device scope should be selected.

Authorizing an app to read my device data (OAuth2 Code Flow)

Once your app has been registered in our cloud (with Code Flow selected as Flow type), it is possible for other users to access their data through it. To allow an app to read data on your behalf, you need to authorize it. To enable this we have implemented the OAuth2 Code Flow. Oauth2 Flow for Users The user of the app should be redirected to accounts.airthings.com/authorize?client_id={appClientId}&redirect_uri={appRedirectUri} for authorization:

  • Sign in with their Airthings credentials
  • Authorize the app to read data on their behalf Once this is complete, the user is redirected from the accounts app back to the app located at the url from: redirect_uri with an authorization code. The authorization code in turn can be exchanged for an access_token on the /token endpoint.
  • Authorization URL: https://accounts.airthings.com/authorize
  • Token URL: https://accounts-api.airthings.com/v1/token

After authorize the token endpoint is to be called with a payload similar to:

{
    "grant_type": "authorization_code",
    "client_id": "b8a19a7d-64cd-4281-xxxx-3ffacc726fe3",
    "client_secret": "82bfed8b-793a-4423-xxxx-7491303354a0",
    "code": "auth-code-from-authorize",
    "redirect_uri": "https://redirect.configured.for.client"
}

Refreshing the access_token

The access-token has a short life-time (seconds can be seen in the token response expires_in). Using an expired access-token towards the API will result in an error response with status code 401, signaling a refresh is needed. When using the code flow the access-token can be refreshed by using a refresh-token. Upon refresh (and code_grant) a new refresh-token is provided. It is important to store the new refresh-token upon refresh, since this token also has a fixed life-time.

To refresh the access-token, the token endpoint: https://accounts-api.airthings.com/v1/token is called with a refresh-grant payload:

{
    "grant_type": "refresh_token",
    "client_id": "b8a19a7d-64cd-4281-xxxx-3ffacc726fe3",
    "client_secret": "82bfed8b-793a-4423-xxxx-7491303354a0",
    "refresh_token": "eyJhbGciOiJSUzI1NiJ9.eyJ....."
}

Using an expired refresh-token yields an error response with a status code 4xx.

Note: in Client Credentials Grant (below) no refresh_token is provided. Hence, there no refreshing is possible.

Authenticating a machine to read data (OAuth2 Client Credentials Grant)

Especially for machine-to-machine (m2m) authentication we have implemented Client Credentials from the OAuth2 spec. NOTE: it is not recommended to use this flow for frontend authentication to the API, only backends can maintain the integrity of a client secret. To setup a client for m2m, create a client for your app, as described above (configured for Client Credentials as Flow type). Next use the client id and client secret to request a token from the accounts-api. The scope specifies what type of operation you want to use. For the date fetching endpoints, the correct scope would be the read:device scope. For writing/posting, use the write:device scope.

  • Token URL: https://accounts-api.airthings.com/v1/token
{
    "grant_type":"client_credentials",
    "client_id":"b8a19a7d-64cd-4281-xxxx-3ffacc726fe3",
    "client_secret":"82bfed8b-793a-4423-xxxx-7491303354a0",
    "scope": ["read:device"]
}

The token from the response can be used to access the endpoints in the API until it expires. After the token is expired (time for expires_in is provided in seconds in the response) the token endpoint has to be called again. Using an expired access-token will result in an error response with status code 401.

API-Documentation

All currently available endpoints are documented on API-Docs.

Rate Limiting

Each Airthings For Business Client is by default allowed 5000 requests per hour. Users signed in through the same client all share that same quota. Since the client and subscription is owned by the user administrating it.

The current rate limit status is indicated in the response headers:

X-RateLimit-Reset: 1607336100 // The time at which the current rate limit window resets (UTC epoch seconds).
X-RateLimit-Remaining: 1000 // The number of remaining requests in the current rate limit window.
X-RateLimit-Limit: 5000 // The maximum number of requests you're granted per hour.

If a client exceeds the rate limit, the API will respond with status code: 429 and the below mentioned response body and header indicating when the sliding windows will grant the client a new request.

X-RateLimit-Retry-After: 100 // A new request can be performed after this many seconds.
{
    "error": "TOO_MANY_REQUESTS",
    "error_description": "Rate limit on API exceeded"
}

You can request increases to the API quota:

Airthings For Business Support

Postman / Insomnia

Download the api specification here for import into Postman or Insomnia.

Import collection

Right click the newly imported collection and select Edit to configure the collection for Oauth 2.0 Authorization. Getting a token for the API can either be done through Code Flow or Client Credentials Flow, select based on your use case:

  • Authorization Code Flow : Authorization for users. Multiple users will be able to login and fetch data for their accounts on airthings.
  • Client Credentials Flow : Authorization for a machine, i.e. a backend integration. Only one account will be used in the integration.

Authorization Code Flow

Configure Oauth2

The client id, secret and redirect_uri for your client needs to be added from the clients page.

Configure Oauth2

Now you should be able to get an access token that can be used by the collection, by pressing Use Token.

Client Credentials Flow

Configure OAuth2 Client Credentials Grant The client id, secret for your client needs to be added from the clients page.

Finalizing Postman setup

In the collection set the request authorization to Inherit auth from parent (or Oauth 2.0).

Configure Oauth2

Sending the requests should now succeed as long as the access token is valid (1 hour, in Code Flow: the refresh_token is then to be used to get a new access_token, in Client Credentials Flow: the client_id, client_secret is used to fetch a new token).

Code samples

Authentication - Authorization (Code Flow)
JavaScript
'use strict';
const simpleOauthModule = require('simple-oauth2');
const app = require('express')();
const port = 3000;
const createApplication = (cb) => {
const callbackUrl = 'http://localhost:3000/callback';
app.listen(port, (err) => {
if (err) return console.error(err);
console.log(`Express server listening at http://localhost:${port}`);
cb({app, callbackUrl});
});
};
createApplication(({ app, callbackUrl }) => {
const oauth2 = simpleOauthModule.create({
client: {
id: 'INSERT CLIENT_ID HERE',
secret: 'INSERT CLIENT_SECRET HERE',
},
auth: {
tokenHost: 'https://accounts.airthings.com',
tokenPath: 'https://accounts-api.airthings.com/v1/token',
authorizePath: '/authorize',
},
options: {
authorizationMethod: 'body',
}
});
// Authorization uri definition
const authorizationUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: callbackUrl,
scope: 'read:device',
});
// Initial page redirecting to Airthings
app.get('/auth', (req, res) => {
console.log(authorizationUri);
res.redirect(authorizationUri);
});
// Callback service parsing the authorization token and asking for the access token
app.get('/callback', async (req, res) => {
const code = req.query.code;
const options = {
code,
redirect_uri: callbackUrl,
};
try {
const result = await oauth2.authorizationCode.getToken(options);
const tokens = oauth2.accessToken.create(result);
return res.status(200).json(tokens);
} catch(error) {
console.error('Access Token Error', error.message);
return res.status(500).json('Authentication failed');
}
});
app.get('/', (req, res) => {
res.send('Hello<br><a href="/auth">Log in with Airthings</a>');
});
});
##### Get Devices
JavaScript
'use strict';
const simpleOauthModule = require('simple-oauth2');
const Wreck = require('@hapi/wreck');
const app = require('express')();
const port = 3000;
const createApplication = (cb) => {
const callbackUrl = 'http://localhost:3000/callback';
app.listen(port, (err) => {
if (err) return console.error(err);
console.log(`Express server listening at http://localhost:${port}`);
cb({
app,
callbackUrl,
});
});
};
const getDevices = async function (token) {
const options = {
headers: {'Authorization': token.access_token}
};
const { res, payload } = await Wreck.get('https://ext-api.airthings.com/v1/devices', options);
return JSON.parse(payload.toString());
};
createApplication(({ app, callbackUrl }) => {
const oauth2 = simpleOauthModule.create({
client: {
id: 'INSERT CLIENT_ID HERE',
secret: 'INSERT CLIENT_SECRET HERE',
},
auth: {
tokenHost: 'https://accounts.airthings.com',
tokenPath: 'https://accounts-api.airthings.com/v1/token',
authorizePath: '/authorize',
},
options: {
authorizationMethod: 'body',
}
});
// Authorization uri definition
const authorizationUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: callbackUrl,
scope: 'read:device',
});
// Initial page redirecting to Airthings
app.get('/auth', (req, res) => {
console.log(authorizationUri);
res.redirect(authorizationUri);
});
// Callback service parsing the authorization token and asking for the access token
app.get('/callback', async (req, res) => {
const code = req.query.code;
const options = {
code,
redirect_uri: callbackUrl,
};
try {
const result = await oauth2.authorizationCode.getToken(options);
const tokens = oauth2.accessToken.create(result);
const devices = await getDevices(tokens.token);
return res.status(200).json(devices);
} catch(error) {
console.error('Access Token Error', error.message);
return res.status(500).json('Authentication failed');
}
});
app.get('/', (req, res) => {
res.send('Hello<br><a href="/auth">Log in with Airthings</a>');
});
});
← Data AccessWebhooks →
  • Building apps
  • Authorizing an app to read my device data (OAuth2 Code Flow)
    • Refreshing the access_token
  • Authenticating a machine to read data (OAuth2 Client Credentials Grant)
  • API-Documentation
  • Rate Limiting
  • Postman / Insomnia
    • Authorization Code Flow
    • Client Credentials Flow
    • Finalizing Postman setup
  • Code samples
Copyright © 2021 Airthings