Command Webhook Callbacks
It is possible to get notified via webhook when a command completes on a device.
#
Overview- Execute command through the API
- If the device does respond, a webhook request is sent with the result of the command.
- If the device does not respond, it will eventually time out (default timeout: 120 seconds), and this will cause a timeout request to be sent to your server.
Note that if the device responds with a command result after the timeout, it will still send the COMMAND_EXECUTED
payload, even after the TIMEOUT
payload has been sent.
#
1. Executing a Command With CallbackThe way this works is that if you specify the callback_url
field when sending a request to the /dongle/devices/{id}/execute/
or /dongle/devices/{id}/execute_raw/
endpoint, the server will send a callback to the requested url when the server receives the response from the device.
note
The fields that contains the command and arguments for the two endpoints are a bit different, but the callback fields is the same for both of them.
See the difference in the autogenerated API documentation
Request
POST /dongle/devices/{DEVICE_ID}/execute[_raw]/{ "command": "{COMMAND}", "callback_url": "{CALLBACK_URL}", "callback_timeout": 1-600 // default 120 seconds}
Response
{ "jid": "{JOB_ID}", "minions": [ "{UNIT_ID}" ]}
#
2. Getting Notified by the Webhook Request.The request sent to your server looks like this.
HEADERS{ 'Content-Type': 'application/json', 'X-Request-Signature': {HMAC_SIGNATURE},}
BODY{ "response": { "tag": "salt/job/{JOB_ID}/ret/{UNIT_ID}", "data": { "fun_args": [], "jid": "{JOB_ID}", "return": true, "retcode": 0, "success": true, "cmd": "_return", "_stamp": "2022-01-01T00:00:00.000000", "fun": "{COMMAND}", "id": "{UNIT_ID}" } }, "jid": "{JOB_ID}", "state": "COMMAND_EXECUTED" | "TIMEOUT", "success": true, "device_id": {DEVICE_ID}}
#
Verifying the Requests Using the HMAC Signature.The response contains a HMAC sign in the X-Request-Signature
header that can be used to verify the integrity of the webhook request.
The response json is signed with HMAC SHA-256 using the Authorization header used for executing the command (Without the 'APIToken' or 'Bearer' part).
Example python code that verifies the request.
import hmacimport hashlib
secret = "API Token or JWT token without Bearer or APIToken postfix"webhook_signature = "xxxxxxxxxxx"
json_body = "{}"
calculated_signature = hmac.new(hmac_secret.encode('utf-8'), json_body, hashlib.sha256).hexdigest()valid = hmac.compare_digest(calculated_signature, webhook_signature)
note
Each response always includes a unique job id, so no two request signatures are the same.
#
3. Debugging: Getting Information About the Scheduled CallbackThe /dongle/devices/{DEVICE_ID}/callback/{JOB_ID}/
endpoint allows you to get the callback object from our system.
Each callback will be stored in our system for 2 days before automatically expiring.
GET /dongle/devices/{DEVICE_ID}/callback/{JOB_ID}/{ // Contains all requests that are sent to your server, it will retry the request up to 5 times. "sent_requests": [ { "timestamp": "2022-01-01T00:00:00.000000Z", "state": "COMMAND_EXECUTED", "success": true, "response_statuscode": 200 } ], "url": "{CALLBACK_URL}", "timestamp": "2022-01-01T00:00:00.000000Z", // uuid used internally for keeping track of the timeout task. "timeout_task_id": "UUID", // Information about the command executed "command": { "returner": null, "command": "{COMMAND}", "arg": [] }, // The timeout valud used for the callback. "timeout": 60, "device_id": "{DEVICE_ID}"}
note
The response will look different based on what command was executed.
If you execute a module, the response will look like the above, but if you instead trigger a state run, like if you use want to sync the pending changes to the device state.sls pending
, then the response will include the whole result of the pending states that was executed.