Workflows
Automations you build on a visual canvas — a trigger plus action and condition nodes wired into a branching graph. This is the reference for every node type.
Building on the canvas
Open a project's Workflows tab and open (or create) a workflow. You get a canvas with three things to work with:
Drag a node from the left palette onto the canvas. Connecta node's bottom handle to another node's top handle to define the order. Double-click any node to open its editor. Select a node or edge and press Delete to remove it. Hit Save when done — the whole graph is the source of truth.
It runs as a DAG: each node fires once its incoming path resolves. A condition node branches on two outputs — the green (true) and red (false)handles — so you can build real if/else and parallel flows, not just a straight line. The payload (the trigger's data, plus anything a query_db_rows writes) is threaded through every node.
Triggers
Exactly one trigger per workflow — the entry point. Configure it by double-clicking the trigger node (that's where the webhook URL and signing secret live).
webhookFires when an external system POSTs to the workflow's URL. Sign the body HMAC-SHA256 with the secret (X-Coagentic-Signature); rotate the secret from the trigger node.cronFires on a schedule.form_submitFires when a visitor submits an HTML form on your site (POST /forms/<subdomain>).db_changeFires when a row in a project table is inserted, updated, or deleted.analytics_thresholdFires when site traffic crosses a target (checked every 5 min, cools down for the window).inbound_emailFires when mail arrives at your tenant subdomain address.integration_eventFires when another service calls in — your payment provider, your shop, your ticketing system. Point it at this workflow's webhook URL and describe how it signs its requests; nothing here is specific to any vendor. Use mode 'none' only if the service cannot sign at all, and treat the URL as the secret when you do.Condition node
A condition evaluates one field of the payload and branches. Its true handle runs when the test passes, the false handle when it fails. Config is field (a payload path like amount), operator, and value.
equals / not_equalsExact match (or not) against the value.existsThe field is present and non-null.containsString includes, or array includes, the value.gt / gte / lt / lteNumeric greater/less-than comparisons.Action nodes
Each action node does one thing when its path is reached. Any field can reference earlier data with {{path}} templating — e.g. a Send email body of New order for {{current_value}}.
send_emailSend an email.send_smsSend an SMS via your connected Twilio.send_whatsappSend a WhatsApp message via Twilio.call_integrationCall one of the project's saved connections (Integrations → Any HTTP API). Give the connection and a path relative to its base URL — the address and the key come from the connection, so no secret is typed into the workflow. Non-2xx fails the step unless listed in allow_status.http_requestCall any HTTP endpoint (SSRF-guarded — private/internal addresses are blocked). Anything outside 2xx fails the step; list the codes you mean to accept in allow_status.insert_db_rowInsert a row into a project table.update_db_rowUpdate a row by id.query_db_rowsRead rows onto the payload so later nodes can reference them.delete_db_rowDelete a row by id.platform_create_checkoutCreate a Polar checkout (platform-managed).polar_create_checkoutCreate a Polar checkout (your own Polar).platform_create_refundRefund a Polar order.platform_cancel_subscriptionCancel a subscription.platform_balanceRead your Polar balance.upload_to_storageUpload data to object storage (R2 / S3).send_verification_codeSend a phone OTP (your Twilio Verify).check_verification_codeCheck a phone OTP.ask_agentWake one of your team's agents to handle the task. It runs read-only and saves its output as a DRAFT for you to review (Activity → Drafts) — nothing is sent or acted on automatically. Writes {{agent_reply}} + {{agent_draft_id}} for downstream nodes.Template variables
Any string field on an action — to, subject, body, message, url — can pull in live data with {{path}}. An unknown path renders empty, so stick to the ones below.
Always available — no upstream step needed, even for a bare cron trigger:
{{project.name}},{{project.subdomain}},{{project.url}}{{date}}(today, YYYY-MM-DD) ·{{now}}(full timestamp){{traffic.pageviews}},{{traffic.visitors}}(alias{{traffic.unique_visitors}}),{{traffic.sessions}}— today's site traffic{{vars.<key>}}— your own custom variables, defined on the project's Email → Variables tab (or by the assistant). A variable can be a fixed value (e.g.{{vars.support_email}}) or one computed live from your database (e.g.{{vars.orders_today}}).
From the trigger — depends on the trigger type:
form_submit&webhook→ the posted fields are top-level, e.g.{{email}},{{name}},{{message}}inbound_email→{{inbound.from}},{{inbound.to}},{{inbound.subject}},{{inbound.text}},{{inbound.receivedAt}}db_change→{{row.<column>}},{{kind}},{{table}},{{tableId}}cron(Schedule) →{{trigger}},{{firedAt}}(when it ran)analytics_threshold→{{metric}},{{current_value}},{{threshold}},{{comparison}},{{window_minutes}},{{triggered_at}}- a
query_db_rowsaction → writes its rows under theresult_keyyou set
Example daily-report email body: Pageviews today: {{traffic.pageviews}} · Visitors: {{traffic.unique_visitors}}
Build it with the agent
Everything above, the assistant can do for you. Describe the automation in the agent panel ("when an order over $100 comes in, email me, otherwise just log it") and it builds the same graph with create_workflow — branching included. It can also update_workflow, get_workflow, and delete_workflow. Whatever the agent builds opens and runs identically on the canvas, so you can hand-tune it afterwards.