With some smart home platforms or devices, LOQED has no direct integration. If you are an advanced user, you can develop your integration by using the LOQED API. Be sure to read our article "Advanced users: Available APIs" first.
When the door is opened/locked, call a URL (outgoing webhook)
When the lock’s status changes (open, unlock, lock) and for other information (battery percentage, online status), the LOQED Bridge can call (POST data to) a URL. Below you can find which data is POSTed as JSON to this URL. You can also add URL's GET parameters by setting the JSON key between "[" and "]". For example: https://your.server.nl/script?yourstate=[requested_state]. You can also choose for which changes a webhook call should be triggered (e.g., you can choose to only call a URL when the door is locked).
The following JSON keys are always sent:
mac_wifi: contains the Wi-Fi MAC address of the bridge. This helps to identify the bridge. The multicast DNS name of the bridge contains this address as well.
mac_ble: contains the Bluetooth MAC address of the bridge.
Reached state
After the motor stopped running, the below JSON keys are sent for the triggers trigger_state_changed_open, trigger_state_changed_latch, trigger_state_changed_night_lock, trigger_state_changed_unknown:
requested_state
OPEN
DAY_LOCK
NIGHT_LOCK
UNKNOWN
event_type
STATE_CHANGED_OPEN (requested_state = OPEN)
STATE_CHANGED_LATCH (requested_state = DAY_LOCK)
STATE_CHANGED_NIGHT_LOCK (requested_state = NIGHT_LOCK)
STATE_CHANGED_UNKNOWN (requested_state = UNKNOWN)
MOTOR_STALL (requested_state = UNKNOWN)
STATE_CHANGED_OPEN_REMOTE (requested_state = OPEN)
STATE_CHANGED_LATCH_REMOTE (requested_state = DAY_LOCK)
STATE_CHANGED_NIGHT_LOCK_REMOTE (requested_state = NIGHT_LOCK)
GO_TO_STATE_TOUCH_TO_LOCK (requested_state = NIGHT_LOCK)
key_local_id (null if e.g. manual opening by knob or pressing button). This contains the KeyID that changed the lock's state.
Going to a state
When the lock is going to a new position (it might not reach the position if the batteries are almost empty, for example) the below JSON keys are sent for the triggers trigger_state_goto_open, trigger_state_goto_latch, trigger_state_goto_night_lock:
go_to_state
OPEN
DAY_LOCK
NIGHT_LOCK
event_type
GO_TO_STATE_INSTANTOPEN_OPEN (Touch to Open) (go_to_state = OPEN)
GO_TO_STATE_INSTANTOPEN_LATCH (Auto Unlock) (go_to_state = DAY_LOCK)
GO_TO_STATE_MANUAL_UNLOCK_BLE_OPEN (go_to_state = OPEN)
GO_TO_STATE_MANUAL_LOCK_BLE_LATCH (go_to_state = DAY_LOCK)
GO_TO_STATE_MANUAL_LOCK_BLE_NIGHT_LOCK (go_to__state = NIGHT_LOCK)
GO_TO_STATE_TWIST_ASSIST_OPEN (go_to_state = OPEN)
GO_TO_STATE_TWIST_ASSIST_LATCH (go_to_state = DAY_LOCK)
GO_TO_STATE_TWIST_ASSIST_LOCK (go_to_state = NIGHT_LOCK)
GO_TO_STATE_MANUAL_UNLOCK_VIA_OUTSIDE_MODULE_PIN (go_to_state = OPEN)
GO_TO_STATE_MANUAL_UNLOCK_VIA_OUTSIDE_MODULE_BUTTON (go_to_state = OPEN)
GO_TO_STATE_TOUCH_TO_LOCK (go_to_state = NIGHT_LOCK)
key_local_id (255 means unknown, e.g. manual opening by knob or pressing button)
Battery percentage
When the lock sends the current battery percentage (every few hours) the below JSON keys are sent for the trigger trigger_battery:
battery_type (0 = Alkaline, 1 = NiMH, 2 = Lithium (non-rechargable), 3 = unknown)
battery_percentage
Online status
When the lock loses the connection to the bridge, the below JSON keys are sent for the trigger trigger_online_status:
wifi_strength (currently in dB, soon this will change to a percentage)
ble_strength (currently in dB, soon this will change to a percentage. -1 means the lock is not connected)
Verify if the webhook request came from the LOQED Bridge
You might take sensitive actions if the door opens (e.g., turn on the lights, turn off the alarm, turn on the heater). Therefore you need to ensure that on the URL that you supplied, no other devices can trigger such actions. You can:
Ensure no other devices can call the URL by limiting the IP only to the LOQED Bridge's IP address. Also, ensure the bridge IP address does not change by fixating this in the DHCP service of your router.
Verify the hash signature sent in the headers of the webhook call. In the header, you find TIMESTAMP (8 bytes) and HASH (hex). You can calculate the hash yourself by doing sha256(BODY + TIMESTAMP + base64_decode(bridge_authentication_key). The bridge authentication key can be found on https://app.loqed.com/API-Config. The BODY is the unaltered body received with the request (with all the JSON code). Also do not forget to validate if the timestamp is within a few seconds from the actual time, to prevent replay attacks.
List, add, and delete a webhook on the bridge using our tool
The easiest way to list, add or delete webhooks is by using our Javascript tool:
Login on https://app.loqed.com/API-Config
Scroll to the heading "Outgoing Webhooks via LOQED Bridge"
Click on the button "Add/Delete webhooks" next to the correct bridge. The tool will open, and your bridge IP address and authentication key are pre-filled.
List, add, and delete a webhook on the bridge using your code
If you want to make it easier for users of your product to connect it to LOQED, you can also use the bridge API to set up the webhooks. Below the API endpoints are described. You can look at the code of the above-mentioned Javascript tool if you are looking for an example. The LOQED Bridge can be found using mDNS in your application (try "DNS-sd -B _http._tcp" on Windows for example)
For all /webhooks webserver methods two headers are mandatory:
TIMESTAMP: contains the current timestamp
HASH – sha256 hash string
The hash calculation is specific for each type of request and described in the corresponding section. You need the bridge's authentication key to be able to calculate the hash. This key can be found after logging in at https://app.loqed.com/API-Config. There is no other way to retrieve this key.
List webhooks
GET: https://bridge-ip-address/webhooks
The HASH in the header needs to be formatted: SHA256(TIMESTAMP + LOCK_TOKEN), where TIMESTAMP is an 8 bytes number and LOCK_TOKEN is the base64 decoded (!) bridge's security key (the key on the webhooks.loqed.com page is in base64). The HASH should be in hex.
Returns JSON array with keys:
'id' : 1 (int)
'trigger_state_changed_open' : 0/1
'trigger_state_changed_latch' : 0/1
'trigger_state_changed_night_lock' : 0/1
'trigger_state_changed_unknown' : 0/1
'trigger_state_goto_open' : 0/1
'trigger_state_goto_latch' : 0/1
'trigger_state_goto_night_lock' : 0/1
'trigger_battery' : 0/1
'trigger_online_status' : 0/1
Returns HTTP codes:
Return HTTP 400 BAD REQUEST code and string with description in case headers are invalid or not found
Return HTTP 401 UNAUTHORIZED if authentication failed
Create webhook
POST: http://bridge-ip-address/webhooks
Body: JSON with keys:
'trigger_state_changed_open' : 0/1
'trigger_state_changed_latch' : 0/1
'trigger_state_changed_night_lock' : 0/1
'trigger_state_changed_unknown' : 0/1
'trigger_state_goto_open' : 0/1
'trigger_state_goto_latch' : 0/1
'trigger_state_goto_night_lock' : 0/1
'trigger_battery' : 0/1
'trigger_online_status' : 0/1
The HASH in the header needs to be formatted: SHA256(URL + trigger_bitmap + TIMESTAMP + LOCK_TOKEN), URL is a string, trigger_bitmap 4 bytes, TIMESTAMP is an 8 bytes number, and LOCK_TOKEN is the base64 decoded (!) bridge's security key (the key on the webhooks.loqed.com page is in base64). The HASH should be in hex. The trigger_bitmap contains the triggers. For example, 0x000F (15 decimal) is 0000 0000 0000 1010 in binary, which means that the following triggers are enabled:
"trigger_state_changed_open":0
"trigger_state_changed_latch":1
"trigger_state_changed_night_lock":0
"trigger_state_changed_unknown":1
"trigger_state_goto_open":0
"trigger_state_goto_latch":0
"trigger_state_goto_night_lock":0
"trigger_battery":0
"trigger_online_status":0
We have also a small PHP snippet that shows how a webhook is created, you can download it here.
Returns:
HTTP 200 OK code and string with description in case of successful webhook creation
HTTP 400 BAD REQUEST code and string with description in case if JSON is not valid for webhook creation
HTTP 400 BAD REQUEST code and string with description in case headers are invalid or not found
HTTP 401 UNAUTHORIZED if authentication failed
HTTP 500 INTERNAL SERVER ERROR code and string with description in case if webhook with this URL already exists
HTTP 500 INTERNAL SERVER ERROR code and string with description in case if MAX number of webhooks reach
Delete webhook
DELETE: http://bridge-ip-address/webhooks/{webhookId}
The HASH in the header needs to be formatted: SHA256(id + TIMESTAMP + LOCK_TOKEN), ID is an 8 bytes number, TIMESTAMP is an 8 bytes number, and LOCK_TOKEN is the base64 decoded (!) bridge's security key (the key on the webhooks.loqed.com page is in base64). The HASH should be in hex.
Returns:
HTTP 200 OK code and string with description in case of successful webhook deletion
HTTP 400 BAD REQUEST code and string with description in case headers are invalid or not found
HTTP 401 UNAUTHORIZED if authentication failed
HTTP 404 NOT FOUND code and string with description in case if webhook with {webhookId} was not found
HTTP 500 INTERNAL SERVER ERROR code and string with description in case any error during deletion occurred
Testing
We recommend using Webhook.site if you want to verify that your smart lock/bridge is calling the Webhook URL. You will also be able to see the JSON data there.
Open/lock the door when something happens (incoming webhook)
If you want to control your lock from a third-party service or device, you can do this by way of an HTTPS GET call to your LOQED Bridge URL.
Creating an API Key
First, you need to create a new key on your LOQED Touch Smart Lock.
Open the page https://app.loqed.com/API-Config.
Log in using your email address and password that you use for logging into the LOQED app.
Click on "Add new API key".
Enter a name for easy identification. This can be anything you like.
If you have multiple locks, you can select the right lock in the dropdown menu right next to "Select Lock".
Click "Add API Key".
You have now created the API key.
Call the API
Currently, the API supports the following commands:
Open (lock opens, then returns to latch. Only supported on doors without a handle on the outside). An empty JSON object is returned.
Latch (unlocked). An empty JSON object is returned.
Night lock (locked). An empty JSON object is returned.
Status. ATTENTION: we recommend only requesting the status once per day, to keep the load on the bridge to a minimum. Instead of asking for the status, you should implement a webhook that calls your server, so you get an instant notification as soon as the lock state changes. It returns the following JSON keys:
mac_wifi (lock identification)
mac_bluetooth
lock_online (1 if the lock is online, otherwise 0)
battery_percentage (-1 if the lock is offline, otherwise 0 - 100)
battery_type (0 = Alkaline, 1 = NiMH, 2 = Lithium (non-rechargable), 3 = unknown)
bolt_state_numeric (0 = unknown, 1 = open, 2 = day_lock, 3 = night_lock)
bolt_state (unknown, open, day_lock, night_lock)
Let the LOQED bridge generate the digital signature
Commands to the smart lock need to be digitally signed. The easiest is to let the LOQED bridge generate this signature. Simply use the four provided URLs (open, latch, night lock, status) shown on webhooks.loqed.com. Note that the HTTP connection to the bridge is not secured, thus other people on your local network could potentially retrieve the encryption key. If you want to securely send commands, you need to generate the digital signature yourself.
Generate the digital signature yourself
At https://app.loqed.com/Bridge-API-example/ we provide example code (Javascript and PHP) that shows how the digital signature is created. You can only use this method if you can create your plugin for the smart home system you want to connect to. The data you need (IP, secret, KeyID) can be found at https://app.loqed.com/API-Config after clicking the "View / Edit" button next to the API Key.