Triggers
A trigger starts a pipeline run. Each pipeline can have multiple triggers, and each trigger belongs to exactly one pipeline.
Trigger types
| Type | Description |
|---|---|
manual |
Fire a run by hand via POST /api/v1/runs with an input payload |
webhook |
Inbound HTTP POST with HMAC secret validation |
cron |
Schedule-based, evaluated as wall-clock schedules in a named IANA timezone |
polling |
Polls a connector for a condition |
agent_signal |
Fired by another pipeline’s output |
ongoing |
Keeps a pipeline topped up to max_concurrent_runs in-flight runs |
Manual
The default way to fire a run by hand. POST /api/v1/runs with an input payload.
Webhook
An inbound HTTP POST with HMAC secret validation.
- Each trigger instance gets a system-generated
webhook_secret - Inbound path:
POST /api/v1/webhooks/<trigger_id> - Auth:
X-Modulo-Webhook-Secretheader validated with a constant-time HMAC comparison payload_mapping(JSONPath or JMESPath) maps raw payload fields to the entry agent’s input schema - required, no passthrough- Flood protection via configurable
max_concurrent_runs(default 1), tracked with a Postgres counter - Deduplication via a configurable payload dedup window (default 60s) using a
webhook_dedup_hashestable
Cron
Schedule-based triggers evaluated as wall-clock schedules in a named IANA timezone. next_fire_at is persisted in UTC.
Pipeline config
{
"schedule": "0 9 * * 1-5",
"timezone": "Europe/London",
"input_template": { "task": "daily report" }
}
Polling
Polls a connector for a condition.
Pipeline config
{
"connector_instance_id": "...",
"poll_query": "state == 'ready'",
"condition_expression": "...",
"poll_interval_seconds": 300
}
Agent signal
Fired by another pipeline’s output.
Pipeline config
{
"source_pipeline_id": "...",
"source_node_id": "...",
"signal_schema_id": "..."
}
Ongoing
Keeps a pipeline topped up to max_concurrent_runs in-flight (active or queued) runs - like a daemon or worker pool.
Pipeline config
{
"scan_interval_seconds": 60,
"input_template": {}
}
scan_interval_secondsmust be an integer >= 60 (default 60)input_templatedefaults to{}- A daily spend limit is required at create/update
- Auto-deactivates after N consecutive no-delivery terminal runs (default 5) and raises a notification
TriggerEvent log
Every trigger activation creates a TriggerEvent record with:
| Field | Description |
|---|---|
trigger_id |
The trigger that fired |
trigger_type |
manual, webhook, cron, polling, agent_signal, ongoing |
raw_payload_hash |
Hash only - never the raw payload, which may contain secrets |
received_at |
When the event was received |
validation_result |
passed | hmac_failed | schema_validation_failed | deduplicated | concurrency_limit_reached |
run_id |
The run started by this event, if any |
error_detail |
Error details on failure |
Operators can view the log and replay any logged event.
Deleting a trigger
When a trigger is deleted, in-flight runs continue against their snapshot to completion. No new runs are initiated.
Org-wide pause
An org admin can pause new trigger-initiated runs org-wide. Running pipelines continue to completion. Manual runs, MCP trigger_pipeline, and scheduled reports are never paused.