Webhooks
Subscribe to incoming events with webhooks.
A webhook is an API concept that allows manufacturer's Web APIs to send realtime updates using regular HTTP requests.
Because Homey connects to the internet through a router, your app is not publicly accessible from the internet. We provide a webhook-forwarding service to route all incoming webhooks to the right Homey.

Let's say there is a Web API that sends a webhook when the user has turned on a light bulb. The webhook HTTP request might look like this:
POST /webhook/56db7fb12dcf75604ea7977d HTTP/1.1
Host: webhooks.athom.com
Content-Type: application/json; charset=utf-8
{
"device_id": "aaabbbccc",
"turned_on": true
}
First, you need a unique Webhook URL to provide to the manufacturer's Web API. Sometimes this can be configured in a manufacturer-owned developer portal, other times this URL can be registered by making an API call.
Go to https://tools.developer.homey.app/webhooks and select
New Webhook
. Copy the ID & Secret to your app's /env.json
file as WEBHOOK_ID
and WEBHOOK_SECRET
.{
"WEBHOOK_ID": "56db7fb12dcf75604ea7977d",
"WEBHOOK_SECRET": "2uhf83h83h4gg34..."
}
Secondly, in your app you you need to register a webhook listener that subscribes to this webhook.
/app.js
const Homey = require('homey');
class App extends Homey.App {
async onInit() {
const id = Homey.env.WEBHOOK_ID; // "56db7fb12dcf75604ea7977d"
const secret = Homey.env.WEBHOOK_SECRET; // "2uhf83h83h4gg34..."
const data = {
// Provide unique properties for this Homey here
deviceId: 'aaabbbccc',
};
const myWebhook = await this.homey.cloud.createWebhook(id, secret, data);
myWebhook.on('message', args => {
this.log('Got a webhook message!');
this.log('headers:', args.headers);
this.log('query:', args.query);
this.log('body:', args.body);
});
}
}
module.exports = App;
But how does the webhook service know that only this Homey may receive the webhook? There are three options, this is depending on how you register webhooks with the manufacturer's Web API.
If the manufacturer's Web API allows you to dynamically register a webhook, for example by posting your webhook URL to an endpoint (
POST https://myapi.com/webhook
), you can attach Homey ID as query parameter homey
to the webhook./app.js
const Homey = require('homey');
const fetch = require('node-fetch');
class App extends Homey.App {
async onInit() {
const homeyId = await this.homey.cloud.getHomeyId();
const webhookUrl = `https://webhooks.athom.com/webhook/${Homey.env.WEBHOOK_ID}?homey=${homeyId}`;
await fetch('https://myapi.com/webhook', {
method: 'POST',
headers: {'Content-Type': 'application/json'}
body: JSON.stringify({ url: webhookUrl }),
});
}
}
module.exports = App;
Homey's webhook forwarding service understands that webhooks with a
homey
query parameter should be forwarded to that Homey.When using query parameters, the
data
property is not required when registering your webhook using the this.homey.cloud.createWebhook()
function.If the manufacturer's Web API requires you to specify the webhook URL beforehand, for example in their developer portal, then you can use the key path option when creating your webhook.
The key path describes which property from the webhook request contains the value that uniquely identifies a Homey. For example:
headers['X-Device-Id']
, note that these properties are case-sensitive. You can use body
, headers
and query
in your Webhook key path filter.A key path is an ECMAScript expression consisting only of identifiers (
myVal
), member accesses (foo.bar
) and key lookup with literal values (arr[0]
obj['str-value'].bar.baz
).Your key path has to match an incoming webhook against the
data
object provided in this.homey.cloud.createWebhook(id, secret, data)
. For example, an object with { $key: "aaabbbccc" }
has to match the value aaabbbccc
in the data
object.It is also possible to define the keypath as an array, for example:
{ $keys: ["aaa", "bbb"] }
then the value in the key path either has to match value aaa
or bbb
.The key path will be checked for each Homey that is registered to this webhook. All Homeys with matching data will receive the webhook in the
webhook.on('message', ...)
listener.Let's use
headers['X-Device-Id']
from the example above, and define $key
as an array in the data
object, as follows:/app.js
const Homey = require('homey');
class App extends Homey.App {
async onInit() {
const id = Homey.env.WEBHOOK_ID; // "56db7fb12dcf75604ea7977d"
const secret = Homey.env.WEBHOOK_SECRET; // "2uhf83h83h4gg34..."
const data = {
// Provide unique properties for this Homey here
$keys: ["aaa", "bbb"],
};
const myWebhook = await this.homey.cloud.createWebhook(id, secret, data);
myWebhook.on('message', args => {
this.log('Got a webhook message!');
this.log('headers:', args.headers);
this.log('query:', args.query);
this.log('body:', args.body);
});
}
}
module.exports = App;
The webhook HTTP request might look like this:
POST /webhook/56db7fb12dcf75604ea7977d HTTP/1.1
X-Device-Id: aaa
Host: webhooks.athom.com
Content-Type: application/json; charset=utf-8
{
"turned_on": true
}
Homey's webhook service will match your webhook based on
headers['X-Device-Id']
with value aaa
(or bbb
) and forward this to that Homey. If the webhook service received value ccc
it will not be forwarded.Using the same
data
object provided in this.homey.cloud.createWebhook(id, secret, data)
as example 1, you can also define your key path in the body of your webhook HTTP request.The webhook HTTP request might look like this:
POST /webhook/56db7fb12dcf75604ea7977d HTTP/1.1
X-Device-Id: aaa
Host: webhooks.athom.com
Content-Type: application/json; charset=utf-8