Skip to main content

Triggers

A trigger starts a pipeline run. Each pipeline can have multiple triggers, and each trigger belongs to exactly one pipeline.

Trigger types

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-Secret header 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_hashes table

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_seconds must be an integer >= 60 (default 60)
  • input_template defaults 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:

TriggerEvent log
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.