Skip to main content

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

  1. Visit api.slack.com/apps and click Create New AppFrom scratch
  2. Name the app (e.g., SpatialFlow Alerts) and pick the target workspace
  3. In the left sidebar, click Incoming Webhooks and toggle the feature On
  4. Click Add New Webhook to Workspace, choose the destination channel (e.g., #dispatch), and click Allow
  5. Copy the generated webhook URL — it looks like https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Treat the webhook URL as a secret

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:

FieldValue
NameNotify Slack
URL(paste the webhook URL from Step 1)
MethodPOST
HeadersContent-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

  1. In the Workflow Builder, click Test
  2. Review the mock trigger payload and run the test
  3. Check the destination Slack channel — you should see a formatted message within a couple of seconds
  4. If the test passes, Save then Deploy the workflow
Confirming via curl

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_interval with a healthy cooldown (15–60 minutes) when you want recurring nudges — once_until_seen is 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).

See Also