Appearance
Workflows
PSA → Workflows is the single home for everything that fires automatically when something happens on a ticket. Four sub-pages live underneath:
- Ticket rules — your custom "when X, do Y" automations.
- Notification templates — reusable email bodies referenced by rules and system notifications.
- System notifications — the four built-in ticket notifications (auto-ack, public reply, comment-to-assignee, comment-to-watchers).
- Audit log — every rule firing, why it matched, what happened. Per-rule for now; org-wide audit page is on the roadmap.
Before this hub existed, these surfaces were scattered across three menus. If you're coming from an older version of OpsMerge and look for "Settings → PSA → Notifications" or "Settings → PSA → Rules", the URLs still redirect — but the canonical home is here now.
Ticket rules
A rule has three parts:
- Trigger — what kicks it off. Six choices:
ticket.created— a new ticket lands (from email, portal, API, or manual creation).ticket.updated— a field changes on an existing ticket.ticket.commented— someone posts a comment (public or internal).ticket.sla_warning— the ticket is approaching an SLA breach.ticket.scheduled_stale— the ticket has been idle for N days (you set N).ticket.scheduled_customer_silence— the customer hasn't replied for N days.
- Conditions — a tree of AND/OR groups. Each leaf compares one ticket field (status, priority, client, queue, requester, subject, etc.) with an operator (
=,!=,in,is_empty,changed, and so on). Leave the conditions empty and the rule matches every event of its trigger kind. - Actions — what to do. Thirteen choices, each with its own form:
send_email— render a notification template and send it to one or more recipients (literal address,{{.requester.email}},{{.watchers}}, a specific user, etc.).send_webhook— POST a JSON payload to a URL you supply.assign_to_user,assign_to_team,assign_round_robin— change the assignee.set_status,set_priority,set_category— patch the ticket.add_note— append an internal note as the rule's audit trail.escalate_to_team— bump the ticket up the priority + assignment chain.create_child_ticket— spin off a related ticket linked back to this one.run_ai_action— sentiment, summarise, draft reply, or classify.spawn_project_from_template— kick off a project using a template.
The list page shows each rule with its trigger, last-fired timestamp, and a toggle. Click into a rule to edit conditions or actions; the dry-run panel on the right lets you test the rule against an existing ticket before you save.
Worked example — auto-route by client
When a new ticket comes in from Acme, assign it to Alice and send her an internal note.
- Trigger:
ticket.created. - Conditions:
client_id=Acme. - Actions:
assign_to_userAlice;add_note"Auto-routed via Acme rule."
Save. Next ticket from Acme will land assigned to Alice, with the note already attached.
Worked example — escalate stale critical tickets
If a Critical ticket has been Open for 24 hours with no response, email the manager.
- Trigger:
ticket.scheduled_stale. - Conditions:
priority_level=urgentANDstatus=openANDfirst_responded_atis_empty. - Actions:
send_emailtemplate = your "Stale critical" template, recipient =[email protected].
Set the rule's stale_days config to 1. Save. The periodic worker checks every 60 seconds.
Rule guards
- Cooldown — minimum gap between fires per ticket (e.g. 3600 seconds = "don't email me about this same ticket more than once an hour").
- Max fires per ticket — lifetime cap (e.g. 1 = "fire exactly once, ever, for this ticket").
- Business hours — only fire between 09:00 and 17:00 on weekdays (configurable per-tenant in the rule's advanced section).
- Throttle table — for
send_emailactions, a per-(org, recipient, template) throttle prevents accidentally mail-bombing one address.
Notification templates
Templates are reusable email bodies that rules pick by name. They live at PSA → Workflows → Notification Templates. The underlying storage is shared with the asset-alert side — see Alert templates for the full picture of how one table feeds four different engines.
Each template has:
- Name — what rules pick it by.
- Kind —
ticket_notification,custom, or (separately)asset_alert. Asset-alert templates live on a different page (/alerts/templates) and drive the alert engine, not the PSA rules engine. - Subject template — the email Subject line, with placeholders.
- Body template — the email body. Choose
text(plain text, no escaping) orhtml(auto-escaped variables, intended for the WYSIWYG editor). - From override — optionally templatised, e.g.
support@{{.tenant_domain}}. - Recipients — default recipient list (rules can override).
- System lock — the four built-in system templates have a lock badge and can't be deleted, though you can freely edit the subject and body.
Variables available in send_email rules
Templates use Go's text/template and html/template syntax. The variables are flat (single-dotted), not nested. Common placeholders:
{{.ticket_ref}}— the human ticket reference, e.g. "INC-1042". The prefix is derived from the ticket type (INC/REQ/PRB/CHG/TSKby default); per-tenant prefix overrides are stored per org (migration 000306){{.ticket_number}}— the short threading id used in subject prefixes (see below); not the human reference{{.ticket_subject}}— subject line{{.ticket_priority}}— current priority{{.ticket_status}}— current status{{.ticket_url}}— link to the ticket{{.org_name}}{{.requester_name}}/{{.requester_email}}{{.assignee_name}}/{{.assignee_email}}{{.comment_body}}— forticket.commentedrules ({{.comment_body_html}}for HTML templates){{.comment_author_name}}{{.watchers}}— expands to the list of watcher email addresses (used as a recipient, not a body variable)
Use the dry-run panel on the rule editor to see exactly what gets rendered before you save.
Subject prefix and threading
Keep [#{{.ticket_number}}] in the subject of any client-facing template. Without it, client replies don't thread back correctly when no Reply-To match exists — the inbound matcher parses that [#<id>] token from the subject as a fallback. Use {{.ticket_number}} here, not {{.ticket_ref}}: the human reference (e.g. "INC-1042") is display-only and isn't recognised by the threading parser.
System notifications
Four built-in notifications ship enabled-or-disabled-by-default:
| System notification | Fires on | Default state |
|---|---|---|
| Auto-acknowledge new email ticket | Inbound email creates a new ticket | Disabled |
| Notify requester on public reply | Staff posts a public comment | Disabled |
| Notify assignee on comment | Anyone other than the assignee comments | Disabled |
| Notify watchers on comment | Any comment posted | Disabled |
Each system notification is implemented as a (template, rule) pair you can edit at PSA → Workflows → System Notifications. The rule itself isn't editable on this page (it's owned by the system), but the template is — change the subject, body, recipient pattern, and per-recipient throttle to taste.
RFC 3834 mail-loop guard
Inbound mail flagged Auto-Submitted: auto-replied or Precedence: bulk (out-of-office replies, mailing lists, other auto-responders) is detected on receipt. The auto-ack rule sees the flag and skips the outbound — preventing the infamous "out-of-office bounces auto-ack bounces out-of-office..." loop. You don't have to configure this. It's on.
Per-recipient throttle
outbound_auto_reply_throttle keeps a row per (org, recipient, system_key, last_sent_at). If the same recipient triggers the same system notification twice within the configured cooldown, the second send is dropped. Default cooldown is 1 hour. Tune in the template's advanced section.
Monitoring workflows
A separate engine fires on RMM events rather than PSA tickets. It lives at Monitoring → Workflows (was "Triggers" pre-reorg). Triggers there are check_failure, agent_status, eventlog, schedule, and webhook_inbound. Actions include run_script, create_alert, fire_webhook, and create_ticket — so a check failing can create a PSA ticket which a rule on this page then reacts to.
Full reference at Monitoring → Workflows.
Audit log
Every rule firing writes a row to ticket_rule_runs capturing:
- Which rule fired
- Which ticket it matched
- Timestamp
- Per-action outcome (success / error / skipped) with detail
- Whether it was a dry-run preview or a real fire
For now the audit drawer on each rule's edit page is the way to view this. A dedicated PSA → Workflows → Audit log page that aggregates across all rules is on the roadmap.
Common patterns
"Auto-ack should look like our brand"
PSA → Workflows → System Notifications → Auto-acknowledge new email ticket. Edit the subject and body. Keep the variables that matter ({{.ticket_ref}}, {{.ticket_url}}) and the [#{{.ticket_number}}] subject prefix so replies still thread.
"Different auto-ack per client"
Don't edit the system auto-ack. Instead, create a custom rule:
- PSA → Workflows → Ticket Rules → New rule.
- Trigger:
ticket.created. - Conditions:
client_id=X ANDsource_type=email. - Action:
send_emailtemplate = your client-specific template. - Disable the system auto-ack for tickets matching this client, or set a high enough cooldown that the custom rule "wins" by firing first.
"Suppress all comment notifications for a specific client"
Two options:
- Disable the public-reply system notification at the contact level (set "Don't email this contact on comments" on the contact record).
- Create a custom rule: trigger
ticket.commented, conditionsclient_id = X, actionset_statusto "no-op", and use rule priorities so this rule runs before the system one (rules run in priority order; lower priority number fires first).
"Round-robin assignment within a team"
PSA → Workflows → Ticket Rules → New rule. Trigger ticket.created. Conditions: whatever filters this to the team's relevant queue. Action: assign_round_robin. The rule tracks state in config.round_robin_next_idx and increments atomically, so concurrent ticket creations don't collide.
Migration from older versions
If you're on an older build of OpsMerge:
Settings → PSA → Rules→ moved toPSA → Workflows → Ticket Rules. Legacy URL still redirects.Settings → PSA → Notifications(tab) → moved toPSA → Workflows → System Notifications.Alerts → Templates→ still there for asset-alert templates only. Notification templates moved toPSA → Workflows → Notification Templates.Triggers(under Automation) → moved toMonitoring → Workflows.Settings → Notifications(Slack/Teams/Discord channels) → renamedSettings → Notification Channels.
All old URLs redirect, so KB articles, bookmarks, and emailed deep-links continue to resolve.
Common issues
A rule fires but the email doesn't arrive. Check the per-rule audit drawer. If the action shows "auto-reply suppressed", the RFC 3834 guard fired or the recipient was on the noreply pattern blocklist. If it shows a render error, check the template syntax in the dry-run panel.
"Template not found" in the audit. The rule's template_key refers to a template name or system_key that doesn't exist. Open the rule, edit the send_email action, repick a template.
My custom kind=asset_alert template doesn't appear under PSA Workflows. Correct — that surface filters to ticket_notification and custom. Asset-alert templates power the alert engine and live at Alerts → Templates.
Variables show literal {{.ticket.subject}} in the email. Either you used the wrong template syntax (Handlebars rather than Go template), or the variable doesn't exist in the rule's render context. The dry-run panel surfaces the actual variable shape.
Next
- Notifications — older overview, still useful for the conceptual flow
- Email gateway — outbound mechanics, how rendered emails leave the building
- Tickets — the things rules act on