Scheduling in BotGami
Learn how to schedule messages, set reminders, and create time-based automation in your bots.
Overview
BotGami provides three types of scheduling:
| Type | Node | Best For |
|---|---|---|
| One-time (Delay) | flow.schedule | Reminders, follow-ups |
| One-time (DateTime) | flow.schedule | Appointments, deadlines |
| Recurring (Cron) | sys.cron_trigger | Daily reports, weekly summaries |
| Quick Message | flow.schedule_message | Simple delayed messages |
Quick Message Scheduling
flow.schedule_message
The easiest way to schedule a single message.
Example: Welcome Drip Campaign
User completes signup
↓
[flow.schedule_message]
Message: "👋 Welcome! Day 1: Getting started..."
DelayMs: 0 (send immediately)
↓
[flow.schedule_message]
Message: "💡 Day 2: Pro tips for success..."
DelayMs: 86400000 (24 hours)
↓
[flow.schedule_message]
Message: "🚀 Day 3: Advanced features..."
DelayMs: 172800000 (48 hours)
[Screenshot: Three schedule_message nodes showing drip campaign setup]
Time Conversion:
- 1 second = 1,000ms
- 1 minute = 60,000ms
- 1 hour = 3,600,000ms
- 1 day = 86,400,000ms
- 1 week = 604,800,000ms
Full Task Scheduling
flow.schedule + sys.scheduled_trigger
For complex flows that need to run later, use the schedule + trigger pattern:
Step 1: Create the Trigger
[sys.scheduled_trigger]
Name: "reminder_trigger"
Outputs:
NEXT → [Flow to execute]
Params → [Data passed from scheduler]
UserID → [Target user]
Step 2: Schedule the Task
[flow.schedule]
TriggerName: "reminder_trigger"
Mode: delay OR datetime
Params: { ...data to pass }
↓ TaskID
[Save TaskID to var.reminder_id]
Complete Reminder System Example
Scenario: User sets a reminder for any future time
Implementation:
--- Set Reminder Flow ---
[Command: /remind]
↓
[Parse input: "in 2 hours: Call mom"]
↓
[Calculate DelayMs: 2 * 3600000 = 7200000]
↓
[flow.schedule]
TriggerName: "send_reminder"
Mode: delay
DelayMs: 7200000
Params: {
"message": "Call mom",
"user_id": {{user.id}},
"set_at": "{{$now()}}"
}
UserID: {{user.id}}
↓ TaskID
[data.set_variable]
Scope: var
Key: active_reminder_id
Value: {{TaskID}}
↓
[Send: "✅ Reminder set for 2 hours from now"]
--- Trigger Flow (runs later) ---
[sys.scheduled_trigger]
Name: "send_reminder"
↓ Params, UserID
[action.send]
ChatID: {{UserID}}
Text: "🔔 Reminder: {{Params.message}}"
↓
[data.set_variable]
Scope: var
Key: active_reminder_id
Value: null // Clear the reminder
[Screenshot: Complete reminder flow showing both setup and trigger parts]
Canceling Schedules
flow.cancel_schedule
Users can cancel pending tasks:
Command: /cancel
[data.get_variable]
Scope: var
Key: active_reminder_id
↓ Found → TaskID
[flow.cancel_schedule]
TaskID: {{TaskID}}
↓ Success
[Send: "✅ Reminder cancelled"]
↓ NotFound
[Send: "No active reminder found"]]
Recurring Schedules (Cron)
sys.cron_trigger
For recurring tasks like daily reports or weekly summaries.
Cron Expression Format:
* * * * *
│ │ │ │ │
│ │ │ │ └─ Day of week (0-7, 0=Sunday)
│ │ │ └─── Month (1-12)
│ │ └───── Day of month (1-31)
│ └─────── Hour (0-23)
└───────── Minute (0-59)
Common Patterns:
| Schedule | Expression | Description |
|---|---|---|
| Every day at 9 AM | 0 9 * * * | Morning reports |
| Every Monday at 10 AM | 0 10 * * 1 | Weekly summary |
| Every hour | 0 * * * * | Hourly checks |
| Every 30 minutes | */30 * * * * | Frequent updates |
| Weekdays at 5 PM | 0 17 * * 1-5 | End of workday |
| First day of month | 0 9 1 * * | Monthly reports |
Example: Daily Stats Report
[sys.cron_trigger]
Name: "daily_stats"
Expression: "0 9 * * *" // Every day at 9 AM
Timezone: "America/New_York"
↓
[db.search_users]
Filter: signup_date > "yesterday"
↓ Count
[db.search_users]
Filter: last_active > "today"
↓ Count as active_count
↓
[action.send]
ChatID: [ADMIN_CHAT_ID]
Text: "📊 Daily Report for {{$now()}}:
New signups: {{Count}}
Active users today: {{active_count}}"
[Screenshot: sys.cron_trigger node showing daily 9 AM schedule]
DateTime Scheduling
Schedule for exact date/time instead of delay:
User books appointment for Dec 25, 2024 at 2 PM
[flow.schedule]
Mode: datetime
DateTime: "2024-12-25T14:00:00Z" // ISO format
TriggerName: "appointment_reminder"
Params: {
"appointment_type": "Dentist",
"location": "Main Street Clinic"
}
--- Day Before Reminder ---
[flow.schedule]
Mode: datetime
DateTime: "2024-12-24T14:00:00Z" // 24h before
TriggerName: "appointment_reminder_24h"
ISO DateTime Format:
YYYY-MM-DDTHH:MM:SSZ
2024-12-25T14:30:00Z
│ │ │ │ │ │ └─ UTC timezone
│ │ │ │ │ └──── Seconds
│ │ │ │ └─────── Minutes
│ │ │ └────────── Hours (24h)
│ │ └───────────── Day
│ └──────────────── Month
└───────────────────── Year
Helper: Use data.transform to format dates:
Expression: $now() + 86400000 // +1 day in ms
Then convert to ISO string
Use Case: Trial Expiration
User starts 7-day trial
[flow.schedule]
Mode: delay
DelayMs: 604800000 // 7 days
TriggerName: "trial_expired"
Params: {
"user_id": {{user.id}},
"trial_start": "{{$now()}}"
}
↓ TaskID
[Save to var.trial_expiry_task]
--- 7 Days Later ---
[sys.scheduled_trigger]
Name: "trial_expired"
↓
[db.get_user]
UserID: {{Params.user_id}}
↓
[Condition: User.metadata.subscribed == false]
↓ True
[Send: "⏰ Your trial has ended. Upgrade to continue!"]
↓ False
[Send: "✅ Thanks for subscribing!"]
Use Case: Appointment Booking System
Complete flow:
--- Booking Flow ---
User selects date/time from menu wizard
↓
[Save to var.appointment_date]
↓
[flow.schedule - Main reminder]
DateTime: {{var.appointment_date}}
TriggerName: "appointment"
Params: {{appointment_details}}
↓
[flow.schedule - 24h reminder]
DateTime: {{var.appointment_date - 24 hours}}
TriggerName: "appointment_reminder_24h"
↓
[flow.schedule - 1h reminder]
DateTime: {{var.appointment_date - 1 hour}}
TriggerName: "appointment_reminder_1h"
↓
[Confirm: "✅ Appointment booked! You'll get reminders."]
--- Reminders ---
[sys.scheduled_trigger: appointment_reminder_24h]
↓
[Send: "📅 Tomorrow: {{Params.service}} at {{Params.time}}"]
[sys.scheduled_trigger: appointment_reminder_1h]
↓
[Send: "⏰ In 1 hour: {{Params.service}}"]
[sys.scheduled_trigger: appointment]
↓
[Send: "It's time for your {{Params.service}} appointment!"]
Best Practices
1. Store Task IDs for Cancellation
✅ Save TaskID to var.*
✅ Allow users to cancel with /cancel command
2. Handle Failed Schedules
[flow.schedule]
↓ NEXT
[Success path]
↓ Error
[Log + notify admin]
3. Timezone Awareness
[sys.cron_trigger]
Timezone: "America/New_York" // Specify user's timezone
4. Repeat Counts
[flow.schedule]
RepeatCount: 0 // One-time
RepeatCount: 3 // Repeat 3 times
RepeatCount: -1 // Infinite (use with cron instead)
5. Clean Up Expired Tasks
Store all TaskIDs in array
On completion, remove from array
Periodically check and cancel stale tasks
Common Patterns
Pattern 1: Nudge Sequence
User doesn't Complete action after 3 days
↓
[Schedule +3 days] "Hey, still interested?"
[Schedule +7 days] "Last chance! 50% off"
[Schedule +14 days] "We miss you!"
Pattern 2: Daily Digest
[sys.cron_trigger: "0 8 * * *"] // Daily 8 AM
↓
[db.search_users with tags contains "subscribed"]
↓
[For each user]
↓
[Generate personalized digest]
↓
[Send to each subscribed user]
Pattern 3: Event Countdown
Event in 7 days
[Schedule +0d]: "Event in 7 days!"
[Schedule +4d]: "Event in 3 days!"
[Schedule +6d]: "Event tomorrow!"
[Schedule +7d]: "Event starting now!"
Troubleshooting
Issue: Scheduled task didn't fire
Check:
- Trigger name matches exactly
- DateTime is in future
- Bot is running/active
Issue: Can't cancel task
Check:
- TaskID stored correctly
- Task hasn't already executed
- Task wasn't manually canceled
Issue: Wrong timezone
Fix: Always specify timezone in cron triggers
Quick Reference
| Need | Use |
|---|---|
| Simple delayed message | flow.schedule_message |
| Complex delayed flow | flow.schedule + sys.scheduled_trigger |
| Recurring (daily/weekly) | sys.cron_trigger |
| Cancel task | flow.cancel_schedule |
Next Steps
- Flow Control Nodes → — See all scheduling nodes
- Cron Expression Builder — Visual cron editor