Triggers
Triggers determine when your workflow runs. Each workflow can have one or more triggers, and the workflow will run whenever any of its triggers fire.
Trigger types
Manual
The simplest trigger — the workflow only runs when you explicitly click “Run” in the UI.
{
"type": "manual",
"config": {}
}Use cases:
- On-demand reports
- Testing and debugging
- Workflows you run occasionally
Incoming email
Runs every time a new email arrives in your inbox.
{
"type": "incoming_email",
"config": {
"accountId": "optional-account-id"
}
}Configuration:
| Field | Required | Description |
|---|---|---|
accountId | No | Limit to a specific Gmail account. If omitted, triggers on all accounts. |
Use cases:
- Inbox filtering (Auto-inbox)
- Real-time notifications
- Immediate email processing
Incoming email triggers run on every email. Make sure your workflow handles high volume efficiently.
Email to assistant
Runs when you send an email to yourname@town.com.
{
"type": "email_to_agent",
"config": {
"accountId": "optional-account-id"
}
}Configuration:
| Field | Required | Description |
|---|---|---|
accountId | No | Limit to a specific Gmail account |
How it works:
Your assistant has an email address (e.g., alex@town.com). When you send an email to this address, workflows with this trigger are activated.
Use cases:
- Ask for help with tasks
- Forward threads for processing
- On-demand analysis
Schedule (cron)
Runs on a schedule defined by a cron expression.
{
"type": "schedule",
"config": {
"cron": "0 6 * * *",
"timezone": "America/New_York",
"accountId": "optional-account-id"
}
}Configuration:
| Field | Required | Description |
|---|---|---|
cron | Yes | Cron expression defining the schedule |
timezone | Yes | Timezone for the schedule |
accountId | No | Which account context to use |
Cron expression format
Cron expressions have 5 fields:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 7, 0 and 7 are Sunday)
│ │ │ │ │
* * * * *Common patterns:
| Expression | Description |
|---|---|
0 6 * * * | Every day at 6:00 AM |
0 9 * * 1-5 | Weekdays at 9:00 AM |
0 18 * * 5 | Every Friday at 6:00 PM |
0 0 * * 0 | Every Sunday at midnight |
0 */2 * * * | Every 2 hours |
30 8 1 * * | 8:30 AM on the 1st of each month |
0 9,17 * * 1-5 | 9 AM and 5 PM on weekdays |
Supported timezones
Common timezones:
America/New_York— Eastern TimeAmerica/Chicago— Central TimeAmerica/Denver— Mountain TimeAmerica/Los_Angeles— Pacific TimeEurope/London— UKEurope/Paris— Central EuropeAsia/Tokyo— JapanAustralia/Sydney— Australia EasternUTC— Coordinated Universal Time
Use cases:
- Morning briefings
- Daily/weekly summaries
- Scheduled reports
Calendar triggers
Town supports four Google Calendar triggers that let your workflows react to calendar events.
Calendar start
Runs before (or after) a calendar event starts.
{
"type": "calendar_start",
"config": {
"offsetMinutes": 15,
"calendarIds": ["primary"],
"accountId": "optional-account-id"
}
}Configuration:
| Field | Required | Default | Description |
|---|---|---|---|
offsetMinutes | No | 15 | Minutes before start (positive) or after start (negative) |
calendarIds | No | ["primary"] | Which calendars to watch |
accountId | No | All accounts | Limit to a specific account |
Offset examples:
| Value | Meaning |
|---|---|
15 | 15 minutes before event starts |
60 | 1 hour before event starts |
-5 | 5 minutes after event starts |
Use cases:
- Pre-meeting prep (research attendees, summarize context)
- Send meeting reminders with context
- Auto-join meeting links
Calendar end
Runs after (or before) a calendar event ends.
{
"type": "calendar_end",
"config": {
"offsetMinutes": 15,
"calendarIds": ["primary"]
}
}Use cases:
- Post-meeting follow-ups
- Summarize meeting notes and action items
- Send thank-you emails to attendees
Calendar RSVP
Runs when your RSVP status changes for an event.
{
"type": "calendar_rsvp",
"config": {
"onStatus": ["accepted", "declined"],
"calendarIds": ["primary"]
}
}Status values:
| Value | Meaning |
|---|---|
needsAction | Invited but not yet responded |
accepted | Accepted the invite |
declined | Declined the invite |
tentative | Marked as “maybe” |
Use cases:
- Prepare for newly accepted meetings
- Follow up after declining (suggest alternatives)
- Process meeting invites automatically
Calendar changed
Runs when a calendar event is updated or cancelled.
{
"type": "calendar_changed",
"config": {
"changeTypes": ["updated", "cancelled"],
"calendarIds": ["primary"]
}
}Change types:
| Value | Description |
|---|---|
updated | Event details changed (time, location, attendees, etc.) |
cancelled | Event was cancelled or deleted |
Use cases:
- Notify when meetings are cancelled
- Update your schedule when times change
- Track meeting room changes
Multiple triggers
Workflows can have multiple triggers:
{
"triggers": [
{ "type": "schedule", "config": { "cron": "0 9 * * 1", "timezone": "America/New_York" } },
{ "type": "manual", "config": {} }
]
}This workflow runs every Monday at 9 AM and whenever you click Run.
Trigger vs. mode
Triggers control when a workflow runs. Modes control how it runs (with or without approval). These are independent:
- A scheduled workflow can be approval-required (proposes actions, waits for approval)
- An incoming-email workflow can be autonomous (acts immediately)
Best practices
Match trigger frequency to workflow complexity. Simple, fast workflows work well with incoming_email. Complex, slow workflows are better on schedules.
Test with manual first. Before enabling automatic triggers, use manual to verify the workflow works correctly.
Set appropriate timezones. Schedule triggers in your local timezone so “9 AM” means 9 AM for you.