Automation
The Automation module is where you see (and eventually build) every workflow running in your concorbit workspace. Think of it as the control room for "when X happens, do Y".
URL: /automation
Required permission: automation.view
What you see on the page
Three sections:
1. Workflows
The custom workflows you build. Each row shows name + trigger + status (active / draft) + steps / runs / failed counts. Click a workflow name to open the list editor (steps as a vertical list with config panels); click canvas next to the name to open the visual editor (drag-and-drop graph). Both edit the same workflow, so pick whichever view you prefer for the task.
2. System automations
The hardcoded flows concorbit runs for you automatically: platform behaviour, module logic, integration hooks. These are read-only by design: they ship as code so correctness, security, and performance can be guaranteed. Grouped by the module that owns them (Core / Helpdesk / Billing / Autotask / …), each entry expands to show:
Trigger: what event fires this flow.
Description: the full explainer of when it runs and why.
Actions: the concrete things it does when triggered.
Source: the class / command path (useful for developers).
Opt-in badge: when a flow is gated behind a tenant setting (e.g.
push_invoices), the required setting is shown so you know what to enable.
Examples you'll see:
Push invoice to QuickBooks: when an invoice becomes sent AND your company is QB-linked AND
push_invoicesis on, the invoice mirrors into QB automatically.Apply SLA policy on ticket creation: when a ticket is created, the best-matching SLA policy stamps
sla_response_due_at/sla_resolution_due_at.Nightly Autotask data pull: at 03:30 every day,
autotask:sync --entity=allrefreshes companies, contacts, tickets, contracts, time entries.Trial expiry reminder emails: for tenants on trial, reminders go out at 7 / 3 / 1 / 0 days before expiry.
If your tenant hasn't enabled a module (say, Autotask), you won't see that module's flows in the list. The catalog is scoped to your active modules.
3. Available step types
The palette of building blocks (actions, conditions, delays, branches) that you can drag onto the canvas.
Actions
Send email: ad-hoc HTML email routed through your tenant SMTP with full EmailLog provenance.
Send webhook: POST/PUT/PATCH to a URL; default body is the trigger context, or use a template.
Create ticket / Update record / Assign to user: MSP-flavoured shortcuts for the helpdesk + CRM models.
Create invoice / subscription / project / purchase order / charge: billing actions on the triggering record.
Pause SLA / Resume SLA: pause and resume the SLA clock on a ticket trigger (waiting on customer, scheduled maintenance, etc.). Reason values are validated against the standard pause-reason list.
Notify user: in-app notification (bell icon + websocket) to a single user. Respects do-not-disturb and per-type opt-outs.
Post ticket reply: customer-visible reply on the triggering ticket. Optional author stamps first-response SLA and triggers the standard customer email. Leave author empty for system-authored replies (no email, no SLA effect).
Add internal note: staff-only note on the triggering ticket. Never sent to the customer, never satisfies first-response SLA. Useful for SLA-breach annotations, handoff context, or audit trails of automated decisions.
Starter templates
Every new tenant is provisioned with five starter automations so the canvas isn't empty on your first visit. The alert templates ship deactivated so you can review the body copy first; Auto-archive resolved tickets ships active because hiding closed tickets is the expected default. The notify recipient defaults to the tenant owner, so you don't need to set a user_id before activating, but you should open the Notify step and pick the on-call person, queue lead, or a merge field (such as {{ticket.assigned_to}} to page whoever owns the ticket) that fits your escalation policy.
Auto-acknowledge new tickets: posts a friendly system reply on every new ticket so customers know it landed.
SLA response breach: alert + audit note: when the breach-detection cron stamps
sla_response_breached_aton a ticket, drops an internal note describing the breach and pages the configured user.SLA resolution breach: alert + audit note: same shape for the resolution clock.
Urgent ticket created: notify queue lead: when a new ticket lands at priority
urgent, pages the configured user. The priority check is acondition:rule_groupstep inside the workflow, so non-urgent tickets exit cleanly without firing the notify.Auto-archive resolved tickets: when a ticket transitions to
resolvedorclosed, moves it to the tenant's Closed archive queue so it stays out of the default ticket list. Ships active; disable to keep closed tickets in their original queues.
The two SLA templates rely on the every-five-minutes breach-detection cron (concorbit:check-sla-breaches). The cron finds tickets whose effective due time has passed, stamps the breach timestamp atomically (so a breach only fires once across cron passes + manual sweeps), and emits the sla.response_breached / sla.resolution_breached trigger that the templates subscribe to. You don't need to add anything inside the workflow body to detect the breach; the trigger fires only when the breach has actually happened.
Conditions (branch True / False)
Field equals / contains / greater than / less than / is empty / in list / changed: compare the trigger context's fields.
field_changedchecks the column transitioned in this event.Has quote lines: quote-specific guard before invoice steps.
Delays + flow
Wait: seconds / minutes / hours / days, up to 30 days.
Continue: no-op pass-through; useful as a join point for diverging branches.
Configuring a step
When you select a step in the list editor, the right panel shows its config inputs. Nearly every step type now renders type-aware pickers instead of asking you to type field names or memorise UUIDs.
What the pickers do
Field picker lists every column on the trigger model (
status,priority,queue,assigned_to,company_id, etc.), annotated with each field's kind so you can tell an enum from a date from a user reference.Value picker adapts to whichever field you just picked. Pick
statusand the value picker becomes a dropdown of the four ticket statuses. Pickassigned_toand you get your tenant's user list. Pickpriorityand you get low/medium/high/urgent. Pick a number column and you get a number input. Free-text columns get a text input that supports merge fields.Updates picker (used by Update Record) is a repeatable list of field + value rows. Click "+ Add field" to add a row, pick the column, pick the value. Switching the field key clears the value, since the next field's kind probably doesn't match the old value anyway.
User picker is a dropdown of your active tenant users with a "Use merge field" toggle. Toggle on to type something like
{{ticket.assigned_to}}and route the action dynamically off the trigger context. Toggle back and the dropdown selection you had is preserved, so an accidental toggle isn't destructive.Static dropdowns for fixed option lists like delay units (seconds/minutes/hours/days), HTTP method (POST/PUT/PATCH), SLA pause reasons.
Merge fields
Inputs marked as "supports merge fields" (subject, body, URL, etc.) resolve {{path.to.value}} expressions against the trigger context at run time. So an email subject like Welcome {{contact.name}} becomes Welcome Alice Smith when the workflow fires for Alice's contact record. Common paths:
{{ticket.subject}},{{ticket.id}},{{ticket.priority}}: fields on the triggering ticket{{deal.title}},{{deal.value_amount}}: fields on the triggering deal{{trigger.original.status}}: the previous value (record-updated triggers){{webhook.field_name}}: payload from a webhook trigger
Advanced JSON toggle
Every schema-driven panel has a collapsible Advanced JSON section at the bottom. Useful for:
Setting keys the picker doesn't expose (legacy options the step still honours).
Pasting in a merge field where the picker wants a literal.
Debugging: see exactly what'll be persisted.
Keys you add here that aren't part of the schema are preserved when you save, so configs written before the schema-driven UI shipped don't lose data. If you change your mind, just save without touching the JSON and the original keys round-trip untouched.
What the server checks
When you save:
Field names are validated against the trigger model's columns. Typos get inline errors.
Enum values are validated against their fixed option list.
User IDs are validated as active, non-deleted users on your tenant.
Foreign-key IDs (company, contact, etc.) are validated as existing records on your tenant.
Numeric thresholds (greater-than / less-than conditions) must be a number or a merge field.
Updates Picker rows must each target a settable (non-readonly) column.
Anything that fails comes back as an inline error on that specific field. No bad state can reach the database, and crucially, no admin can route a workflow to a different tenant's user or record by guessing a UUID.
Legacy / not-yet-migrated steps
A few step types (the billing-action cluster: create invoice, charge, project, purchase order, subscription) still use the legacy text-input forms while their migration is pending. You'll know because there's no "Advanced JSON" toggle on those panels.
Run history
The Run history link (top right) takes you to /automation/runs. Every workflow execution is recorded here: started_at, finished_at, status, and (if failed) the error message. Click a run to see the per-step timeline with the input / output for each step.
What's coming
System automation detail pages: click a read-only flow to see a dedicated page with run history + the precise conditions it checks.
When to build a workflow vs request code
Use the canvas for:
Notifications & email sequences (drip, renewal reminders, welcome sequences).
Cross-module actions (deal won → create project from template + send welcome email).
Escalations (urgent ticket unacknowledged for 1h → reassign).
Approval hooks (expense > £500 → require manager approval).
Integration glue (ticket closed → Slack post).
Stay in code for:
Payment processing, auth, encryption, audit: these live in system automations for a reason.
High-frequency hooks (every request / every search indexing): the canvas layer would add latency.
FAQ
Can I edit system automations? Not directly; they're shown so you know what's running, but the logic lives in code. If you need different behaviour, request it as a feature or wait until it graduates to canvas-editable (some will over time).
Will every system automation eventually move to the canvas? The ones where customer-editable behaviour makes sense, yes (notifications, escalations, integration routing). The ones where correctness / security matters (billing, auth, audit) stay in code by design.
How do I turn off a system automation? When a flow has an opt-in badge with a toggle name (e.g. push_invoices), disable that setting in the relevant integration page. Flows without a toggle are always on; they're either always safe or aren't customer-configurable.