Webhooks
Webhooks are the recommended way to react to what happens in a home. Instead of polling the API on a timer, you register an HTTPS endpoint that you control and Minut sends an HTTP POST to it as each event is generated. This fits the way Minut works — devices only talk to the backend periodically (see Architecture), so there is nothing to gain from polling, and a webhook delivers the event as soon as the backend has it.
This page covers registering, verifying and managing user webhooks (the /webhooks endpoints). Every request needs a valid access token — see Authentication for Users.
Register a webhook
POST /webhooks with the URL you want events delivered to and the list of events you care about:
curl --request POST 'https://api.minut.com/v8/webhooks' \
--header 'Authorization: Bearer ACCESS_TOKEN' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://example.com/minut/webhook",
"events": ["disturbance_first_notice", "disturbance_ended"],
"token": "a-secret-you-choose"
}'
url— must be a publicly reachable HTTPS endpoint.events— the event types to subscribe to. See the Events Reference for the full list. Pass["*"]to receive every event type. Note that*must be the only element in the array — combining it with named event types is rejected with400 wildcard events can only be used with a single event.token(optional) — an arbitrary string you choose. Minut sends it back on every delivery (see Verifying deliveries), so you can confirm a request really came from your webhook.
The response is the created webhook:
{
"hook_id": "6628f1a2b167b70039f80800",
"created_at": "2026-05-29T10:00:00.000Z",
"url": "https://example.com/minut/webhook",
"events": ["disturbance_first_notice", "disturbance_ended"],
"token": true,
"hook_secret": "a3f1c8d2e9b047561234abcd5678ef901234abcd"
}
hook_secret is returned only in this create response — it is never included again when you list webhooks. Store it now; you need it to verify the HMAC signature on incoming deliveries.
List your webhooks
GET /webhooks returns every webhook registered for the authenticated user:
curl --request GET 'https://api.minut.com/v8/webhooks' \
--header 'Authorization: Bearer ACCESS_TOKEN'
{
"hooks": [
{
"hook_id": "6628f1a2b167b70039f80800",
"created_at": "2026-05-29T10:00:00.000Z",
"url": "https://example.com/minut/webhook",
"events": ["disturbance_first_notice", "disturbance_ended"],
"token": true
}
]
}
Delete a webhook
DELETE /webhooks/{hook_id} stops deliveries and removes the webhook:
curl --request DELETE 'https://api.minut.com/v8/webhooks/HOOK_ID' \
--header 'Authorization: Bearer ACCESS_TOKEN'
Send a test event
POST /webhooks/{hook_id}/ping triggers a ping delivery to the webhook's URL, so you can confirm your endpoint is reachable and your verification logic works without waiting for a real event:
curl --request POST 'https://api.minut.com/v8/webhooks/HOOK_ID/ping' \
--header 'Authorization: Bearer ACCESS_TOKEN'
At the moment the ping is always sent to your first registered webhook, regardless of the hook_id in the path. If you have several webhooks, a ping isn't a reliable way to test a specific one — it's most useful when you have a single webhook registered.
What Minut sends to your endpoint
For each event, Minut makes an HTTP POST to your url with these headers:
| Header | Value |
|---|---|
Content-Type | application/json; charset=utf-8 |
User-Agent | minut-webhook-service |
Authorization | the raw token you set when registering, sent verbatim without a Bearer prefix (absent if you didn't set one) |
and a JSON body shaped like this:
{
"hook_id": "6628f1a2b167b70039f80800",
"hook_token": "a-secret-you-choose",
"event": {
"id": "5ffffeecb167b70039f8076f",
"type": "disturbance_first_notice",
"user_id": "5ffff21db167b70039f806f8",
"created_at": "2026-05-29T10:05:00.708Z",
"home_id": "5ffff22ab167b70039f806fe"
},
"hook_digest": "3a7bdb1f...hex"
}
The event object delivered by webhooks is a reduced representation — not the same shape as the events endpoints. id, type, created_at, and user_id are always present; home_id is additionally included for home-scoped events, and sensor-related events also carry device_id, sensor_value, and sensor_threshold. Note in particular that the identifier is id (the events endpoints use event_id), and fields like text_params or actions are not included. See the Events Reference for which fields accompany each event type.
Verifying deliveries
Your endpoint is public, so verify that a delivery actually came from Minut before acting on it. There are two independent checks:
- The token. Compare the
Authorizationheader (and/orhook_tokenin the body) against thetokenyou registered. If it doesn't match, reject the request. - The HMAC signature.
hook_digestis an HMAC-SHA256, hex-encoded, computed over the JSON-serializedeventobject using yourhook_secretas the key. Recompute it and compare:
import { createHmac, timingSafeEqual } from 'crypto'
function isFromMinut(body, hookSecret) {
const expected = createHmac('sha256', hookSecret)
.update(JSON.stringify(body.event))
.digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(body.hook_digest ?? '')
return a.length === b.length && timingSafeEqual(a, b)
}
Responding and delivery semantics
- Respond quickly with a
2xxstatus. Do any heavy processing asynchronously — Minut applies a short timeout to the request, and a slow endpoint will be treated as a failed delivery. - Webhook delivery is best-effort (at-most-once). A single delivery is attempted per event with no retry queue, so if your endpoint is down, returns a non-
2xx, or times out, that event is not redelivered. If you need to be sure you haven't missed anything, periodically reconcile against Fetching Events. - When you reconcile, you may re-encounter an event you already received via webhook — deduplicate on the event
idso reprocessing is harmless.
Good to know
- Prefer subscribing to the specific events you need over
["*"]; it keeps the traffic to your endpoint relevant and easier to reason about. - Use a fresh, hard-to-guess
tokenper webhook, and keep yourhook_secretserver-side. - For organization-level integrations that manage many homes, see the organization webhook endpoints in the API Reference.