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 and call AWS Lambda when employee arrives at job site
Quick Start
The workflow examples in this guide use a simplified trigger/actions format for readability. The actual API uses a nodes and edges format. See Create Your First Workflow for the exact API schema.
Basic Workflow Structure
Every workflow has three components:
- Name: Descriptive identifier
- Trigger: Geofence event that starts the workflow
- Actions: List of actions to execute (in order)
Example:
{
"name": "Office Entry Notification",
"trigger": {
"type": "geofence_entry",
"geofence_id": "gf_office_building"
},
"actions": [
{
"type": "slack",
"config": {
"webhook_url": "https://hooks.slack.com/services/YOUR/WEBHOOK",
"message": "{{device.name}} arrived at the office"
}
}
]
}
Creating Your First Workflow
curl -X POST https://api.spatialflow.io/api/v1/workflows \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Delivery Zone Entry Alert",
"description": "Notify operations team when driver enters delivery zone",
"trigger": {
"type": "geofence_entry",
"geofence_id": "your-geofence-id"
},
"actions": [{
"type": "webhook",
"config": {
"url": "https://your-app.com/api/delivery-alerts",
"method": "POST",
"headers": {
"Content-Type": "application/json"
}
}
}]
}'
Trigger Types
Geofence Entry
Fires when a device enters a geofence boundary.
{
"trigger": {
"type": "geofence_entry",
"geofence_id": "gf_abc123"
}
}
Use cases:
- Customer arrival notifications
- Check-in automation
- Zone entry logging
Geofence Exit
Fires when a device leaves a geofence boundary.
{
"trigger": {
"type": "geofence_exit",
"geofence_id": "gf_abc123"
}
}
Use cases:
- Departure confirmations
- Dwell time calculations
- Zone exit alerts
Available Actions
1. Webhook (HTTP Request)
Send HTTP request to any URL.
{
"type": "webhook",
"config": {
"url": "https://your-app.com/webhooks/geofence-event",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"X-Custom-Header": "value"
},
"body": {
"device": "{{device.name}}",
"geofence": "{{geofence.name}}",
"event_type": "{{event.type}}"
}
}
}
Template Variables:
{{device.id}},{{device.name}}{{geofence.id}},{{geofence.name}}{{location.latitude}},{{location.longitude}}{{event.type}},{{event.timestamp}}
2. Slack Notification
Send message to Slack channel.
{
"type": "slack",
"config": {
"webhook_url": "https://hooks.slack.com/services/YOUR/WEBHOOK",
"message": "🚗 {{device.name}} entered {{geofence.name}}",
"channel": "#operations"
}
}
3. Email (SES/SendGrid)
Send email notification.
{
"type": "email",
"config": {
"to": "operations@example.com",
"subject": "Geofence Alert: {{geofence.name}}",
"body": "Device {{device.name}} entered {{geofence.name}} at {{event.timestamp}}"
}
}
4. SMS (Twilio)
Send SMS alert.
{
"type": "sms",
"config": {
"to": "+1234567890",
"message": "Alert: {{device.name}} entered {{geofence.name}}"
}
}
5. AWS Lambda
Invoke Lambda function.
{
"type": "lambda",
"config": {
"function_name": "process-geofence-event",
"payload": {
"device_id": "{{device.id}}",
"geofence_id": "{{geofence.id}}",
"event_type": "{{event.type}}"
}
}
}
6. AWS SNS
Publish to SNS topic.
{
"type": "sns",
"config": {
"topic_arn": "arn:aws:sns:us-east-1:123456789012:geofence-events",
"message": "Device {{device.name}} event at {{geofence.name}}"
}
}
7. Microsoft Teams
Send Teams notification.
{
"type": "teams",
"config": {
"webhook_url": "https://outlook.office.com/webhook/YOUR/WEBHOOK",
"title": "Geofence Alert",
"text": "{{device.name}} entered {{geofence.name}}"
}
}
8. Discord
Send Discord message.
{
"type": "discord",
"config": {
"webhook_url": "https://discord.com/api/webhooks/YOUR/WEBHOOK",
"content": "**Alert**: {{device.name}} entered {{geofence.name}}"
}
}
9. Database Operation
Execute SQL query.
{
"type": "database",
"config": {
"connection_id": "db_connection_id",
"query": "INSERT INTO geofence_events (device_id, geofence_id, event_type, timestamp) VALUES ('{{device.id}}', '{{geofence.id}}', '{{event.type}}', '{{event.timestamp}}')"
}
}
Common Workflow Patterns
Pattern 1: Multi-Channel Notification
Send alerts to multiple channels simultaneously.
{
"name": "Multi-Channel Security Alert",
"trigger": {
"type": "geofence_entry",
"geofence_id": "restricted_area_id"
},
"actions": [
{
"type": "slack",
"config": {
"webhook_url": "https://hooks.slack.com/...",
"message": "🚨 ALERT: {{device.name}} entered restricted area",
"channel": "#security"
}
},
{
"type": "email",
"config": {
"to": "security@example.com",
"subject": "Security Alert: Unauthorized Entry",
"body": "Device {{device.name}} entered restricted area at {{event.timestamp}}"
}
},
{
"type": "sms",
"config": {
"to": "+1234567890",
"message": "SECURITY ALERT: {{device.name}} entered restricted area"
}
}
]
}
Pattern 2: Webhook + Database Logging
Trigger external system and log to database.
{
"name": "Delivery Notification with Logging",
"trigger": {
"type": "geofence_entry",
"geofence_id": "delivery_zone_id"
},
"actions": [
{
"type": "webhook",
"config": {
"url": "https://your-app.com/api/delivery-started",
"method": "POST"
}
},
{
"type": "database",
"config": {
"connection_id": "main_db",
"query": "INSERT INTO delivery_logs (device_id, zone_id, entered_at) VALUES ('{{device.id}}', '{{geofence.id}}', '{{event.timestamp}}')"
}
}
]
}
Pattern 3: Lambda Processing
Use AWS Lambda for complex logic.
{
"name": "Process Vehicle Entry",
"trigger": {
"type": "geofence_entry",
"geofence_id": "depot_geofence"
},
"actions": [
{
"type": "lambda",
"config": {
"function_name": "process-vehicle-checkin",
"payload": {
"vehicle_id": "{{device.id}}",
"location": {
"lat": "{{location.latitude}}",
"lng": "{{location.longitude}}"
},
"timestamp": "{{event.timestamp}}"
}
}
}
]
}
Testing Workflows
1. Create Test Geofence
Create a small test geofence for development:
curl -X POST https://api.spatialflow.io/api/v1/geofences \
-H "Authorization: Bearer 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 "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Test Workflow",
"trigger": {
"type": "geofence_entry",
"geofence_id": "test_geofence_id"
},
"actions": [{
"type": "webhook",
"config": {
"url": "https://webhook.site/your-unique-id",
"method": "POST"
}
}]
}'
3. Send Test Location
Trigger the workflow with a test location:
curl -X POST https://api.spatialflow.io/api/v1/locations \
-H "Authorization: Bearer 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 "Authorization: Bearer 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 "Authorization: Bearer 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 "Authorization: Bearer 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",
"actions_executed": 0,
"actions_total": 1
}
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
curl -X PATCH https://api.spatialflow.io/api/v1/workflows/{workflow_id} \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active": false}'
3. Monitor Action Failures
Set up monitoring for failed actions:
# Get failed executions in last 24 hours
curl -X GET https://api.spatialflow.io/api/v1/workflows/executions?status=failed&since=24h \
-H "Authorization: Bearer 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
6. Add Metadata for Context
Store workflow context in metadata:
{
"name": "Customer Arrival Workflow",
"metadata": {
"owner": "operations-team",
"purpose": "customer_engagement",
"created_by": "john@example.com",
"cost_center": "marketing"
}
}
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 AWS Lambda/SNS for high-volume fanout
Real-World Examples
Example 1: Fleet Check-In System
{
"name": "Vehicle Depot Check-In",
"description": "Log vehicle arrivals and notify dispatch",
"trigger": {
"type": "geofence_entry",
"geofence_id": "depot_north_bay"
},
"actions": [
{
"type": "database",
"config": {
"connection_id": "fleet_db",
"query": "INSERT INTO vehicle_checkins (vehicle_id, depot_id, checkin_time) VALUES ('{{device.id}}', '{{geofence.id}}', '{{event.timestamp}}')"
}
},
{
"type": "slack",
"config": {
"webhook_url": "https://hooks.slack.com/...",
"message": "✅ Vehicle {{device.name}} checked in at {{geofence.name}}",
"channel": "#dispatch"
}
}
]
}
Example 2: Customer Proximity Marketing
{
"name": "Store Arrival - Send Welcome Offer",
"trigger": {
"type": "geofence_entry",
"geofence_id": "store_42_sf"
},
"actions": [
{
"type": "webhook",
"config": {
"url": "https://marketing-platform.com/api/send-offer",
"method": "POST",
"headers": {
"Authorization": "Bearer MARKETING_API_KEY"
},
"body": {
"customer_id": "{{device.id}}",
"store_id": "{{geofence.metadata.store_number}}",
"offer_type": "welcome_discount"
}
}
}
]
}
Example 3: Security Perimeter Alert
{
"name": "Restricted Area - Immediate Alert",
"trigger": {
"type": "geofence_entry",
"geofence_id": "construction_site_restricted"
},
"actions": [
{
"type": "sms",
"config": {
"to": "+1234567890",
"message": "⚠️ ALERT: {{device.name}} entered restricted construction area"
}
},
{
"type": "email",
"config": {
"to": "security@example.com",
"subject": "URGENT: Restricted Area Entry",
"body": "Device: {{device.name}}\nArea: {{geofence.name}}\nTime: {{event.timestamp}}\nLocation: {{location.latitude}}, {{location.longitude}}"
}
},
{
"type": "webhook",
"config": {
"url": "https://security-system.com/api/alerts",
"method": "POST"
}
}
]
}
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