Documentation

Automations

An automation is when something happens and what should happen next. Confirm a booking when the deposit lands. Text the customer when it is confirmed. Post new enquiries to your team chat at nine every morning.

They live at /admin/automations. You build them on the same kind of screen as your pages: the steps on the left, what each step needs on the right, and what it would do in the middle.

When it runs

Something is createdA booking arrives, an enquiry is submitted.
Something changesAny edit to a row of that type.
Something changes statusA booking becomes confirmed — and you can name which status.
A payment succeedsOnly when the platform has confirmed it with the provider, never because someone said so.
On a scheduleFive-field cron, in UTC. 0 9 * * * is nine every morning.
Someone finishes a journeyThe last step of a multi-step booking flow.

What can happen

entry.transitionMove something along a status it already declares — pending to confirmed. It will not jump to a status the type does not allow.
webhook.postPost it to somewhere you have declared: your chat, your automation tool, your own system.
http.requestCall a service you have declared, and keep what it answered for a later step.
sms.send · email.sendText or email one person.
script.runWork something out in JavaScript when the steps above cannot.

Passing values along

Give a step a name and the ones after it can read what it produced. Anywhere a step takes a value, you can write it in double braces:

{{ entry.customerName }}      the thing that triggered it
{{ steps.customer.body.id }}  what an earlier step answered
{{ site.name }}               your site

That is the whole language. There is no arithmetic, no functions and no conditions in it — on purpose. It is the same tiny language your pages use, and it cannot grow into something nobody can review. When you genuinely need to calculate, that is what the script step is for.

Try it before it is real

Press Try it. Every step that would touch the outside world tells you what it would have done and does nothing:

webhook.post: would have posted to chat
entry.transition: would have moved from pending to confirmed

It refuses rather than pretending, deliberately. A test that invented a fake response would run the rest of your automation on the invention and then report success for something that has never happened.

Reading what happened

Every run is listed with what each step did. A failed step is retried five times over about ten minutes, and then it stops with the reason on it — “the SMS was not accepted (InsufficientBalance)”. An automation that quietly stopped working is worse than one you never made, so nothing fails silently.

Sending messages

Declare an SMS or email account under integrations, and the automation names it. Until you have an account with a provider, use provider: preview — the message is written onto the run and marked not delivered, so you can build and read the whole thing before you can send anything.

One recipient per step. There is no “send to everyone who matches”, and that is a decision rather than a missing feature: an automation that texts every row is something you build once, by accident, and then explain to your customers and your provider.

The script step

When you need real calculation — split a total by line item, work out VAT, reshape what a service answered — a script step runs JavaScript over the values the pipeline has:

const net = input.lines.reduce((sum, l) => sum + l.amount, 0)
return { net, vat: Math.round(net * 0.16) }

It runs in a separate process that cannot reach anything: no network, no files, no database, no access to your integrations’ credentials, and no memory between runs. If it needs data, an earlier step fetches it; if something must be sent, a later step sends it. It gets two seconds and a fixed amount of memory, and a script that runs long is stopped.

That is the point rather than a limitation. Code that cannot reach anything is code you can let an assistant write for you.