> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/kortix-ai/suna/llms.txt
> Use this file to discover all available pages before exploring further.

# Triggers & Automation

> Automate agent tasks with scheduled triggers and event-based webhooks

Triggers allow you to automate agent execution based on schedules or external events. Instead of manually starting conversations, your agents can run automatically at specified times or when specific events occur.

## Trigger Types

Kortix supports two primary trigger types:

### Schedule Triggers

Run agents on a recurring schedule using cron expressions:

* Daily reports at 9 AM
* Weekly summaries every Monday
* Hourly data syncs
* Custom intervals

### Webhook Triggers

Execute agents when external events occur:

* New customer signup
* Payment received
* Form submission
* API events from third-party services

### Event Triggers

Integrate with external platforms (via Composio):

* Gmail: New email received
* Slack: Message in channel
* GitHub: Pull request opened
* Google Calendar: Event starting soon

## Creating a Schedule Trigger

<Steps>
  <Step title="Get available providers">
    List trigger providers to see available options
  </Step>

  <Step title="Configure the trigger">
    Set up cron expression, timezone, and agent prompt
  </Step>

  <Step title="Create the trigger">
    Send the configuration to create an active trigger
  </Step>
</Steps>

### List Available Providers

```bash theme={null}
GET /api/triggers/providers
```

**Response:**

```json theme={null}
[
  {
    "provider_id": "schedule",
    "name": "Schedule",
    "description": "Time-based recurring triggers",
    "trigger_type": "schedule",
    "webhook_enabled": false,
    "config_schema": {
      "type": "object",
      "properties": {
        "cron_expression": {
          "type": "string",
          "description": "Cron expression for schedule"
        },
        "timezone": {
          "type": "string",
          "default": "UTC"
        },
        "agent_prompt": {
          "type": "string"
        }
      }
    }
  }
]
```

### Create a Schedule Trigger

```bash theme={null}
POST /api/triggers/agents/{agent_id}/triggers
Content-Type: application/json

{
  "provider_id": "schedule",
  "name": "Daily Report",
  "description": "Generate daily sales report",
  "config": {
    "cron_expression": "0 9 * * *",
    "timezone": "America/New_York",
    "agent_prompt": "Generate a sales report for yesterday and send it to the team"
  }
}
```

**Response:**

```json theme={null}
{
  "trigger_id": "trigger_abc123",
  "agent_id": "agent_xyz789",
  "trigger_type": "schedule",
  "provider_id": "schedule",
  "name": "Daily Report",
  "description": "Generate daily sales report",
  "is_active": true,
  "webhook_url": null,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z",
  "config": {
    "cron_expression": "0 9 * * *",
    "timezone": "America/New_York",
    "agent_prompt": "Generate a sales report for yesterday"
  }
}
```

### Cron Expression Examples

| Expression     | Description                          |
| -------------- | ------------------------------------ |
| `0 9 * * *`    | Every day at 9:00 AM                 |
| `0 */6 * * *`  | Every 6 hours                        |
| `0 9 * * 1`    | Every Monday at 9:00 AM              |
| `*/15 * * * *` | Every 15 minutes                     |
| `0 0 1 * *`    | First day of every month at midnight |

<Note>
  All cron expressions are interpreted in the timezone specified in the trigger config. If no timezone is specified, UTC is used.
</Note>

## Viewing Upcoming Runs

Check when your scheduled triggers will run next:

```bash theme={null}
GET /api/triggers/agents/{agent_id}/upcoming-runs?limit=10
```

**Response:**

```json theme={null}
{
  "upcoming_runs": [
    {
      "trigger_id": "trigger_abc123",
      "trigger_name": "Daily Report",
      "trigger_type": "schedule",
      "next_run_time": "2024-01-16T14:00:00Z",
      "next_run_time_local": "2024-01-16T09:00:00-05:00",
      "timezone": "America/New_York",
      "cron_expression": "0 9 * * *",
      "agent_prompt": "Generate a sales report for yesterday",
      "is_active": true,
      "human_readable": "Daily at 9:00 AM EST"
    }
  ],
  "total_count": 1
}
```

### Human-Readable Schedules

The system automatically converts cron expressions to readable formats:

<CodeGroup>
  ```python utils.py theme={null}
  def get_human_readable_schedule(cron_expression: str, timezone: str) -> str:
      # "0 9 * * *" -> "Daily at 9:00 AM"
      # "0 */6 * * *" -> "Every 6 hours"
      # "0 9 * * 1" -> "Every Monday at 9:00 AM"
      pass
  ```
</CodeGroup>

## Managing Triggers

### List Agent Triggers

```bash theme={null}
GET /api/triggers/agents/{agent_id}/triggers
```

### Get Trigger Details

```bash theme={null}
GET /api/triggers/{trigger_id}
```

### Update a Trigger

```bash theme={null}
PUT /api/triggers/{trigger_id}
Content-Type: application/json

{
  "name": "Updated Daily Report",
  "config": {
    "cron_expression": "0 10 * * *",
    "timezone": "America/New_York",
    "agent_prompt": "Generate sales and marketing reports"
  },
  "is_active": true
}
```

<Warning>
  Updating the config will teardown and re-setup the trigger. This ensures the new schedule takes effect immediately.
</Warning>

### Pause/Resume a Trigger

Toggle the `is_active` flag:

```bash theme={null}
PUT /api/triggers/{trigger_id}
Content-Type: application/json

{
  "is_active": false
}
```

### Delete a Trigger

```bash theme={null}
DELETE /api/triggers/{trigger_id}
```

## Trigger Execution History

View past executions and their results:

```bash theme={null}
GET /api/triggers/{trigger_id}/executions?limit=20
```

**Response:**

```json theme={null}
{
  "executions": [
    {
      "execution_id": "run_def456",
      "thread_id": "thread_ghi789",
      "trigger_id": "trigger_abc123",
      "agent_id": "agent_xyz789",
      "status": "completed",
      "started_at": "2024-01-15T14:00:00Z",
      "completed_at": "2024-01-15T14:02:30Z",
      "error_message": null
    }
  ],
  "total_count": 15,
  "next_run_time": "2024-01-16T14:00:00Z",
  "next_run_time_local": "2024-01-16T09:00:00-05:00",
  "timezone": "America/New_York",
  "human_readable_schedule": "Daily at 9:00 AM EST"
}
```

### Execution Statuses

* `pending`: Execution queued
* `running`: Agent is currently running
* `completed`: Execution finished successfully
* `failed`: Execution encountered an error
* `cancelled`: Execution was cancelled

## Webhook Triggers

Receive webhook events to trigger agent execution:

### Webhook URL Format

```
POST /api/triggers/{trigger_id}/webhook
X-Trigger-Secret: <your-secret>
```

### Configure Webhook Secret

Set the `TRIGGER_WEBHOOK_SECRET` environment variable:

```bash theme={null}
export TRIGGER_WEBHOOK_SECRET="your-secret-key-here"
```

### Send Webhook Event

```bash theme={null}
curl -X POST https://api.kortix.com/api/triggers/trigger_abc123/webhook \
  -H "Content-Type: application/json" \
  -H "X-Trigger-Secret: your-secret-key-here" \
  -d '{
    "event": "customer.signup",
    "customer_email": "user@example.com",
    "plan": "pro"
  }'
```

**Response:**

```json theme={null}
{
  "success": true,
  "message": "Trigger processed and worker execution started",
  "execution": {
    "execution_id": "run_xyz123",
    "thread_id": "thread_new456",
    "status": "running"
  },
  "trigger_result": {
    "should_execute_agent": true,
    "agent_prompt": "Process new customer signup"
  }
}
```

### Webhook Authentication

Webhooks use HMAC-based authentication:

<CodeGroup>
  ```python api.py (lines 573-582) theme={null}
  # Verify webhook secret
  secret = os.getenv("TRIGGER_WEBHOOK_SECRET")
  if not secret:
      raise HTTPException(status_code=500, detail="Webhook secret not configured")

  incoming_secret = request.headers.get("x-trigger-secret", "")
  if not hmac.compare_digest(incoming_secret, secret):
      logger.warning(f"Invalid webhook secret for trigger {trigger_id}")
      raise HTTPException(status_code=401, detail="Unauthorized")
  ```
</CodeGroup>

## Trigger Limits by Tier

Different subscription tiers have different trigger limits:

| Tier       | Scheduled Triggers | App/Webhook Triggers |
| ---------- | ------------------ | -------------------- |
| Free       | 0                  | 0                    |
| Basic      | 2                  | 5                    |
| Pro        | 10                 | 20                   |
| Enterprise | Unlimited          | Unlimited            |

<CodeGroup>
  ```python api.py (lines 292-312) theme={null}
  # Check trigger limits
  if config.ENV_MODE != EnvMode.LOCAL:
      provider_trigger_type = await provider_service.get_provider_trigger_type(request.provider_id)
      trigger_type_str = 'scheduled' if provider_trigger_type.value == 'schedule' else 'app'
      
      from core.utils.limits_checker import check_trigger_limit
      limit_check = await check_trigger_limit(user_id, agent_id, trigger_type_str)
      
      if not limit_check['can_create']:
          error_detail = {
              "message": f"Maximum of {limit_check['limit']} {trigger_type_str} triggers allowed",
              "current_count": limit_check['current_count'],
              "limit": limit_check['limit'],
              "tier_name": limit_check['tier_name'],
              "trigger_type": trigger_type_str,
              "error_code": "TRIGGER_LIMIT_EXCEEDED"
          }
          raise HTTPException(status_code=402, detail=error_detail)
  ```
</CodeGroup>

## Trigger Service Architecture

The trigger system consists of several services:

### Trigger Service

Manages trigger lifecycle:

<CodeGroup>
  ```python trigger_service.py (lines 55-94) theme={null}
  async def create_trigger(
      self,
      agent_id: str,
      provider_id: str,
      name: str,
      config: Dict[str, Any],
      description: Optional[str] = None
  ) -> Trigger:
      trigger_id = str(uuid.uuid4())
      
      # Validate config with provider
      provider_service = get_provider_service(self._db)
      validated_config = await provider_service.validate_trigger_config(provider_id, config)
      
      trigger_type = await provider_service.get_provider_trigger_type(provider_id)
      
      trigger = Trigger(
          trigger_id=trigger_id,
          agent_id=agent_id,
          provider_id=provider_id,
          trigger_type=trigger_type,
          name=name,
          description=description,
          is_active=True,
          config=validated_config,
          created_at=now,
          updated_at=now
      )
      
      # Setup with provider (e.g., register cron job)
      setup_success = await provider_service.setup_trigger(trigger)
      if not setup_success:
          raise ValueError(f"Failed to setup trigger with provider: {provider_id}")
      
      await self._save_trigger(trigger)
      
      return trigger
  ```
</CodeGroup>

### Provider Service

Handles provider-specific logic (schedules, webhooks, etc.)

### Execution Service

Runs agents when triggers fire

## Best Practices

<AccordionGroup>
  <Accordion title="Use specific prompts">
    Provide clear, specific agent prompts in your trigger config:

    * Good: "Generate a sales report for yesterday and email it to [team@company.com](mailto:team@company.com)"
    * Bad: "Do the daily thing"
  </Accordion>

  <Accordion title="Test before scheduling">
    Run your agent manually with the planned prompt before creating a scheduled trigger. This ensures the output is what you expect.
  </Accordion>

  <Accordion title="Monitor executions">
    Regularly check execution history to ensure triggers are running successfully. Failed executions may need prompt or configuration adjustments.
  </Accordion>

  <Accordion title="Use appropriate timezones">
    Always specify the timezone in schedule configs to avoid confusion. "9 AM EST" is clearer than "2 PM UTC".
  </Accordion>

  <Accordion title="Secure webhook secrets">
    Use strong, random secrets for webhook authentication. Rotate secrets periodically for security.
  </Accordion>
</AccordionGroup>

## Version Control Integration

Triggers are synced to agent version configs:

<CodeGroup>
  ```python api.py (lines 104-150) theme={null}
  async def sync_triggers_to_version_config(agent_id: str):
      # Get current agent version
      agent_result = await client.table('agents')
          .select('current_version_id')
          .eq('agent_id', agent_id)
          .single()
          .execute()
      
      current_version_id = agent_result.data['current_version_id']
      
      # Get all triggers for this agent
      triggers_result = await client.table('agent_triggers')
          .select('*')
          .eq('agent_id', agent_id)
          .execute()
      
      triggers = triggers_result.data or []
      
      # Update version config with triggers
      version_result = await client.table('agent_versions')
          .select('config')
          .eq('version_id', current_version_id)
          .single()
          .execute()
      
      config = version_result.data.get('config', {})
      config['triggers'] = triggers
      
      await client.table('agent_versions')
          .update({'config': config})
          .eq('version_id', current_version_id)
          .execute()
      
      # Invalidate cache
      from core.cache.runtime_cache import invalidate_agent_config_cache
      await invalidate_agent_config_cache(agent_id)
  ```
</CodeGroup>

## Troubleshooting

### Trigger Not Firing

* **Check active status**: Ensure `is_active` is `true`
* **Verify cron expression**: Test the expression with a cron validator
* **Check timezone**: Ensure the timezone is correct for your location
* **Review logs**: Look for setup or execution errors

### Webhook Not Receiving Events

* **Verify secret**: Ensure the `X-Trigger-Secret` header matches your configured secret
* **Check URL**: Confirm the webhook URL is correct
* **Test manually**: Use curl to send a test event
* **Review webhook logs**: Check for authentication or processing errors

### Execution Failures

* **Review error message**: Check the `error_message` in execution history
* **Test agent prompt**: Run the agent manually with the same prompt
* **Check agent configuration**: Ensure the agent has necessary tools and permissions
* **Verify resource limits**: Ensure you haven't exceeded API rate limits

## API Reference

### Endpoints

| Method | Endpoint                              | Description                            |
| ------ | ------------------------------------- | -------------------------------------- |
| GET    | `/triggers/providers`                 | List available trigger providers       |
| GET    | `/triggers/agents/{id}/triggers`      | List agent triggers                    |
| POST   | `/triggers/agents/{id}/triggers`      | Create trigger                         |
| GET    | `/triggers/{id}`                      | Get trigger details                    |
| PUT    | `/triggers/{id}`                      | Update trigger                         |
| DELETE | `/triggers/{id}`                      | Delete trigger                         |
| GET    | `/triggers/agents/{id}/upcoming-runs` | Get upcoming scheduled runs            |
| GET    | `/triggers/{id}/executions`           | Get execution history                  |
| POST   | `/triggers/{id}/webhook`              | Receive webhook event                  |
| GET    | `/triggers/all`                       | List all user triggers (across agents) |

<Card title="See also" icon="link">
  * [Agent Configuration](/agents/agent-builder)
  * [Webhook Integration](/features/triggers)
  * [Introduction](/introduction)
</Card>
