Core Concepts
Routing Rules

Routing Rules

Routing rules decide who gets notified when an event arrives. Without a matching rule, an event is stored but no notification is sent.

How matching works

When an event arrives, FlowAlert checks all enabled rules. A rule matches when its event key pattern matches the incoming event key.

Event: booking.created

Rule 1: booking.*      ✓ matches  →  notify "Booking Staff"
Rule 2: payment.*      ✗ no match
Rule 3: *              ✓ matches  →  notify "Managers"

Multiple rules can match a single event — all matched rules fire.

Event key patterns

PatternMatches
*Every event
booking.createdExactly booking.created
booking.*booking.created, booking.cancelled, etc.
payment.failedExactly payment.failed

Use specific keys in production where possible. Wildcard rules like * are useful as a catch-all during onboarding, but can cause over-notification in busier workspaces.

Rule fields

FieldDescription
NameHuman-readable label for the rule
Event key pattern*, resource.*, or an exact key like booking.created
Target groupWhich group receives the notification
Priority overrideOverride the event's priority for this rule's notifications
Requires acknowledgementIf enabled, the notification must be acknowledged by a staff member
EnabledDisabled rules are skipped entirely

Filter conditions

Filter conditions let you add payload-based matching on top of the event key pattern. If conditions are set, the rule only fires when both the event key matches and all conditions pass.

Field paths

Conditions use dot-notation paths to reference values on the incoming event:

FieldValue
titleThe event's title string
bodyThe event's body string
priorityLOW, NORMAL, HIGH, URGENT, or CRITICAL
data.fieldNameAny key inside the data object you send
data.nested.keyNested keys are supported (arbitrary depth)

For example, if you send:

{
  "event": "order.created",
  "title": "New order",
  "body": "3 items",
  "priority": "HIGH",
  "data": {
    "branch": "pattaya",
    "customer": {
      "tier": "vip"
    }
  }
}

Then data.branch resolves to "pattaya" and data.customer.tier resolves to "vip".

Operators

OperatorDescriptionExample value
equalsExact string or number matchpattaya
not_equalsDoes not equalbangkok
containsString contains substringurgent
starts_withString starts withVIP-
ends_withString ends with-critical
is_emptyField is null, undefined, or ""
is_not_emptyField has a value
one_ofMatches any of a comma-separated listpattaya,phuket,samui
greater_thanNumeric greater than1000
less_thanNumeric less than500
betweenNumeric between two values (inclusive)100,999
is_trueBoolean true
is_falseBoolean false
time_of_dayCurrent time is within range (workspace timezone)09:00-18:00
day_of_weekCurrent day matchesweekday, weekend, or monday,tuesday

AND / OR logic

Conditions are organised into groups:

  • Conditions within a group are AND'd — all must be true
  • Multiple groups are OR'd — any one group matching is enough
Group 1: data.branch = "bangkok"  AND  priority = "HIGH"
  OR
Group 2: data.branch = "phuket"   AND  priority = "HIGH"

This fires the rule if the event is HIGH priority from either Bangkok or Phuket.

End-to-end example — branch routing

Goal: Notify the Bangkok Branch Team only when an order.created event comes from the Bangkok branch.

1. Send the event from your app — using whatever event key you choose (order.created here is just an example):

POST /v1/events
{
  "event": "order.created",
  "title": "New order #1042",
  "body": "2 items · ฿890",
  "priority": "NORMAL",
  "data": {
    "branch": "pattaya",
    "order_id": "ORD-1042"
  }
}

2. Configure the routing rule:

  • Event key: order.created
  • Target group: Bangkok Branch Team
  • Add a filter condition:
    • Field: data.branch
    • Operator: equals
    • Value: pattaya

Only orders from the Bangkok branch will reach the Bangkok team. You can duplicate the rule for each branch, pointing each one at the appropriate group.

Field values are always compared as strings unless you use a numeric operator (greater_than, less_than, between). For example, data.total equals 1000 compares the string "1000", while data.total greater_than 1000 compares numerically.

Requires acknowledgement

When enabled, FlowAlert tracks whether a staff member has opened and acknowledged the notification. If no acknowledgement is received within the escalation window, the escalation policy fires (if configured).

See Acknowledgements for details.