Workflows
Workflows are the core automation engine of SpatialFlow, enabling you to create event-driven automation sequences that respond to geospatial events in real-time. When a device enters or exits a geofence, workflows automatically trigger actions like sending webhooks, Slack notifications, emails, or SMS messages—typically within 2 seconds.
What is a Workflow?
A workflow is an automation pipeline that connects a trigger to one or more actions. Think of it as: "When [something happens], do [these things]."
Trigger → Action 1 → Action 2 → Action 3
For example:
- When a delivery truck enters the customer's geofence
- Do send a webhook to your backend API and send a Slack message to the operations channel
Workflow Components
Triggers
Triggers define when a workflow should execute. SpatialFlow currently supports the following trigger types:
Geofence Entry
Fires when a device enters a geofence boundary.
Configuration:
- Geofence Selection: Choose one or more geofences to monitor
- Debounce Settings: Minimum distance delta and time interval to prevent GPS jitter from causing duplicate triggers
Example:
{
"type": "geofence_enter",
"geofence_ids": ["a1b2c3d4-..."],
"debounce_distance_m": 50,
"debounce_time_s": 30
}
Geofence Exit
Fires when a device leaves a geofence boundary.
Configuration:
- Geofence Selection: Choose one or more geofences to monitor
- Debounce Settings: Similar to entry triggers
Example:
{
"type": "geofence_exit",
"geofence_ids": ["a1b2c3d4-..."],
"debounce_distance_m": 50,
"debounce_time_s": 30
}
Signal Triggers
Workflows can also trigger on spatial signals — anomaly detection events that go beyond simple boundary crossings. Signal triggers fire when SpatialFlow detects behavioral patterns like prolonged dwell time or policy violations.
Configuration:
- Signal Types: Choose which signal types to listen for (
dwell,policy_violation) - Signal States: Which lifecycle states trigger the workflow (default:
confirmed) - Geofence Filter: Optionally limit to signals from specific geofences
- Device Filter: Optionally limit to signals from specific devices
Example:
{
"type": "signal",
"signal_types": ["dwell", "policy_violation"],
"signal_states": ["confirmed"],
"geofence_ids": ["a1b2c3d4-..."]
}
route_deviation is a reserved signal type but is not yet active. See Signals for details.
See Signals for details on signal types and lifecycle, and the Signal Configuration Guide for setup instructions.
Actions
Actions define what happens when a workflow is triggered. You can chain multiple actions together in sequence.
Webhook (HTTP Request)
Send HTTP requests to external APIs with custom headers, authentication, and payloads.
Supported Methods: GET, POST, PUT, PATCH, DELETE
Features:
- Custom headers and request body
- Authentication: Basic Auth, Bearer Token, API Key
- Variable substitution from trigger data
- Request signing with HMAC signatures
- Automatic retries with exponential backoff
- Configurable timeouts (up to 30 seconds)
Example Configuration:
{
"type": "webhook",
"name": "Send arrival notification",
"config": {
"url": "https://api.example.com/webhooks/arrival",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"X-API-Key": "your-api-key"
},
"body": {
"device_id": "{{trigger.device_id}}",
"geofence_name": "{{trigger.geofence.name}}",
"timestamp": "{{trigger.timestamp}}",
"location": {
"lat": "{{trigger.location.lat}}",
"lng": "{{trigger.location.lng}}"
}
},
"timeout": 10,
"retry_count": 3
}
}
Slack Notification
Send messages to Slack channels or direct messages with rich formatting.
Features:
- Webhook-based authentication via Integrations
- Channel or user targeting
- Rich message formatting with Markdown
- Block Kit support for interactive messages
- Thread support for organizing conversations
Example Configuration:
{
"type": "slack",
"name": "Notify operations team",
"config": {
"integration_id": "int_abc123",
"channel": "#operations",
"message": "Vehicle {{trigger.device_id}} arrived at {{trigger.geofence.name}}"
}
}
Email
Send email notifications using AWS SES or SendGrid.
Features:
- HTML and plain text email support
- Template variables for dynamic content
- Multiple recipients (to, cc, bcc)
- Attachments support
- Custom sender names
Example Configuration:
{
"type": "email",
"name": "Send arrival email",
"config": {
"integration_id": "int_xyz789",
"to": ["manager@example.com"],
"subject": "Arrival at {{trigger.geofence.name}}",
"body_html": "<p>Device {{trigger.device_id}} has arrived at {{trigger.geofence.name}} at {{trigger.timestamp}}.</p>",
"body_text": "Device {{trigger.device_id}} arrived at {{trigger.geofence.name}}"
}
}
SMS (Twilio)
Send SMS notifications via Twilio integration.
Features:
- International phone number support
- Template variables for dynamic content
- Delivery tracking and status updates
- Support for multiple recipients
Example Configuration:
{
"type": "twilio_sms",
"name": "Send arrival SMS",
"config": {
"integration_id": "int_twilio123",
"to": "+14155551234",
"message": "Your delivery has arrived at {{trigger.geofence.name}}"
}
}
AWS Lambda
Invoke AWS Lambda functions with custom payloads.
Features:
- Synchronous and asynchronous invocation
- IAM role support for secure authentication
- Custom payload with trigger context
- Response data capture for downstream actions
Example Configuration:
{
"type": "aws_lambda",
"name": "Process arrival event",
"config": {
"integration_id": "int_lambda456",
"function_name": "process-geofence-event",
"payload": {
"event_type": "arrival",
"device_id": "{{trigger.device_id}}",
"geofence_id": "{{trigger.geofence.id}}"
}
}
}
AWS SNS
Publish messages to AWS SNS topics for fan-out messaging patterns.
Features:
- Topic publishing with message attributes
- Support for different message formats (JSON, String)
- IAM role support
- Message deduplication for FIFO topics
Example Configuration:
{
"type": "aws_sns",
"name": "Publish to SNS topic",
"config": {
"integration_id": "int_sns789",
"topic_arn": "arn:aws:sns:us-east-1:123456789012:geofence-events",
"message": "{{trigger | json}}",
"message_attributes": {
"event_type": "geofence_entry",
"device_id": "{{trigger.device_id}}"
}
}
}
Microsoft Teams
Send messages to Microsoft Teams channels via webhook connectors.
Features:
- Adaptive Cards support for rich formatting
- Channel webhook integration
- Action buttons and interactive elements
Discord
Send messages to Discord channels via webhooks.
Features:
- Rich embeds with colors and formatting
- Webhook-based messaging
- Support for avatars and custom usernames
Database Operations
Execute database queries for custom data persistence.
Features:
- PostgreSQL query execution
- Read and write operations
- Parameterized queries for security
- Result capture for downstream actions
Creating Workflows
Via Visual Builder
The SpatialFlow web application includes a no-code workflow builder with a drag-and-drop canvas interface powered by React Flow.
Steps:
- Navigate to Workflows in the dashboard
- Click New Workflow
- Drag a Trigger node onto the canvas
- Configure the trigger (select geofences, set debounce settings)
- Drag Action nodes and connect them to the trigger
- Configure each action with the required settings
- Test your workflow with the built-in testing tool
- Save and activate your workflow
Features:
- Visual workflow canvas with zoom and pan
- Collapsible component palette
- Real-time configuration inspector
- Auto-save and draft recovery
- Workflow templates for common patterns
- Test mode with live execution monitoring
Via API
Create workflows programmatically using the REST API.
The actual API uses a nodes and edges format (a visual graph representation) rather than the simplified trigger_config/steps structure shown below. See Create Your First Workflow for the exact API schema with the nodes/edges format.
Endpoint: POST /api/v1/workflows
Request (simplified representation):
curl -X POST https://api.spatialflow.io/api/v1/workflows \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Warehouse Arrival Alert",
"description": "Send notifications when trucks arrive at warehouse",
"trigger_config": {
"type": "geofence_enter",
"geofence_ids": ["a1b2c3d4-5678-90ab-cdef-1234567890ab"]
},
"steps": [
{
"type": "webhook",
"name": "Send to backend",
"config": {
"url": "https://api.example.com/arrivals",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"body": {
"device_id": "{{trigger.device_id}}",
"timestamp": "{{trigger.timestamp}}"
}
}
},
{
"type": "slack",
"name": "Notify team",
"config": {
"integration_id": "int_slack123",
"channel": "#warehouse",
"message": "Truck {{trigger.device_id}} arrived"
}
}
],
"is_active": false,
"is_test_mode": true,
"tags": ["warehouse", "arrivals"],
"category": "geofence"
}'
Response:
{
"id": "wf_abc123def456",
"name": "Warehouse Arrival Alert",
"description": "Send notifications when trucks arrive at warehouse",
"status": "draft",
"version": 1,
"created_at": "2025-11-10T12:00:00Z",
"updated_at": "2025-11-10T12:00:00Z"
}
Workflow Execution
When a trigger condition is met, SpatialFlow executes the workflow automatically:
- Event Detection: The platform monitors location updates and detects geofence transitions
- Workflow Matching: All active workflows matching the trigger are identified
- Execution Queue: A workflow execution job is queued to Celery for async processing
- Step Execution: Each action in the workflow executes in sequence
- Status Updates: Real-time status updates are sent via WebSocket
- Result Capture: Execution results, timing, and any errors are stored
Target Latency: < 2 seconds from trigger to action completion (p95)
Execution Context
Each workflow execution has access to a context object containing:
trigger: The triggering event data (device_id, location, geofence details, timestamp)workflow: Workflow metadata (id, name, version)execution: Current execution context (id, started_at)- Step outputs: Accessible via
step_0,step_1, etc., for subsequent steps
Example Template Variable Usage:
Device {{trigger.device_id}} entered {{trigger.geofence.name}} at {{trigger.timestamp}}
Location: {{trigger.location.lat}}, {{trigger.location.lng}}
Workflow Status & Monitoring
Status States
Workflows can be in one of three states:
- Draft: Inactive workflow in test mode (not triggered by real events)
- Active: Deployed workflow actively monitoring for trigger conditions
- Paused: Inactive workflow that can be quickly reactivated
Execution History
Every workflow execution is tracked with detailed information:
- Execution ID: Unique identifier for each run
- Status: pending, running, completed, failed, cancelled
- Trigger Source: geofence, manual_test, schedule, webhook
- Step Details: Individual step execution with timing and status
- Duration: Total execution time in milliseconds
- Error Messages: Detailed error information for failed executions
API Endpoint: GET /api/v1/workflows/{workflow_id}/executions
Real-time Monitoring
The workflow builder includes a real-time debugger that shows:
- Live execution progress
- Step-by-step status updates via WebSocket
- Input and output data for each step
- Execution duration and performance metrics
- Error messages and retry attempts
Best Practices
Naming Conventions
- Use descriptive names that explain the purpose: "Warehouse Entry Alerts" instead of "Workflow 1"
- Include the trigger type and primary action: "Geofence Exit → Webhook"
- Add environment prefix for multi-environment setups: "PROD: Customer Arrivals"
Testing Workflows
- Start workflows in test mode (is_test_mode: true)
- Use the built-in workflow tester with mock trigger data
- Verify all actions execute successfully
- Check execution logs for timing and error details
- Test edge cases (missing data, API failures)
- Activate only after thorough testing
Error Handling
- Configure appropriate retry counts for webhook actions (default: 3)
- Set realistic timeouts based on downstream API performance
- Monitor execution history for patterns of failures
- Use exponential backoff for retry policies
- Configure dead-letter queues for terminal failures
Performance Considerations
- Keep action chains short (recommended: 3-5 actions maximum)
- Use async actions when order doesn't matter
- Minimize large payload sizes in webhook bodies
- Cache frequently accessed data in action handlers
- Monitor execution latency and optimize slow actions
Security
- Use integrations for storing credentials instead of hardcoding secrets
- Enable webhook signature verification (HMAC)
- Validate input data before using in templates
- Follow least-privilege principle for IAM roles (AWS actions)
- Regularly rotate API keys and tokens
Common Patterns
Pattern 1: Delivery Arrival Notification
Use Case: Notify customers when their delivery vehicle arrives
{
"name": "Customer Arrival Notification",
"trigger_config": {
"type": "geofence_enter",
"geofence_ids": ["customer_delivery_zone"]
},
"steps": [
{
"type": "webhook",
"name": "Update backend",
"config": {
"url": "https://api.example.com/deliveries/arrival",
"method": "POST",
"body": {
"delivery_id": "{{trigger.device_id}}",
"customer_id": "{{trigger.geofence.metadata.customer_id}}",
"arrival_time": "{{trigger.timestamp}}"
}
}
},
{
"type": "twilio_sms",
"name": "SMS customer",
"config": {
"to": "{{trigger.geofence.metadata.customer_phone}}",
"message": "Your delivery is arriving now!"
}
}
]
}
Pattern 2: Restricted Zone Alert
Use Case: Alert security team when a vehicle enters a restricted area
{
"name": "Restricted Zone Entry Alert",
"trigger_config": {
"type": "geofence_enter",
"geofence_ids": ["restricted_zone_1", "restricted_zone_2"]
},
"steps": [
{
"type": "slack",
"name": "Alert security",
"config": {
"channel": "#security-alerts",
"message": "⚠️ ALERT: Vehicle {{trigger.device_id}} entered restricted zone {{trigger.geofence.name}} at {{trigger.timestamp}}"
}
},
{
"type": "email",
"name": "Email security manager",
"config": {
"to": ["security@example.com"],
"subject": "Restricted Zone Entry Alert",
"body_html": "<p>Vehicle {{trigger.device_id}} entered {{trigger.geofence.name}}</p>"
}
}
]
}
Pattern 3: Multi-Action Webhook Fan-out
Use Case: Trigger multiple downstream systems when a depot entry occurs
{
"name": "Depot Entry Multi-System Update",
"trigger_config": {
"type": "geofence_enter",
"geofence_ids": ["main_depot"]
},
"steps": [
{
"type": "webhook",
"name": "Update ERP system",
"config": {
"url": "https://erp.example.com/api/vehicle-arrival",
"method": "POST"
}
},
{
"type": "webhook",
"name": "Update fleet management",
"config": {
"url": "https://fleet.example.com/api/events",
"method": "POST"
}
},
{
"type": "aws_sns",
"name": "Publish to event bus",
"config": {
"topic_arn": "arn:aws:sns:us-east-1:123456789012:depot-events",
"message": "{{trigger | json}}"
}
}
]
}
Pattern 4: Time-Windowed Notification
Use Case: Only send alerts during business hours
{
"name": "Business Hours Arrival Alert",
"trigger_config": {
"type": "geofence_enter",
"geofence_ids": ["office_location"],
"time_window": {
"start": "08:00",
"end": "18:00",
"timezone": "America/New_York",
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"]
}
},
"steps": [
{
"type": "slack",
"name": "Notify reception",
"config": {
"channel": "#reception",
"message": "Visitor arrived at front entrance"
}
}
]
}
Troubleshooting
Workflow Not Triggering
Symptoms: Workflow is active but not executing when expected
Solutions:
- Verify the workflow status is "active" (not "draft" or "paused")
- Check that
is_test_modeis set tofalsefor production - Confirm geofences are correctly selected in trigger configuration
- Review location data accuracy—low accuracy points may be filtered
- Check debounce settings aren't preventing triggers
- Verify the device is sending location updates to SpatialFlow
Action Failing Repeatedly
Symptoms: Workflow executes but specific action always fails
Solutions:
- Review execution logs for detailed error messages
- Test the action endpoint independently (e.g., curl for webhooks)
- Verify integration credentials are valid and not expired
- Check webhook URL is accessible from SpatialFlow servers
- Ensure request payload is valid for the destination API
- Review timeout settings—increase if downstream API is slow
- Check rate limits on destination service
Slow Workflow Execution
Symptoms: Workflow takes longer than 2 seconds to complete
Solutions:
- Review execution timing for each step to identify bottleneck
- Increase timeout for slow webhook endpoints
- Optimize downstream API performance
- Consider parallelizing independent actions (future feature)
- Reduce payload size by removing unnecessary data
- Check for network latency between SpatialFlow and action endpoints
Template Variables Not Rendering
Symptoms: Action receives literal {{variable}} instead of actual value
Solutions:
- Verify the variable path is correct (e.g.,
trigger.device_id) - Check that the trigger data contains the expected fields
- Use the workflow tester to inspect trigger data structure
- Ensure JSON is properly formatted in webhook body
- Review template syntax documentation for correct format
Integration Not Found
Symptoms: Action fails with "Integration not found" error
Solutions:
- Verify the integration_id exists and is active
- Check that the integration belongs to your workspace
- Ensure the integration type matches the action type
- Verify the integration credentials are valid
- Verify the user has permission to use the integration
Next Steps
- Quick Start Guide: Set up your first workflow
- API Reference: Complete API documentation
- Geofences Guide: Learn about creating and managing geofences
- Signals: Anomaly detection beyond geofence enter/exit
- Workflow Automation Guide: Common patterns and testing