Routing Rule configuration
A Routing Rule decides which incoming alerts are sent to which Schedule. It references a Schedule, so create the Schedule first.
Fields
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string | Yes | — | Rule name. Cannot be empty. |
schedule_id | number | Yes | — | The target Schedule. Must reference an existing Schedule (greater than 0). |
match_mode | string | Yes | all | all (every condition must match) or any (at least one). An empty value defaults to all. |
priority | number | Yes | 0 | Lower values are evaluated first. Zero is allowed. |
description | string | No | "" | Free-text description. |
conditions | array | No | [] | List of { field, op, value } conditions to match against the alert. op is one of equals, not_equals, contains, matches, exists. See What conditions match against. |
is_active | boolean | No | true | Whether the rule is active. Can only be set when updating an existing rule, not at creation. |
What conditions match against
Conditions are evaluated after the Webhook's Transformation Rule has run, against the alert as Unit Oncall will store it. A field can be either:
- A normalized alert field —
fingerprint,title,message,severity,timestamp,labels,tags. These hold the transformed value. source— always read straight from the incoming payload'ssourcefield. A Transformation Rule cannot mapsource, so asourceentry inmappingshas no effect and asourcecondition always sees what your monitoring tool sent.- A path into the incoming payload — dot-separated, for example
custom_fields.region. These hold the value exactly as your monitoring tool sent it.
If the Webhook binds a Transformation Rule, write conditions against the transformed value. A rule that maps
P1tocriticalmeans the alert's severity iscriticalby the time routing runs, soseverity equals criticalmatches andseverity equals P1does not. Writing the pre-transformation value is easy to miss becauseseverity existsstill matches either way — the rule simply never fires and every alert falls through to the Webhook'sdefault_schedule_id.
Normalized fields always reflect the alert, including when they end up empty. For example, if tags arrives as a delimited string rather than an array and no Transformation Rule reshapes it, the alert carries no tags and a tags condition sees no tags. Use the Transformation Rule's array_delimiter option to split such a value into an array.
The exists operator asks whether the alert has that field at all, so a normalized field the alert never received — say labels on a payload that sends none — does not match exists.
The matches operator takes a regular expression, and its pattern is limited to 512 characters. The limit counts characters rather than bytes, so a pattern written in Japanese or any other non-ASCII script gets the same 512. A longer pattern — or one that is not a valid regular expression — is rejected when you save the rule, not silently ignored at routing time.
A second limit caps how large the pattern becomes once compiled: 2,000 instructions. Character count alone does not bound this, because a bounded repetition such as {100} expands into roughly that many instructions — (?:a{100}){10} is only 14 characters but compiles to about 1,000. Ordinary patterns are nowhere near the limit: a 512-character literal is about 514 instructions, and the conditions people actually write are usually under 50. You will only run into it by nesting large {n} repetitions, and the fix is to write the repetition more loosely (for example a+ or a{1,100} instead of stacking fixed counts).
Some tools send a normalized field name as an object — Prometheus and Alertmanager send labels that way. As long as no Transformation Rule produces a value for that field, the object is left untouched and dot paths into it (labels.env) keep working. Once a Transformation Rule does produce a value for the field, that value replaces the object and those dot paths stop resolving — match on the transformed field itself instead.
