Skip to main content

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

Simplified Payload

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:

  1. Name: Descriptive identifier
  2. Trigger: Geofence event that starts the workflow
  3. 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