> ## Documentation Index
> Fetch the complete documentation index at: https://docs.opencompany.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Schedulers & Triggers

> Start workflows on schedules, timers, and manual triggers

# Schedulers & Triggers

Control when and how workflows start execution.

## Available Nodes

| Node            | Type                   | Purpose                     |
| --------------- | ---------------------- | --------------------------- |
| Start           | Trigger                | Manual workflow start       |
| Cron Scheduler  | Trigger (also AI tool) | Run on a recurring schedule |
| Timer           | Action (also AI tool)  | Delay execution             |
| Python Executor | Action (also AI tool)  | Run Python code             |

***

## Start

Manually start a workflow with the Run button.

### Use Cases

* Testing workflows during development
* On-demand execution
* Entry point for manual processes

<Info>
  Every workflow needs at least one trigger node (Start, Cron Scheduler, a Webhook, or another event trigger) to begin execution.
</Info>

***

## Cron Scheduler

Run workflows on a recurring schedule. Instead of raw cron expressions, you pick a **frequency** and then set the matching interval or time-of-day fields. The Cron Scheduler is also a **dual-purpose node** -- it can be connected to an AI Agent's `input-tools` handle so agents can schedule delayed or recurring runs programmatically.

### Parameters

<ParamField path="frequency" type="select" default="minutes">
  How often the schedule fires: `seconds`, `minutes`, `hours`, `days`, `weeks`, `months`, or `once`. The other fields below appear based on the frequency you choose.
</ParamField>

<ParamField path="interval" type="number" default="30">
  Seconds between fires (5-59). Shown when frequency is `seconds`.
</ParamField>

<ParamField path="interval_minutes" type="number" default="5">
  Minutes between fires (1-59). Shown when frequency is `minutes`.
</ParamField>

<ParamField path="interval_hours" type="number" default="1">
  Hours between fires (1-23). Shown when frequency is `hours`.
</ParamField>

<ParamField path="daily_time" type="select" default="09:00">
  Time of day (HH:MM). Shown when frequency is `days`.
</ParamField>

<ParamField path="weekday" type="select" default="1">
  Day of week for weekly schedules (0=Sunday … 6=Saturday). Shown when frequency is `weeks`.
</ParamField>

<ParamField path="weekly_time" type="select" default="09:00">
  Time of day for weekly schedules. Shown when frequency is `weeks`.
</ParamField>

<ParamField path="month_day" type="select" default="1">
  Day of month (1-28, or `L` for the last day). Shown when frequency is `months`.
</ParamField>

<ParamField path="timezone" type="select" default="UTC">
  IANA timezone identifier (UTC, America/New\_York, America/Los\_Angeles, Europe/London, Europe/Berlin, Asia/Tokyo, Asia/Kolkata).
</ParamField>

### Frequency Examples

| Frequency | Fields you set                    | Result                          |
| --------- | --------------------------------- | ------------------------------- |
| `minutes` | interval\_minutes = 5             | Every 5 minutes                 |
| `hours`   | interval\_hours = 1               | Every hour                      |
| `days`    | daily\_time = 09:00               | Daily at 9am                    |
| `weeks`   | weekday = 1, weekly\_time = 09:00 | Every Monday at 9am             |
| `months`  | month\_day = 1, timezone = UTC    | Monthly on the 1st              |
| `once`    | —                                 | Fires a single time (no repeat) |

### Output

```json theme={null}
{
  "timestamp": "2026-06-15T09:00:00Z",
  "iteration": 1,
  "frequency": "days",
  "timezone": "UTC",
  "schedule": "Daily at 09:00",
  "scheduled_time": "2026-06-15T09:00:00Z",
  "triggered_at": "2026-06-15T09:00:00Z",
  "waited_seconds": 86400,
  "next_run": "Daily at 09:00",
  "message": "Triggered after 1 day, will repeat: Daily at 09:00"
}
```

### Example: Daily Report

```
[Cron (Daily at 09:00)] --> [HTTP Request] --> [AI Summary] --> [WhatsApp Send]
                            (fetch data)                          (send report)
```

***

## Timer

Add a delay between nodes. The Timer is a **dual-purpose node** -- it works both as a workflow delay node and as an AI Agent tool.

### Parameters

<ParamField path="duration" type="number" default="1">
  Delay duration (1-86400).
</ParamField>

<ParamField path="unit" type="select" default="seconds">
  Time unit: `seconds`, `minutes`, or `hours`.
</ParamField>

### Use Cases

* Rate limiting API calls
* Waiting for external processes
* Scheduling sequential actions
* **AI Agent tool** -- agents can set timers programmatically when connected to `input-tools`

### As a Workflow Node

```
[For Each Item] --> [HTTP Request] --> [Timer (1s)] --> [Next Item]
```

### As an AI Agent Tool

Connect the Timer to an agent's `input-tools` handle. The agent can then invoke the timer to introduce delays during reasoning:

```
[Timer] --(tools handle)--> [AI Agent] --> [Output]
```

<Info>
  See [AI Tools](/nodes/tools#timer-tool) for the full tool schema and LLM interaction details.
</Info>

### Output

```json theme={null}
{
  "timestamp": "2026-06-15T10:30:05Z",
  "elapsed_ms": 5000,
  "duration": 5,
  "unit": "seconds",
  "message": "Timer completed after 5 seconds"
}
```

***

## Python Executor

Run custom Python code within workflows.

### Parameters

<ParamField path="code" type="code" required>
  Python code to execute
</ParamField>

### Available Variables

| Variable     | Description                      |
| ------------ | -------------------------------- |
| `input_data` | Data from connected input node   |
| `output`     | Dictionary to set as node output |

### Example: Data Processing

```python theme={null}
# Access input data
message = input_data.get("text", "")

# Process
word_count = len(message.split())
has_question = "?" in message

# Set output
output = {
    "word_count": word_count,
    "has_question": has_question,
    "summary": f"Message has {word_count} words"
}
```

### Example: Conditional Logic

```python theme={null}
level = input_data.get("battery_level", 100)
is_charging = input_data.get("is_charging", False)

if level < 20 and not is_charging:
    output = {
        "action": "alert",
        "message": f"Low battery: {level}%"
    }
else:
    output = {
        "action": "none"
    }
```

### Example: API Response Formatting

```python theme={null}
# Parse response (json is available without importing)
data = input_data.get("data", {})
items = data.get("items", [])

# Format for output
formatted = []
for item in items:
    formatted.append({
        "name": item.get("name"),
        "price": f"${item.get('price', 0):.2f}"
    })

output = {
    "count": len(formatted),
    "items": formatted
}
```

### Available Libraries

The Python executor pre-injects a fixed set of names into the namespace:

* `math` - Mathematical functions
* `json` - JSON parsing
* `datetime`, `timedelta` - Date/time handling
* `re` - Regular expressions
* `random` - Random number generation
* `Counter`, `defaultdict` - Collections helpers

Reference them directly (for example `math.sqrt(4)`). `import` statements are not available in the sandbox; for other modules use the **Process Manager** node instead.

<Warning>
  Code runs in a sandboxed environment. File system and network access are restricted.
</Warning>

***

## Combining Schedulers

### Schedule with Delay

```
[Cron (hourly)] --> [HTTP Request] --> [Timer (5s)] --> [HTTP Request #2]
```

### Multiple Schedules

Deploy workflows with different schedules:

```
Workflow 1: [Cron (frequency: days)]  --> [Daily Report]
Workflow 2: [Cron (frequency: hours)] --> [Hourly Check]
Workflow 3: [Webhook]                 --> [On-Demand Action]
```

***

## Workflow States

After deployment, trigger nodes show their state:

| State   | Color   | Description                |
| ------- | ------- | -------------------------- |
| Idle    | Default | Waiting for next trigger   |
| Waiting | Cyan    | Actively waiting for event |
| Running | Purple  | Workflow executing         |

***

## Tips

<Tip>
  The Cron Scheduler uses a frequency dropdown -- pick `minutes`/`hours`/`days`/`weeks`/`months`/`once` and fill in the matching interval or time-of-day field. No raw cron expression is needed.
</Tip>

<Tip>
  Use **Python Executor** for conditional logic instead of multiple workflow branches.
</Tip>

<Tip>
  Add **Timer** nodes when calling rate-limited APIs repeatedly.
</Tip>

<Warning>
  Cron schedules are in **UTC** by default. Set timezone if needed.
</Warning>

***

## Troubleshooting

<Accordion title="Cron not triggering">
  * Verify workflow is **deployed** (not just saved)
  * Check that the frequency and its interval/time fields are set
  * Ensure timezone is correct
  * Check server logs for errors
</Accordion>

<Accordion title="Python code fails">
  * Check for syntax errors
  * Verify `input_data` has expected fields
  * Use `try/except` for error handling
  * Print debug info with `print()` (shows in logs)
</Accordion>

<Accordion title="Timer not working">
  * Ensure the duration is at least 1 (max 86400)
  * Check the unit (seconds vs minutes vs hours)
  * Verify node is connected properly
</Accordion>

***

## Related

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/nodes/webhooks">
    Trigger workflows via HTTP
  </Card>

  <Card title="WhatsApp" icon="whatsapp" href="/nodes/whatsapp">
    Message-triggered workflows
  </Card>
</CardGroup>
