Workflow Automation Guide
Build powerful multi-step location-based automations with SpatialFlow workflows. This guide covers common patterns, best practices, and real-world examples.
Overview
Workflows in SpatialFlow automate actions when geofence events occur. Think of workflows as "if-then" rules:
If a device enters/exits a geofence → Then execute one or more actions
Common use cases:
- Send Slack notification when vehicle enters delivery zone
- Trigger webhook and send email when unauthorized device enters restricted area
- Log to database when employee arrives at job site
Quick Start
Basic Workflow Structure
Every workflow has three components:
- Name: Descriptive identifier
- Trigger node: Geofence event that starts the workflow
- Action nodes: Actions to execute, connected by edges
Example:
{
"name": "Office Entry Notification",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "slack",
"label": "Slack Notification",
"config": {
"webhook_url": "https://hooks.slack.com/services/YOUR/WEBHOOK",
"message": "{{trigger.device_name}} arrived at the office"
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"}
]
}
Creating Your First Workflow
curl -X POST https://api.spatialflow.io/api/v1/workflows \
-H "X-API-KEY: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Delivery Zone Entry Alert",
"description": "Notify operations team when driver enters delivery zone",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["your-geofence-id"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "webhook",
"label": "HTTP Request",
"config": {
"url": "https://your-app.com/api/delivery-alerts",
"method": "POST",
"headers": {
"Content-Type": "application/json"
}
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"}
]
}'
Trigger Types
Geofence Entry
Fires when a device enters a geofence boundary.
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["b2c3d4e5-f6a7-8901-bcde-f12345678901"]
}
}
}
Use cases:
- Customer arrival notifications
- Check-in automation
- Zone entry logging
Geofence Exit
Fires when a device leaves a geofence boundary.
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_exit",
"label": "Geofence Exit",
"config": {
"geofence_ids": ["b2c3d4e5-f6a7-8901-bcde-f12345678901"]
}
}
}
Use cases:
- Departure confirmations
- Dwell time calculations
- Zone exit alerts
Available Actions
1. Webhook (HTTP Request)
Send HTTP request to any URL.
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "webhook",
"label": "HTTP Request",
"config": {
"url": "https://your-app.com/webhooks/geofence-event",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"X-Custom-Header": "value"
},
"body": {
"device": "{{trigger.device_name}}",
"geofence": "{{trigger.geofence_name}}",
"event_type": "{{trigger.event_type}}"
}
}
}
}
Template Variables:
{{trigger.device_id}},{{trigger.device_name}}{{trigger.geofence_id}},{{trigger.geofence_name}}{{trigger.location.latitude}},{{trigger.location.longitude}}{{trigger.event_type}},{{trigger.timestamp}}
2. Slack Notification
Send message to Slack channel.
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "slack",
"label": "Slack Notification",
"config": {
"webhook_url": "https://hooks.slack.com/services/YOUR/WEBHOOK",
"message": "🚗 {{trigger.device_name}} entered {{trigger.geofence_name}}",
"channel": "#operations"
}
}
}
3. Email (SES/SendGrid)
Send email notification.
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "email",
"label": "Email Notification",
"config": {
"to": "operations@example.com",
"subject": "Geofence Alert: {{trigger.geofence_name}}",
"body": "Device {{trigger.device_name}} entered {{trigger.geofence_name}} at {{trigger.timestamp}}"
}
}
}
4. SMS (Twilio)
Send SMS alert.
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "sms",
"label": "SMS Alert",
"config": {
"to": "+1234567890",
"message": "Alert: {{trigger.device_name}} entered {{trigger.geofence_name}}"
}
}
}
5. Database
Execute database operations for custom data persistence.
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "database",
"label": "Log Entry",
"config": {
"query": "INSERT INTO arrivals (device_id, geofence_id, arrived_at) VALUES ($1, $2, $3)",
"params": ["{{trigger.device_id}}", "{{trigger.geofence_id}}", "{{trigger.timestamp}}"]
}
}
}
Common Workflow Patterns
Pattern 1: Multi-Channel Notification
Send alerts to multiple channels simultaneously.
{
"name": "Multi-Channel Security Alert",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["restricted_area_id"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "slack",
"label": "Slack Alert",
"config": {
"webhook_url": "https://hooks.slack.com/...",
"message": "🚨 ALERT: {{trigger.device_name}} entered restricted area",
"channel": "#security"
}
}
},
{
"id": "action-2",
"type": "action",
"data": {
"actionType": "email",
"label": "Email Alert",
"config": {
"to": "security@example.com",
"subject": "Security Alert: Unauthorized Entry",
"body": "Device {{trigger.device_name}} entered restricted area at {{trigger.timestamp}}"
}
}
},
{
"id": "action-3",
"type": "action",
"data": {
"actionType": "sms",
"label": "SMS Alert",
"config": {
"to": "+1234567890",
"message": "SECURITY ALERT: {{trigger.device_name}} entered restricted area"
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"},
{"id": "edge-2", "source": "action-1", "target": "action-2"},
{"id": "edge-3", "source": "action-2", "target": "action-3"}
]
}
Pattern 2: Webhook Processing
Use a webhook for custom backend logic.
{
"name": "Process Vehicle Entry",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["depot_geofence"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "webhook",
"label": "Process Checkin",
"config": {
"url": "https://your-app.com/api/vehicle-checkin",
"method": "POST",
"body": {
"vehicle_id": "{{trigger.device_id}}",
"location": {
"lat": "{{trigger.location.latitude}}",
"lng": "{{trigger.location.longitude}}"
},
"timestamp": "{{trigger.timestamp}}"
}
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"}
]
}
Testing Workflows
1. Create Test Geofence
Create a small test geofence for development:
curl -X POST https://api.spatialflow.io/api/v1/geofences/ \
-H "X-API-KEY: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Test Geofence - Delete After Testing",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-122.4200, 37.7745],
[-122.4200, 37.7753],
[-122.4188, 37.7753],
[-122.4188, 37.7745],
[-122.4200, 37.7745]
]]
}
}'
2. Create Test Workflow
Use webhook.site for quick testing:
curl -X POST https://api.spatialflow.io/api/v1/workflows \
-H "X-API-KEY: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Test Workflow",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["test_geofence_id"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "webhook",
"label": "HTTP Request",
"config": {
"url": "https://webhook.site/your-unique-id",
"method": "POST"
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"}
]
}'
3. Send Test Location
Trigger the workflow with a test location:
curl -X POST https://api.spatialflow.io/api/v1/locations \
-H "X-API-KEY: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"device_id": "test_device",
"lat": 37.7749,
"lon": -122.4194,
"ts": "2025-11-10T12:00:00Z"
}'
4. Check Webhook Deliveries
View webhook delivery history:
curl -X GET https://api.spatialflow.io/api/v1/workflows/{workflow_id}/executions \
-H "X-API-KEY: YOUR_API_KEY"
Debugging Failed Workflows
Check Workflow Execution Logs
curl -X GET https://api.spatialflow.io/api/v1/workflows/{workflow_id}/executions?status=failed \
-H "X-API-KEY: YOUR_API_KEY"
Common failure reasons:
- Webhook endpoint returned 5xx error
- Request timeout (> 30 seconds)
- Invalid action configuration
- Missing required fields
View Execution Details
curl -X GET https://api.spatialflow.io/api/v1/workflows/executions/{execution_id} \
-H "X-API-KEY: YOUR_API_KEY"
Response includes:
{
"execution_id": "exec_123",
"workflow_id": "wf_456",
"status": "failed",
"error": "Webhook returned 500 Internal Server Error",
"started_at": "2025-11-10T12:00:00Z",
"completed_at": "2025-11-10T12:00:05Z",
"duration_seconds": 5.0,
"current_step": 0
}
Best Practices
1. Use Descriptive Names
Good:
- "Notify Ops Team - Delivery Zone Entry"
- "Log Employee Arrival - SF Office"
- "Security Alert - Restricted Area"
Bad:
- "Workflow 1"
- "Test"
- "asdf"
2. Set Workflow Active/Inactive
Disable workflows during maintenance without deleting:
# Deactivate workflow (toggle endpoint)
curl -X POST https://api.spatialflow.io/api/v1/workflows/{workflow_id}/toggle \
-H "X-API-KEY: YOUR_API_KEY"
3. Monitor Action Failures
Set up monitoring for failed actions:
# Get failed executions
curl -X GET https://api.spatialflow.io/api/v1/workflows/executions?status=failed \
-H "X-API-KEY: YOUR_API_KEY"
4. Use Idempotent Actions
Ensure actions can be safely retried:
- Use unique IDs in database inserts
- Check for duplicates before processing
- Handle webhook retries gracefully
5. Keep Actions Fast
- Webhooks should respond in < 5 seconds
- Use async processing for slow operations
- Return 2xx quickly to prevent retries
Performance Considerations
Workflow Execution Speed
- Actions execute sequentially (one after another)
- Typical execution time: 100-500ms per action
- Webhook actions depend on your endpoint response time
Rate Limits
- No limit on workflow count
- No limit on executions per workflow
- Webhook delivery rate limited to 60/min per endpoint
Scaling Tips
- Use separate workflows for different priorities
- Group related actions in single workflow (fewer executions)
- Use webhooks to fan out to external services for high-volume scenarios
Real-World Examples
Example 1: Fleet Check-In System
{
"name": "Vehicle Depot Check-In",
"description": "Log vehicle arrivals and notify dispatch",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["depot_north_bay"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "slack",
"label": "Slack Notification",
"config": {
"webhook_url": "https://hooks.slack.com/...",
"message": "✅ Vehicle {{trigger.device_name}} checked in at {{trigger.geofence_name}}",
"channel": "#dispatch"
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"}
]
}
Example 2: Customer Proximity Marketing
{
"name": "Store Arrival - Send Welcome Offer",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["store_42_sf"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "webhook",
"label": "HTTP Request",
"config": {
"url": "https://marketing-platform.com/api/send-offer",
"method": "POST",
"headers": {
"Authorization": "Bearer MARKETING_API_KEY"
},
"body": {
"customer_id": "{{trigger.device_id}}",
"store_id": "{{trigger.geofence.metadata.store_number}}",
"offer_type": "welcome_discount"
}
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"}
]
}
Example 3: Security Perimeter Alert
{
"name": "Restricted Area - Immediate Alert",
"nodes": [
{
"id": "trigger-1",
"type": "trigger",
"data": {
"triggerType": "geofence_enter",
"label": "Geofence Entry",
"config": {
"geofence_ids": ["construction_site_restricted"]
}
}
},
{
"id": "action-1",
"type": "action",
"data": {
"actionType": "sms",
"label": "SMS Alert",
"config": {
"to": "+1234567890",
"message": "⚠️ ALERT: {{trigger.device_name}} entered restricted construction area"
}
}
},
{
"id": "action-2",
"type": "action",
"data": {
"actionType": "email",
"label": "Email Alert",
"config": {
"to": "security@example.com",
"subject": "URGENT: Restricted Area Entry",
"body": "Device: {{trigger.device_name}}\nArea: {{trigger.geofence_name}}\nTime: {{trigger.timestamp}}\nLocation: {{trigger.location.latitude}}, {{trigger.location.longitude}}"
}
}
},
{
"id": "action-3",
"type": "action",
"data": {
"actionType": "webhook",
"label": "HTTP Request",
"config": {
"url": "https://security-system.com/api/alerts",
"method": "POST"
}
}
}
],
"edges": [
{"id": "edge-1", "source": "trigger-1", "target": "action-1"},
{"id": "edge-2", "source": "action-1", "target": "action-2"},
{"id": "edge-3", "source": "action-2", "target": "action-3"}
]
}
Next Steps
- Workflows Concept Guide - Deep dive into workflow engine
- Webhook Integration - Build custom webhook receivers
- Geofences - Create and manage geofences
- API Reference - Complete API documentation
- Error Handling - Debug failed workflows