Blog article

Automations — business logic without writing code

Published on May 1, 2023

Every business application needs custom logic. When an invoice is paid, create a receipt and email the customer. When a task is overdue by more than a week, notify its owner and its owner's manager. Every night at 2 a.m., archive closed tickets older than ninety days. When a form is submitted on the public website, create a lead, assign it to a salesperson based on the lead's region, and send an acknowledgment email. These are the kinds of rules that make an application yours rather than generic software. In most platforms, this is exactly where implementers stop and developers take over. Automations push that boundary forward — far enough that most tenants never have to cross it.

An automation has three parts. A trigger decides when it runs. A set of input parameters (optional, for automations that accept user input) decides what context it runs with. A sequence of actions decides what happens. The builder is visual — you assemble the automation from dropdowns and typed expressions — but the result is a real, auditable piece of logic that runs predictably whenever its trigger fires.

Triggers cover the events that actually matter in a business application. Record created, updated, or deleted on any type. A specific field changed, with old and new values both available to the logic. Scheduled on any cadence through the scheduler. User-initiated, when someone clicks a button in the UI. Inbound webhook, when an external system notifies the platform. Canvas form submitted, when a custom form is filled in. API event, when an integration triggers something specific. Each trigger comes with the right context — an "on record updated" trigger knows the old and new values of every changed field; an "inbound webhook" trigger knows the request headers and body; a "scheduled" trigger carries the scheduled time. Automations don't have to reach for this context; it's there.

A small but important detail: triggers can exclude system-level actions from firing them. That avoids a category of infinite-loop surprises where an automation's own changes would otherwise re-trigger it. System-initiated updates — migrations, bulk imports, or changes made by other automations marked as system — pass through without re-firing the listener. Tenant-driven changes still trigger normally. The distinction keeps long chains of automation from becoming runaway processes.

Actions are where automations become capable. The library is large and grows steadily: create, update, delete, duplicate records; patch by reference using an external identifier; convert an object from one type to another (a Lead into a Customer); list objects from a query and iterate over them — including iterating a streamed JSON response from an external source, which handles large datasets without buffering. Branching is explicit with if/else, and loops are explicit with while, continue, abort, and terminate — so control flow in the automation looks like control flow in any structured program.

Communication actions cover the channels the platform supports: send email (with templates, attachments, cc/bcc, reply-to), send SMS, send webhook (with configurable method, headers, body), send JSON response when the automation was called from an API, send in-app notification, send push notification for mobile targets, send system notification for admin alerts. Each of these is one action in the builder, and each is driven by the same expression language so personalization happens inline.

Data actions cover the platform surface: load external data from a CSV, a JSON endpoint, or a business-registry lookup; create PDF from a canvas page; store file in the repository; publish server-sent event to push real-time updates to listening clients. For automations that act in the UI context — a user clicked a button — redirect sends the user's browser to a new page; flash message shows confirmation. For administrative patterns, login as user runs the rest of the automation in another user's identity (with full audit trail), which is how certain delegated workflows can produce the right activity-log entries.

Custom scripts handle the cases that don't fit the built-in actions. A small sandboxed script — written in a server-side scripting language or in an embedded client-side language — can perform arbitrary logic with access to the automation context. That's the escape hatch, and we've spent some care making sure it's genuinely safe (sandboxed, time-limited, resource-bounded) rather than a back door. The code editor article covers the authoring side; from the automation perspective, scripts are just another action you can drop into the flow.

Input parameters turn automations into user-driven tools. Parameters are typed, they can be exposed as a form when the automation is triggered manually, and they can have conditional visibility between them — "show the reason for cancellation parameter only if the user selected Cancel as the action." The same parameter UI powers one-click UI buttons that launch automations with a small confirmation form, which is how many of the custom actions on a record get built.

SUDO is the small feature that solves the elevated-permission problem. Most of the time, an automation should run with the permissions of the user who triggered it — that's the right default, because it prevents automations from becoming privilege-escalation tools. But sometimes an automation genuinely needs to do something the triggering user can't do — write to a restricted type, access a system-only field, run a sensitive action. Marking an individual action or the whole automation as SUDO grants that elevation, and the elevation is logged so auditors can see exactly when and why the automation stepped outside the user's normal permissions.

Governance is what turns automations into a reliable operational asset. Automations can be role-restricted, so only certain roles can create or modify them. Change tracking records every edit to an automation's definition with diffs, so the history of a process is visible. Test runs let an implementer exercise an automation against sample data without side-effects, which matters when the automation writes to a live system. Run-time logs capture each execution — the context it ran against, the actions it took, any errors it hit — so debugging a production issue starts with real data rather than guesswork.

That last point deserves emphasis. Many platforms treat automation as an afterthought — a simple rule engine bolted onto a data model. Because ours was designed from the ground up as a process layer, debugging automations feels like debugging code: a log of what happened, a trace of the values at each step, a clear indication of where something went wrong. That's what lets non-developers build automations that survive contact with production.

The scheduler, canvas forms, webhooks, server-side scripting, and AI-in-automations articles are all natural companions to this one. Automations are the connective tissue between the data model and the business process, and they're the feature that, more than any other, determines how far a tenant can get without a developer in the room.