Receive Webhook Events
SmartThings delivers events to your app by sending POST requests to your webhook endpoint (POST /). These include device state change events from your subscriptions and lifecycle events, such as app un-installations.
Request Verification
SmartThings signs every webhook request so your app can verify that it genuinely originated from the SmartThings platform. The request includes three headers used for verification:
| Header | Description |
|---|---|
authorization | Contains an HTTP Signature with an RSA-SHA256 signature, the key ID, and the signed headers |
digest | A SHA-256 hash of the request body |
date | The timestamp of the request, used as part of the signature |
The authorization header follows the HTTP Signatures specification and looks like this:
Signature keyId="/pl/useast2/1b-75-d2-...",
signature="uzuB6YqCFF...",
headers="(request-target) digest date",
algorithm="rsa-sha256"
Verify a Request
- Retrieve the public key using the
keyIdfrom theauthorizationheader - Reconstruct the signing string from the
(request-target),digest, anddateheaders - Verify the
signatureusing the public key and the RSA-SHA256 algorithm - Verify the
digestheader matches a SHA-256 hash of the request body
Your app should reject requests that fail verification.
Retrieve the Public Key
The keyId in the authorization header is a URI path. SmartThings hosts the matching RSA public key at https://key.smartthings.com followed by that path. For example, if the header contains keyId="/pl/useast2/1b-75-d2-...", fetch the key with:
GET https://key.smartthings.com/pl/useast2/1b-75-d2-...
The response is an X.509 certificate in PEM format. Extract the RSA public key from the certificate before verifying the signature.
The keyId comes from an unverified request, so validate it before you append it to the URL. Accept only plain path segments, and reject anything containing .. or other unexpected characters.
A keyId is immutable. When SmartThings rotates its signing key, the new key gets a new keyId, so always use the keyId from each request rather than hard-coding a key. To avoid fetching the key on every request, cache it by keyId with a short time-to-live. A few hours is a good default, and you shouldn't cache a key for more than 24 hours. Don't cache keys indefinitely: if a key is ever compromised, SmartThings can only revoke it for clients that fetch it again.
Request Structure
All webhook requests share a common envelope structure:
{
"messageType": "EVENT",
"eventData": {
"installedApp": {
"installedAppId": "b4c71ab2-116d-4d79-9125-b1909fa9b0c7",
"locationId": "95efee9b-6073-4871-b5ba-de6642187293"
},
"events": [
...
]
}
}
| Field | Description |
|---|---|
messageType | The type of message (e.g. EVENT) |
eventData.installedApp | Identifies which app installation this event is for |
eventData.installedApp.installedAppId | The installed app identifier |
eventData.installedApp.locationId | The location identifier |
eventData.events | Array of one or more events |
Each event in the events array has an eventType that determines its structure.
Device Events
When a subscribed device attribute changes, SmartThings sends a device event with eventType: "DEVICE_EVENT". This occurs both when a device is controlled externally (e.g. through the SmartThings app or physically) and when your own app sends a command.
Example Request
POST / HTTP/1.1
Content-Type: application/json
Accept: application/json
Date: Thu, 12 Mar 2026 16:44:05 UTC
Digest: SHA256=fnTrY/Ng/lOhTsbdm/Rd7/mLMvIVYtViiN6K4SS4x6w=
Authorization: Signature keyId="...",signature="...",headers="(request-target) digest date",algorithm="rsa-sha256"
{
"messageType": "EVENT",
"eventData": {
"installedApp": {
"installedAppId": "b4c71ab2-116d-4d79-9125-b1909fa9b0c7",
"locationId": "95efee9b-6073-4871-b5ba-de6642187293"
},
"events": [
{
"eventTime": "2026-03-12T16:44:04Z",
"eventType": "DEVICE_EVENT",
"deviceEvent": {
"eventId": "ae79778e-1e32-11f1-84e0-75d1083bc178",
"locationId": "95efee9b-6073-4871-b5ba-de6642187293",
"deviceId": "80e26532-85d4-484c-b012-1c04f3d35f95",
"componentId": "main",
"capability": "switch",
"attribute": "switch",
"value": "on",
"valueType": "string",
"stateChange": true,
"subscriptionName": "switchHandler"
}
}
]
}
}
Device Event Fields
| Field | Description |
|---|---|
eventTime | ISO 8601 timestamp of when the event occurred |
eventType | DEVICE_EVENT for device attribute changes |
deviceEvent.eventId | Unique identifier for this event |
deviceEvent.locationId | The location the device belongs to |
deviceEvent.deviceId | The device that changed |
deviceEvent.componentId | The component on the device (e.g. main) |
deviceEvent.capability | The capability that changed (e.g. switch) |
deviceEvent.attribute | The specific attribute that changed (e.g. switch) |
deviceEvent.value | The new value (e.g. "on", "off") |
deviceEvent.valueType | The data type of the value (e.g. string) |
deviceEvent.stateChange | true if the value is different from the previous value |
deviceEvent.subscriptionName | The name you assigned when creating the subscription, allowing your app to route the event to the correct handler |
Response
Your app must respond with a 200 OK status code to acknowledge receipt:
HTTP/1.1 200 OK
If your app does not respond with a 200 status code, SmartThings may retry the delivery and may eventually disable the subscription.
Lifecycle Events
SmartThings sends a DELETE lifecycle event when a user disconnects your app from their SmartThings account, so that you can do appropriate cleanup of persisted data in your app.
Example Uninstall Request
POST / HTTP/1.1
Content-Type: application/json
Accept: application/json
Date: Thu, 12 Mar 2026 16:45:40 UTC
Digest: SHA256=4Pi2HIaWV3FPHewsjKVLuTvDCQ4SxJXMHJSWuqzWbf0=
Authorization: Signature keyId="...",signature="...",headers="(request-target) digest date",algorithm="rsa-sha256"
{
"messageType": "EVENT",
"eventData": {
"installedApp": {
"installedAppId": "b4c71ab2-116d-4d79-9125-b1909fa9b0c7",
"locationId": "95efee9b-6073-4871-b5ba-de6642187293"
},
"events": [
{
"eventTime": "2026-03-12T16:45:40Z",
"eventType": "INSTALLED_APP_LIFECYCLE_EVENT",
"installedAppLifecycleEvent": {
"eventId": "e7440a61-1e32-11f1-8a3b-538c5d7cb4a2",
"locationId": "95efee9b-6073-4871-b5ba-de6642187293",
"installedAppId": "b4c71ab2-116d-4d79-9125-b1909fa9b0c7",
"appId": "02ef84da-984e-43a6-b7cc-905c88183e9e",
"lifecycle": "DELETE",
"delete": {}
}
}
]
}
}
Lifecycle Event Fields
| Field | Description |
|---|---|
eventType | INSTALLED_APP_LIFECYCLE_EVENT for lifecycle changes |
installedAppLifecycleEvent.eventId | Unique identifier for this event |
installedAppLifecycleEvent.locationId | The location the app was installed in |
installedAppLifecycleEvent.installedAppId | The installed app that is being removed |
installedAppLifecycleEvent.appId | The registered app definition identifier |
installedAppLifecycleEvent.lifecycle | The lifecycle stage (e.g. DELETE) |
Handling Uninstall
When your app receives a DELETE lifecycle event, it should:
- Delete the stored access and refresh tokens for this
installedAppId - Remove any session data associated with the user
- Clean up any other app-specific resources tied to this installation
Respond with 200 OK:
HTTP/1.1 200 OK
Up Next
Next, learn about the second way of receiving events, SSE, or skip ahead and explore the SmartThings device model to understand how physical hardware maps to components, capabilities, and attributes. It will also cover how to retrieve a list of accessible devices within a location and query their current status in Query and List Devices.