Skip to main content

Schedule Triggers

Schedule triggers execute agents autonomously on a cron schedule — no user interaction needed. Use cases: daily reports, expiration monitoring, proactive alerts.

Configuration

{
"trigger_type": "schedule",
"trigger_config": {
"cron": "0 8 * * 1-5",
"timezone": "America/Sao_Paulo",
"query_template": "List contracts expiring in the next 30 days and send a summary email to manager@company.com",
"enabled_days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"session_strategy": {
"mode": "new"
},
"output": {
"channel": "silent"
}
}
}

Schedule Config Fields

FieldTypeRequiredDescription
cronstringYesCron expression (5 or 6 fields). Example: "0 8 * * 1-5" = 8am weekdays
timezonestringNoIANA timezone (default: "America/Sao_Paulo")
query_templatestringYesThe task for the agent — natural language instruction (min 10 chars)
enabled_daysstring[]NoRestrict execution to specific days: ["monday", "friday"]. Empty = all days
session_strategyobjectNoSession behavior between executions
outputobjectNoHow to deliver the agent's response
memory_configobjectNoSave result to agent memory for context transport

Session Strategy

ModeDescriptionUse When
new (default)New session per execution (UUID)Reports, independent tasks
persistentSame session across executions (deterministic hash of trigger_id + agent_id)Monitoring with context buildup

With persistent mode, the agent accumulates context between runs — token usage decreases as the session grows (compaction handles long sessions automatically).


Output Channels

The agent executes the query_template using its configured tools. The output channel controls what happens with the agent's text response after execution.

ChannelDescriptionWhen to Use
silent (default)No external delivery — the agent handles output via its own tools (e.g., send_email)Email reports, API writes, database updates
webhookPOST JSON to a URL (no auth)Slack incoming webhooks, n8n triggers, simple automations
callbackHTTP with auth + template + transform — same mechanism as webhook async callbacksWhatsApp (Twilio), Slack API, Teams, any authenticated API

Output: silent

The agent is responsible for delivering results via its tools. The schedule trigger only executes the agent — no external delivery.

{
"output": { "channel": "silent" }
}

Example: The query_template instructs the agent to "list contracts and send by email to manager@company.com". The agent calls manage_contracts + send_email tools autonomously.

Output: webhook

Simple JSON POST to a URL. No authentication, no template.

{
"output": {
"channel": "webhook",
"webhook_url": "https://hooks.slack.com/services/xxx/yyy/zzz"
}
}

Payload sent:

{
"trigger_id": "uuid",
"agent_id": "uuid",
"success": true,
"content": "Agent response text...",
"execution_time_ms": 12000,
"iterations": 2,
"timestamp": "2026-03-18T08:00:12Z"
}

Output: callback

Full HTTP callback with authentication, custom body template, response transform, and optional chunking. Reuses the same http-callback infrastructure as webhook async execution.

{
"output": {
"channel": "callback",
"callback": {
"url": "https://api.twilio.com/2010-04-01/Accounts/ACxxx/Messages.json",
"method": "POST",
"content_type": "application/x-www-form-urlencoded",
"auth": {
"type": "basic",
"secret_ref": "TWILIO_CREDENTIALS"
},
"body_template": {
"To": "whatsapp:+556298226333",
"Body": "{{agent_response}}",
"From": "whatsapp:+14155238886"
},
"response_transform": {
"strip_markdown": true,
"max_length": 1500
}
},
"split_config": {
"enabled": true,
"max_chunk_size": 1500,
"max_chunks": 6,
"inter_chunk_delay_ms": 800
}
}
}

Template placeholders: {{agent_response}}, {{trigger_id}}, {{trigger_name}}, {{agent_id}}, {{timestamp}}

Auth types: basic (secret = base64 of user:pass), bearer (secret = token), api_key (secret = HeaderName:value), none


Memory Config — Context Transport

Problem: Schedule creates an isolated session. When the user responds later (e.g., via WhatsApp), they land in a different session. The agent loses the schedule context.

Solution: memory_config saves the schedule result to agent_memory, linked to the output recipient. On the user's next turn, the memory is automatically injected into the agent's prompt.

{
"memory_config": {
"enabled": true,
"user_key_field": "To",
"strip_prefix": "whatsapp:",
"ttl_hours": 48
}
}
FieldTypeDescription
enabledbooleanEnable/disable memory saving
user_key_fieldstringField from callback.body_template to derive user identity (e.g., "To")
strip_prefixstringPrefix to remove from the value (e.g., "whatsapp:")
ttl_hoursnumberMemory TTL in hours (1-720, default: 48). Memory auto-expires after this
max_content_lengthnumberTruncate agent response before saving (default: 1000 chars)
user_keystringFixed user key (alternative to user_key_field when there's no body_template)

Flow:

Schedule → isolated session → agent executes → result saved to agent_memory
user_key derived from output recipient
expires_at = now + ttl_hours

User responds (WhatsApp/chat) → different session → load-session recalls memory
→ "Scheduled Reports" section in prompt
→ agent responds WITH schedule context
Memory works without skill_config

Schedule reports are saved by the system, not the agent. They are recalled automatically — the agent does not need skill_config enabled for this to work.


Management Endpoints

EndpointMethodAuthDescription
GET /api/triggers/schedule/statusGETHybridActive cron jobs and execution counts
POST /api/triggers/schedule/reloadPOSTJWTReload all schedule triggers (without server restart)

Example: Daily Report via WhatsApp

Complete trigger configuration for a daily contract report delivered via WhatsApp at 8am on weekdays, with memory transport so the user can follow up:

{
"agent_id": "uuid",
"name": "Daily Contract Report",
"trigger_type": "schedule",
"trigger_config": {
"cron": "0 8 * * 1-5",
"timezone": "America/Sao_Paulo",
"query_template": "List contracts expiring in the next 30 days. Be concise: client name, value, expiration date.",
"enabled_days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"session_strategy": { "mode": "new" },
"output": {
"channel": "callback",
"callback": {
"url": "https://api.twilio.com/2010-04-01/Accounts/ACxxx/Messages.json",
"method": "POST",
"content_type": "application/x-www-form-urlencoded",
"auth": { "type": "basic", "secret_ref": "TWILIO_CREDENTIALS" },
"body_template": {
"To": "whatsapp:+556298226333",
"Body": "{{agent_response}}",
"From": "whatsapp:+14155238886"
},
"response_transform": { "strip_markdown": true, "max_length": 1500 }
}
},
"memory_config": {
"enabled": true,
"user_key_field": "To",
"strip_prefix": "whatsapp:",
"ttl_hours": 48
}
}
}

Example: Daily Report via Email (using agent tools)

The agent uses its own send_email tool — output is silent:

{
"agent_id": "uuid",
"name": "Daily Contract Report (Email)",
"trigger_type": "schedule",
"trigger_config": {
"cron": "0 8 * * 1-5",
"timezone": "America/Sao_Paulo",
"query_template": "List contracts expiring in the next 30 days. Send the result by email to manager@company.com with subject 'Daily Report: Expiring Contracts'. If none, send the email anyway saying there are no pending expirations.",
"session_strategy": { "mode": "new" },
"output": { "channel": "silent" }
}
}
Twilio WhatsApp Number Format

For outbound messages to Brazilian numbers, use 12 digits (+55 + area code + 8-digit number, without the 9th digit):

FormatExampleWorks?
+55 DD 9XXXX-XXXX (13 digits)+5562998226333NO — Twilio accepts (201) but does not deliver
+55 DD XXXX-XXXX (12 digits)+556298226333YES

Twilio Sandbox requires the recipient to send "join" to the sandbox number before receiving outbound messages. Without opt-in, messages are silently dropped (201 response, no error).