Generic HTTP Alerting
When your destination isn't Slack or PagerDuty — an internal incident tracker, a Twilio number, a custom alerting service, or a logging pipeline — the Webhook action posts directly to any HTTPS endpoint that accepts JSON. This is the most flexible recipe for any of the live-ops triggers (Device Offline, Device Stuck, or Shift Overdue).
Prerequisites
- An HTTPS endpoint that accepts
POSTwith a JSON body (a public service or your own backend) - A SpatialFlow workflow with one of the three live-ops triggers configured
- (Optional) Authentication credentials for your endpoint (API key, bearer token, basic auth)
Step 1 — Sanity-Check Your Endpoint With curl
Before wiring anything up in SpatialFlow, confirm your endpoint accepts the shape of payload you intend to send. A throwaway endpoint like webhook.site is perfect for this:
curl -X POST https://your-endpoint.example.com/spatialflow-alerts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"alert": "device_offline",
"device_id": "test-device-1",
"minutes_since_seen": 22
}'
A 2xx response confirms the endpoint is reachable and the auth header is valid. If you get 401/403, fix that here — the SpatialFlow Webhook action will return the same error.
Step 2 — Add a Webhook Action to Your Workflow
In the Workflow Builder, drag a Webhook action onto the canvas after your trigger node and connect them. Configure:
| Field | Value |
|---|---|
| Name | Post alert to <system-name> |
| URL | (your endpoint, e.g. https://api.your-system.example/alerts) |
| Method | POST |
| Headers | Content-Type: application/json + your auth header (see below) |
| Body | (copy from the matching tab below) |
| Timeout | 10 seconds (raise if your endpoint is slow) |
Common Authentication Headers
| Auth Style | Header |
|---|---|
| Bearer Token | Authorization: Bearer YOUR_TOKEN |
| API Key | X-API-Key: YOUR_KEY |
| Basic Auth | Authorization: Basic BASE64(user:password) |
| HMAC Signing | Configure on the action's Signing tab |
Body — Device Offline
{
"alert_type": "device_offline",
"trigger_type": "{{trigger.event_type}}",
"device": {
"id": "{{trigger.device_id}}",
"name": "{{trigger.device_name}}",
"type": "{{trigger.device_type}}"
},
"anomaly": {
"last_seen_at": "{{trigger.last_seen_at}}",
"minutes_since_seen": "{{trigger.minutes_since_seen}}",
"threshold_minutes": "{{trigger.threshold_minutes}}",
"stale_since": "{{trigger.stale_since}}"
},
"location": {
"latitude": "{{trigger.location.latitude}}",
"longitude": "{{trigger.location.longitude}}"
},
"workspace_id": "{{trigger.workspace_id}}"
}
Body — Device Stuck
{
"alert_type": "device_stuck",
"trigger_type": "{{trigger.event_type}}",
"device": {
"id": "{{trigger.device_id}}",
"name": "{{trigger.device_name}}",
"type": "{{trigger.device_type}}"
},
"anomaly": {
"meters_moved_in_window": "{{trigger.meters_moved_in_window}}",
"window_minutes": "{{trigger.window_minutes}}",
"threshold_distance_meters": "{{trigger.threshold_distance_meters}}"
},
"location": {
"latitude": "{{trigger.location.latitude}}",
"longitude": "{{trigger.location.longitude}}"
},
"workspace_id": "{{trigger.workspace_id}}"
}
Body — Shift Overdue
{
"alert_type": "shift_overdue",
"trigger_type": "{{trigger.event_type}}",
"device": {
"id": "{{trigger.device_id}}",
"name": "{{trigger.device_name}}",
"type": "{{trigger.device_type}}"
},
"anomaly": {
"shift_started_at": "{{trigger.shift_started_at}}",
"hours_elapsed": "{{trigger.hours_elapsed}}",
"threshold_hours": "{{trigger.threshold_hours}}"
},
"location": {
"latitude": "{{trigger.location.latitude}}",
"longitude": "{{trigger.location.longitude}}"
},
"workspace_id": "{{trigger.workspace_id}}"
}
Step 3 — Test the Workflow
- In the Workflow Builder, click Test
- Review the mock trigger payload and run the test
- Confirm your endpoint logged the request with the expected body
- If the test passes, Save then Deploy the workflow
Receiver-Side Verification (Optional but Recommended)
For production endpoints, verify that incoming requests really came from SpatialFlow:
- Enable HMAC signing on the Webhook action — SpatialFlow will sign each request body with your shared secret
- On the receiver side, recompute the signature and compare against the
X-SpatialFlow-Signatureheader - Reject any request whose signature does not match
This prevents replay attacks and lets you safely expose the endpoint on the public internet. See Webhook Integration for full signing details.
Best Practices
- Use HTTPS — SpatialFlow will not refuse plain HTTP, but anything carrying live-ops data should be encrypted in transit
- Set a reasonable timeout — default is 10 seconds; raise it only for endpoints that genuinely need longer to respond
- Configure retries — the default retry count is 3 with exponential backoff; lower this for endpoints that are intentionally idempotent only
- Idempotency keys — if your endpoint is sensitive to duplicates, add
"idempotency_key": "{{trigger.device_id}}-{{trigger.last_seen_at}}"to the body so retries don't double-record - Echo back
workspace_id— multi-tenant receivers should always carry the workspace ID to disambiguate
Troubleshooting
Receiver gets {{trigger.device_id}} instead of the resolved value. Either 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).
Receiver gets the payload but the body is malformed JSON. Smart quotes or non-ASCII characters from copy-paste are the usual culprit. Re-paste from this page (which uses plain ASCII) and avoid editing in a rich-text editor.
Endpoint returns 4xx and the workflow retries forever. Configure retries with exponential backoff and a finite max attempts count. SpatialFlow does not retry on 4xx by default (4xx means "your request is wrong, retrying will not help"), but it does on 5xx and timeouts.
Endpoint is slow and the workflow times out. Raise the timeout in the Webhook action's config (max 300 seconds), or restructure the receiver to accept the payload asynchronously and process it in the background.
Related Recipes
- Slack Alerting
- PagerDuty Alerting
- Webhook Integration — full webhook action reference, including signing