Triggers

Workflows are started by trigger nodes or entry points. Each trigger type has its own endpoint or background process.

Workflows are started by trigger nodes or entry points. Each trigger type has its own endpoint or background process.

Trigger Nodes

Start nodes (no incoming edges) that initiate execution:

Node TypeDescription
Input (textInput)HTTP entry point. Receives body, headers, query from requests.
CronRuns on a schedule (cron expression, e.g. 0 * * * * for hourly).
Telegram TriggerStarts when Telegram sends a bot webhook update to the node-specific webhook URL.
Discord TriggerStarts when Discord sends an Interactions API webhook to the node-specific endpoint.
IMAP TriggerPolls an IMAP mailbox and starts once for each newly detected email.
Google Drive TriggerPolls a Drive folder or file and starts once per created, updated, or deleted file.
Google Sheets TriggerPolls a sheet tab and starts once per added, updated, or deleted row.
Heym TriggerStarts when Heym publishes a platform event. Events in one dispatch window arrive together as an array.
WebSocket TriggerOpens an outbound client connection to an external socket and starts on selected socket events.
File Upload TriggerMints a single-use upload URL and starts when a caller posts a large multipart file.
RabbitMQ (receive)Starts when a message is consumed from a RabbitMQ queue.
Slack TriggerStarts when Slack sends an event via the Events API webhook.

Entry Points

TriggerEndpoint / SourceAuth
Webhook/APIPOST /api/workflows/{id}/executeanonymous / jwt / header_auth
MCPPOST /api/mcp/tools/call, /message, /sseX-MCP-Key header or Authorization: Bearer (headers only)
PortalPOST /api/portal/{slug}/executePortal session token
BoardBoard card move / follow-up run into a column with a workflow chain (trigger_source="board")JWT (board owner)
CronCron scheduler (runs every 60s, evaluates cron expressions)N/A
IMAPIMAP trigger manager (leader worker, per-node polling interval)IMAP username/password
Google Drive / SheetsGoogle trigger poller (leader worker, per-node polling interval)Google OAuth2 credential
WebSocketOutbound WebSocket trigger manager (leader worker, persistent client connections)Optional per-node headers
File UploadPOST /api/file-intake/u/{token} after a slot is mintedSingle-use capability token
RabbitMQRabbitMQ consumer (leader worker)N/A
SlackPOST /api/slack/webhook/{node_id}HMAC-SHA256 signing secret
DiscordPOST /api/discord/webhook/{node_id}Ed25519 application public key
TelegramPOST /api/telegram/webhook/{node_id}Optional x-telegram-bot-api-secret-token
EditorSame as Webhook, via workflowStore.executeWorkflowJWT

Webhook / API

  • Endpoint: POST /api/workflows/{workflow_id}/execute
  • Input: Request body is passed as body to textInput nodes
  • Body mode: Workflows can use defined field-shaped examples or generic raw JSON examples in the editor and cURL dialog
  • Auth: Configured per workflow (auth_type, allow_anonymous)

See Webhooks for details on TTL, cache, rate limiting, and auth.

MCP

Workflows with mcp_enabled=true appear as tools to MCP clients. Tool name is derived from the workflow name. See MCP Tab.

Portal

Public chat UI at /chat/{slug}. See Portal for details.

Cron

The cron scheduler runs every 60 seconds, finds workflows with active cron nodes, evaluates cron expressions, and runs matching workflows. Input includes {"triggered_by": "cron"}.

IMAP

The IMAP trigger manager runs in the leader worker and checks active imapTrigger nodes on their configured pollIntervalMinutes. Each node stores an IMAP cursor (UIDVALIDITY + last seen UID). Input includes email, triggered_by: "imap", trigger_node_id, and triggered_at.

Google Drive and Google Sheets

The Google trigger poller runs in the leader worker and checks active googleDriveTrigger and googleSheetsTrigger nodes on their pollIntervalMinutes. Each node keeps a snapshot in the database: file metadata for Drive, keyed fingerprints of cells for Sheets (never cell values). Polls are claimed per node and each change is consumed with a compare-and-swap, so a change starts one run across every worker and instance. Input includes change, triggered_by ("google_drive" or "google_sheets"), trigger_node_id, and triggered_at.

Heym Platform Events

The Heym event dispatcher polls the heym_events log every 5 seconds and delivers matching events to active heymTrigger nodes. Delivery is claimed per (event, workflow, node) through a unique constraint, so an event fires exactly once per subscribing node across every worker, container, and machine. Every event claimed in one pass is delivered in a single run: input includes events (always an array, oldest first), count, triggered_by: "heym_event", trigger_node_id, and triggered_at. Only events published in the last 5 minutes are dispatched, which stops an outage from replaying a backlog; events are retained for 7 days.

WebSocket

The WebSocket trigger manager runs in the leader worker and keeps one outbound client connection per active WebSocket Trigger node. It can emit runs for onMessage, onConnected, and onClosed. Input includes eventName, url, triggered_by: "websocket", trigger_node_id, and one of message, connection, or close.

File Upload

The File Upload Trigger mints a TTL-bounded, single-use upload slot when the workflow is invoked through the API, MCP, or canvas. Uploading multipart form data to POST /api/file-intake/u/{token} consumes the slot, stores the file as a Drive file, and starts the workflow synchronously. Input includes file, uploaded_at, triggered_by: "file_upload", and upload metadata. Set Accept: text/event-stream to receive heartbeats and the final result without leaving a long-running request silent.

Telegram

Telegram sends bot webhook updates to POST /api/telegram/webhook/{node_id}. The payload is passed into the workflow as update, message, optional callback_query, sanitized headers, triggered_by, trigger_node_id, and triggered_at. If the selected credential has a secret token, Heym verifies x-telegram-bot-api-secret-token before execution.

Discord

Discord sends interaction webhooks to POST /api/discord/webhook/{node_id}. The payload is passed into the workflow as interaction, type, data, sanitized headers, triggered_by, trigger_node_id, and triggered_at. Heym verifies the request using Ed25519 and the selected discord_trigger credential's application public key before execution.

RabbitMQ

The RabbitMQ consumer starts when the leader worker initializes. Workflows with rabbitmq nodes where rabbitmqOperation === "receive" get a consumer. Input includes message_data (body, headers, routing_key, etc.) and triggered_by: "rabbitmq".

Concurrency Limit

A workflow with a concurrency limit queues production runs from every entry point above when its slots are full, first in, first out, across all instances. How a caller learns the result depends on the entry point:

Entry pointWhile the run waits
Webhook / API202 Accepted with an execution_id and a status URL
SSE streaming, Quick Drawer, Portal chatThe stream stays open and sends queued events
Portal without streamingThe request waits for the result
MCPA queued result to poll with heym_execution_status
Cron, IMAP, Google Drive / Sheets, WebSocket, RabbitMQ, Slack, Discord, Telegram, Heym events, error workflows, Dashboard run widgetsThe trigger waits for the result, as long as a run on another instance would. The run executes either way and is written to history

When the queue is full, the run does not start and history records it as queue_full. Editor test runs, sub-workflow calls (Execute node and agent workflow tools), Evals, chat build-mode test runs and review resumes are never queued. Board card runs, File Upload runs, runs started by the AI assistant's run-workflow tool, and alert notify workflows also start without waiting for a slot.

trigger_source

Execution history records trigger_source for every entry point:

ValueWhen
"API"Webhook / API call with no explicit header (default)
"Canvas"Run from the workflow editor canvas
"Quick Drawer"Run from the editor quick-drawer panel, including file runs uploaded from its drop zone
"cron"Cron scheduler
"imap"IMAP trigger manager
"google_drive"Google Drive Trigger poller
"google_sheets"Google Sheets Trigger poller
"websocket"Outbound WebSocket trigger manager
"file_upload"File Upload Trigger upload endpoint (links minted over HTTP, MCP, or the canvas)
"dashboard"Dashboard widget runs, and uploads from a file drop widget
"telegram"Telegram bot webhook
"Discord"Discord interactions webhook
"MCP"MCP tool call
"portal"Portal execute
"dashboard_chat"AI assistant chat
"AI Agents"Sub-workflow invoked by an AI agent node
"SUB_WORKFLOW"Sub-workflow invoked by an Execute Workflow node
customAny value sent in X-Trigger-Source header or trigger_source query/body param
(not set)RabbitMQ consumer

Inputs by Trigger

  • HTTP/Webhook: body, headers, query from the request
  • Cron: {"triggered_by": "cron"}
  • Telegram: update + message + optional callback_query + sanitized headers + triggered_by: "telegram" + trigger_node_id + triggered_at
  • Discord: interaction + type + data + sanitized headers + triggered_by: "Discord" + trigger_node_id + triggered_at
  • IMAP: email + triggered_by: "imap" + trigger_node_id + triggered_at
  • Google Drive / Sheets: change + triggered_by: "google_drive" or "google_sheets" + trigger_node_id + triggered_at
  • WebSocket: eventName + url + triggered_by: "websocket" + message / connection / close
  • File Upload: file + uploaded_at + triggered_by: "file_upload"
  • RabbitMQ: message_data + triggered_by: "rabbitmq"
  • Slack: event (full Slack event object) + headers (sanitized) + triggered_by: "Slack" + trigger_node_id
  • Portal: body.inputs + optional conversation_history