Download OpenAPI specification:Download
Welcome to the Minut developer documentation. Here you will find an introduction to the Minut API, how to setup your first application, and how to subscribe to events from Minut.
To get started with the API there are two prerequisites:
Sign up here or use our app to create your account.
Instructions on how to get one are found here
Before making requests you first need to aquire an access token. For this we use OAuth2.0, which is well documented on other sites, as well as the official spec: RFC6749. The endpoints for doing the exchange are documented under Authentication.
Before we dive into the API Reference it is useful to get a brief understanding about how Minut works, what it communicates, and how it does so.
Minut runs on batteries and as such a lot of care is taken to make the batteries last as long as possible. This means that for the most time, communication channels like Wi-Fi, are turned off. It is only activated when necessary and that happens for two reasons. The first reason is regular checkins, called Heartbeats. The heartbeat is a message that Minut sends roughly once an hour to indicate to the backend that it is still alive and well. This message contains all the sensor readings since the last heartbeat, usually some diagnostics, and a check for new configuration or software updates. The other reason is when something out of the ordinary happens, for example, when the Minut detects a sudden temperature drop, an alarm, or other activity. These messages are called Events.
While heartbeats are sent regularly Minut does not expose them directly the API. Instead, and much more useful, is the sensor data they contain. The API provides endpoints to retrieve temperature, humidity, pressure, ambient light, sound, and battery data as continuous time series.
Minut is mostly about events. Events are sent when something out of the ordinary is detected, when a long-running analysis on the backend has yielded some result, or if the user performs certain actions.
There exists a broad range of events that describe user actions, activity in the home, and system information. See Events for a list. Events can be retrieved both from the API and subscribed to via Webhooks. We will explain how to subscribe to events in the next section.
Depending on the type of the event, the fields in the event varies. For instance, an event generated by a sensor value crossing a threshold will contain a reference to the threshold crossed. Whereas a tamper event will only contain a reference to which device was tampered with. Events at least contain the following fields:
{
"event_id": "string",
"created_at": "datetime",
"type": "string"
}
Most of the time they will also include either device_id
or user_id
.
When doing integrations we highly recommend either subscribing to or reading events rather than sensor data to make sure you get the most up to date information
Webhooks are a great way to react to events as they happen. Rather than implementing a mechanism where you would poll the Minut API at regular intervals, you tell the API about an endpoint that you control to which Minut can send events as they happen.
For the sake of simplifying this example, we are going to use https://webhook.site. It’s an online service that lists HTTP requests directed to it. Since they are only temporary they are not recommended for continued use. Visit the site and make note of the url.
Now we need to set up the subscription. This is done with a POST request to /webhooks
as an authenticated user. Make sure to replace $token and
$webhook-url with valid values.
curl -X POST -H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d '{"url": $webhook-url, "events": ["short_button_press"]}'\
"https://api.minut.com/v5/webhooks/"
Once this is done, you should be able to press the button on your Minut and see that the event is received in the webhook UI. Another way to test that it works is by doing this request using the webhook id you got from the previous request.
curl -X POST -H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d {} \
"https://api.minut.com/v5/webhooks/WEBHOOK_ID/ping"
From now on all events that belong to the user are forwarded to your web service. Minut will automatically retry sending the event roughly 10
times with an exponential back-off. In case all attempts fail, we will not try sending the message again and you have to implement some form of
recovery of lost messages yourselves by asking the /events
endpoint.
Minut uses Uptimerobot to measure API availability. You can check the most recent status here: https://status.minut.com
We partner with insurances, telcos, and utilities around the world to provide new types of services for end users.
For integrations, we provide enterprise APIs tailored to managing thousands of devices, SLAs and support. Feel free to reach out to Sales for more information at sales@minut.com.
Most endpoints in our API requires the user to be authenticated. For this we use OAuth2. To get started with this you'll need an OAuth client, instructions on how to get one are found here
Before making requests you first need to aquire an access token. How to get a token is well documented on other sites, as well as the official spec: RFC6749. But a quick simple guide follows here:
Make sure to replace CLIENT_ID and REDIRECT_URI with the values you got from our support.
The page will ask you to sign in with your Minut account.
Accept the prompt asking if your application should be able to access your Minut data.
Your browser will redirect to the url provided in the redirect_uri parameter, with a query parameter like so: code=randomcode
Perform this request using the code.
Use the access_token from the previous request in the Authorization header for all requests to the api:
Authorization: Bearer access_token
Done!
response_type required | string Value: "code" Must be set to "code" |
client_id required | string The client id |
redirect_uri required | string Where to redirect the user-agent after performing the request. Must match the |
scope | string Space separated list of scopes to request. |
state | string An opaque value used by the client to maintain state between the request and the callback. |
code_challenge | string A PKCE code challenge |
code_challenge_method | string Enum: "S256" "plain" Should be S256 unless your client does not support SHA256, in which case plain can be used |
An authorization code
Bad request
Unauthorized
{- "code": "string"
}
There are two ways to get a bearer token which are requried for all other endpoints.
authorization_code
refresh_token
All exchange methods will return a short-lived bearer token and a refresh token.
Set the TokenExchange
parameters required for the grant_type
used.
grant_type required | string Enum: "refresh_token" "authorization_code" "password" Grant type to exchange for access token |
redirect_uri | string Required if |
client_id required | string Client ID if not provided using HTTP Basic Auth |
client_secret required | string Client secret if not provided using HTTP Basic Auth |
code | string Authorization code is |
username | string Username if |
password | string Password if |
refresh_token | string Refresh token if |
token | string Token if |
code_verifier | string The plain text code used in the original authorization request |
response_type | string Value: "token" Should be set to token |
A bearer and refresh token token
Bad request
Unauthorized
{- "grant_type": "refresh_token",
- "redirect_uri": "string",
- "client_id": "string",
- "client_secret": "string",
- "code": "string",
- "username": "string",
- "password": "string",
- "refresh_token": "string",
- "token": "string",
- "code_verifier": "string",
- "response_type": "token"
}
{- "access_token": "string",
- "refresh_token": "string",
- "expires_in": 0,
- "token_type": "string",
- "user_id": "string"
}
Refresh token to revoke
token required | string The refresh token to revoke |
client_id required | string |
client_secret required | string |
Status of revokation
{- "token": "string",
- "client_id": "string",
- "client_secret": "string"
}
{- "revoked": true
}
Returns a list of all devices the authenticated user has access to.
A list of devices
{- "devices": [
- {
- "device_id": "string",
- "device_mac": "string",
- "device_bluetooth_address": "string",
- "owner": "string",
- "home": "string",
- "active": true,
- "offline": true,
- "first_seen_at": "2021-01-13T09:48:08Z",
- "last_heard_from_at": "2021-01-13T09:48:08Z",
- "last_heartbeat_at": "2021-01-13T09:48:08Z",
- "firmware": {
- "installed": 0,
- "wanted": 0
}, - "hardware_version": 0,
- "description": "string",
- "timezone": "string",
- "configuration": {
- "version": 0,
- "installed_on_device_at": "2021-01-13T09:48:08Z",
- "updated_at": "2021-01-13T09:48:08Z",
- "room_type": "string",
- "glassbreak_config": {
- "active_until": "string",
- "active_from": "string"
}, - "quiet_hours": {
- "enabled": true,
- "start": "string",
- "end": "string"
}, - "reactions": [
- {
- "type": "home:temperature:low",
- "notifications": [
- "string"
], - "value": 0,
- "duration_seconds": 0
}
]
}, - "ongoing_events": [
- "battery_low"
], - "battery": {
- "voltage": 0,
- "low_warning_sent_at": "2021-01-13T09:48:08Z",
- "percent": 0
}, - "location": {
- "longitude": 0,
- "latitude": 0
}, - "listening_mode": "on",
- "insights": { },
- "mould_risk_level": "LOW",
- "muted_until": "2021-01-13T09:48:08Z",
- "charge_status": "connected_charging",
- "wlan": {
- "ssid": "string",
- "bssid": "string",
- "address_ipv4": "string",
- "signal_quality": 0,
- "rssi": 0
}, - "mount_status": "unknown",
- "latest_sensor_values": {
- "temperature": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "sound": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "pressure": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "humidity": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "accelerometer_x": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}
}
}
]
}
Returns a device
device_id required | string Device ID |
A Device
User is not authorized access
The Device does not exist
{- "device_id": "string",
- "device_mac": "string",
- "device_bluetooth_address": "string",
- "owner": "string",
- "home": "string",
- "active": true,
- "offline": true,
- "first_seen_at": "2021-01-13T09:48:08Z",
- "last_heard_from_at": "2021-01-13T09:48:08Z",
- "last_heartbeat_at": "2021-01-13T09:48:08Z",
- "firmware": {
- "installed": 0,
- "wanted": 0
}, - "hardware_version": 0,
- "description": "string",
- "timezone": "string",
- "configuration": {
- "version": 0,
- "installed_on_device_at": "2021-01-13T09:48:08Z",
- "updated_at": "2021-01-13T09:48:08Z",
- "room_type": "string",
- "glassbreak_config": {
- "active_until": "string",
- "active_from": "string"
}, - "quiet_hours": {
- "enabled": true,
- "start": "string",
- "end": "string"
}, - "reactions": [
- {
- "type": "home:temperature:low",
- "notifications": [
- "string"
], - "value": 0,
- "duration_seconds": 0
}
]
}, - "ongoing_events": [
- "battery_low"
], - "battery": {
- "voltage": 0,
- "low_warning_sent_at": "2021-01-13T09:48:08Z",
- "percent": 0
}, - "location": {
- "longitude": 0,
- "latitude": 0
}, - "listening_mode": "on",
- "insights": { },
- "mould_risk_level": "LOW",
- "muted_until": "2021-01-13T09:48:08Z",
- "charge_status": "connected_charging",
- "wlan": {
- "ssid": "string",
- "bssid": "string",
- "address_ipv4": "string",
- "signal_quality": 0,
- "rssi": 0
}, - "mount_status": "unknown",
- "latest_sensor_values": {
- "temperature": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "sound": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "pressure": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "humidity": {
- "time": "2021-01-13T09:48:08Z",
- "value": 0
}, - "accelerometer_x": {
- "time": "2021-01-13T09:48:08Z",