Slack Alerting
Route any of the live-ops triggers (Device Offline, Device Stuck, or Shift Overdue) into a Slack channel using an Incoming Webhook. This recipe is end-to-end runnable — follow it once and you'll have a working alert in under five minutes.
Prerequisites
- A Slack workspace where you can install apps
- A SpatialFlow workflow with one of the three live-ops triggers configured
- An API key or JWT token for the SpatialFlow API (see Authentication)
Step 1 — Create an Incoming Webhook in Slack
- Visit api.slack.com/apps and click Create New App → From scratch
- Name the app (e.g.,
SpatialFlow Alerts) and pick the target workspace - In the left sidebar, click Incoming Webhooks and toggle the feature On
- Click Add New Webhook to Workspace, choose the destination channel (e.g.,
#dispatch), and click Allow - Copy the generated webhook URL — it looks like
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Anyone with this URL can post to your Slack channel. Store it in your workspace's Integrations settings rather than hard-coding it into every workflow.
Step 2 — Add a Webhook Action to Your Workflow
In the SpatialFlow Workflow Builder, drag a Webhook action onto the canvas after your trigger node and connect them. Configure it as follows:
| Field | Value |
|---|---|
| Name | Notify Slack |
| URL | (paste the webhook URL from Step 1) |
| Method | POST |
| Headers | Content-Type: application/json |
| Body | (copy from the matching tab below) |
Body — Device Offline
{
"text": ":satellite: Device offline alert",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "Device Offline" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Device:*\n{{trigger.device_name}} (`{{trigger.device_id}}`)" },
{ "type": "mrkdwn", "text": "*Type:*\n{{trigger.device_type}}" },
{ "type": "mrkdwn", "text": "*Last seen:*\n{{trigger.last_seen_at}}" },
{ "type": "mrkdwn", "text": "*Silent for:*\n{{trigger.minutes_since_seen}} minutes (threshold: {{trigger.threshold_minutes}})" }
]
}
]
}
Body — Device Stuck
{
"text": ":octagonal_sign: Device stuck alert",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "Device Stuck" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Device:*\n{{trigger.device_name}} (`{{trigger.device_id}}`)" },
{ "type": "mrkdwn", "text": "*Type:*\n{{trigger.device_type}}" },
{ "type": "mrkdwn", "text": "*Moved:*\n{{trigger.meters_moved_in_window}} m in {{trigger.window_minutes}} min" },
{ "type": "mrkdwn", "text": "*Threshold:*\n{{trigger.threshold_distance_meters}} m" }
]
}
]
}
Body — Shift Overdue
{
"text": ":hourglass: Shift overdue alert",
"blocks": [
{
"type": "header",
"text": { "type": "plain_text", "text": "Shift Overdue" }
},
{
"type": "section",
"fields": [
{ "type": "mrkdwn", "text": "*Device:*\n{{trigger.device_name}} (`{{trigger.device_id}}`)" },
{ "type": "mrkdwn", "text": "*Shift started:*\n{{trigger.shift_started_at}}" },
{ "type": "mrkdwn", "text": "*Elapsed:*\n{{trigger.hours_elapsed}} hours" },
{ "type": "mrkdwn", "text": "*Threshold:*\n{{trigger.threshold_hours}} hours" }
]
}
]
}
Step 3 — Test the Workflow
- In the Workflow Builder, click Test
- Review the mock trigger payload and run the test
- Check the destination Slack channel — you should see a formatted message within a couple of seconds
- If the test passes, Save then Deploy the workflow
You can sanity-check your Slack webhook independently of SpatialFlow with a one-liner:
curl -X POST -H 'Content-Type: application/json' \
--data '{"text":"Hello from curl"}' \
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
If that posts to the channel, the webhook is good and the SpatialFlow side is the only piece left to wire up.
Best Practices
- Use a dedicated channel for live-ops alerts (e.g.,
#fleet-ops) so they don't drown in general chatter - Pair
repeat_policy: every_intervalwith a healthy cooldown (15–60 minutes) when you want recurring nudges —once_until_seenis the right default for everything else - Store the webhook URL in an Integration rather than per-workflow so you can rotate it in one place
- Add a map link by templating
https://www.google.com/maps?q={{trigger.location.latitude}},{{trigger.location.longitude}}into a Slack block — operators love a one-click way to see where the device is
Troubleshooting
Slack returns invalid_payload. Your JSON is malformed. Most often this is a missing comma or a smart quote (") that slipped in from copy-paste — strip non-ASCII characters and re-paste.
Slack returns channel_not_found. The webhook URL is bound to a specific channel at creation time. If you renamed or archived the channel, create a fresh webhook in Step 1.
Message arrives but template variables are literal ({{trigger.device_name}}). The variable path is wrong, or the trigger payload doesn't include that field — check the trigger reference page for the exact envelope and confirm the trigger fired (the workflow execution log shows the inbound trigger_data).