Skip to main content

Cases

Cases are a supported entity type in Notification Center. When Case lifecycle events occur, Notification Center generates notification requests that can be routed to external destinations.

Supported entity subtypes

An entity subtype adds a layer of granularity to an entity type. For Cases, an entity subtype consists of two elements: state and status.

EntityStateStatusDescription
CasesCREATEDOPENA new Case has been created and is open for handling.
CasesACTIVEOPENThe Case is actively in progress and remains open.
CasesACTIVEACKNOWLEDGEDThe Case is being handled and has been explicitly acknowledged.
CasesRESOLVEDCLOSEDThe Case has been resolved and closed, with optional resolution metadata.

All supported entity subtypes can be found in the Cases API reference.

Notification triggers

Case routing rules support the following lifecycle triggers:

TriggerWhen it fires
ActivatedImpact is confirmed and the Case becomes active
AcknowledgedSomeone takes ownership of the Case
ResolvedUnderlying indicators are healthy and the Case is resolved
ClosedFollow-ups are complete and the Case is fully finished
Priority changedThe Case priority level is updated
Assignee changedThe Case is assigned or reassigned

These triggers are configured in Case routing rules within a router. Each trigger can be routed to a different destination, allowing teams to control which stakeholders are notified at each stage of the incident lifecycle.

Routing and Ownership Tags

Cases use Ownership Tags (environment, service, and team) for routing. These are the same attributes used in Infra Explorer Ownership Tags, so labels already defined on your infrastructure carry through to notification routing.

Unlike alerts, which use the routing.<key>: <value> prefix, Cases inherit their routing labels from the Ownership Tags assigned to the underlying infrastructure.

Template variable reference

Every field a Case notification exposes to a preset template, organized by namespace. Use these paths in preset message bodies and routing rule conditions (Tera syntax).

Namespaces

A Case notification exposes three namespaces plus a few flat shortcuts:

NamespaceWhat it holdsUse it for
case.*The incident itself — a snapshot at send time: title, status, priority, assignee, indicators, KPI breaches, Olly analysis, and all deep links.Message content: "what is this incident?"
caseMetadata.*Why you are being notified right now — the lifecycle event and exactly what changed.Reason lines, branching the template per event.
_context.*The notification envelope — shared by all entity types (alerts and cases): source type, routing labels, team, and trigger.Routing conditions, cross-entity presets.
Top-levelFlat shortcuts: correlationKey, name, priority (mirror case.id / case.title / case.priority).Integrations that expect a flat field, such as dedup keys.

In short: case is the incident, caseMetadata is why you were notified now, and _context is how it reached you.

Reading arrays and the [0] rule

Arrays are not usable bare. Rendering an array directly (for example {{ case.kpiBreaches.breachedKpis }}) produces unusable output, and referencing a variable the Case does not have (for example {{ case.impactedEntities }} on a Case with no impacted entities) fails the entire render with Variable case.impactedEntities not found. Always index an array with [0], iterate it with a {% for %} loop, or serialize it with json_encode.

ShapePathsHow to read
True arraycase.indicators.alerts / .genericIndicators / .prometheusAlerts, case.kpiBreaches.breachedKpis, case.impactedEntities, case.externalReferences, case.notificationDeliveries, remediationRecommendations, entityLinks[0].field, a {% for %} loop, or json_encode
Array-shaped map {key: [values]}case.labels, case.groupings, _context.entityLabels, _context.grouping["key"][0] — without [0] the brackets leak into the message (["platform"] instead of platform)
Plain object (no index)case.links, case.indicators.alerts[0].labels / .groupingsdirect field access

Safe patterns:

{# per-variable guard #}
{% for e in case.impactedEntities | default(value=[]) %}{{ e.name }}: {{ e.url }}
{% endfor %}

{# dump an array as JSON #}
{{ case.kpiBreaches.breachedKpis | json_encode() | safe }}
Tip

Autocomplete in the preset editor only reveals array-element fields after an index. case.impactedEntities. suggests nothing, while case.impactedEntities[0]. suggests kind, name, url, and so on.

case.* — the Case object

PathDescriptionExample
case.idUnique Case ID (UUID).76c411be-ff4d-4fb1-a987-5fce042deaaf
case.titleCase title.Test Case
case.descriptionCase description.This is the description of the Test Case
case.statusCase status. Values: PENDING_ACTIVATION, ACTIVE, ACKNOWLEDGED, RESOLVED, CLOSED.ACKNOWLEDGED
case.priorityPriority P1P5.P4
case.categoryCase category.AVAILABILITY
case.urlDeep link to the Case in Coralogix.https://team.coralogix.com/#/cases?id=CASE-123
case.links.watchCaseDeep link — watch the Case....?id=CASE-123
case.links.assignToMeDeep link — assign to me....?id=CASE-123&action=assign
case.links.ackCaseDeep link — acknowledge....?id=CASE-123&action=ack
case.links.resolveCaseDeep link — resolve....?id=CASE-123&action=resolve
case.links.closeCaseDeep link — close....?id=CASE-123&action=close
case.assigneeCurrent assignee — tagged union, see Actor tagged unions.{{ case.assignee.coralogixUser.userEmail }}
case.createdAtCreated (ISO 8601).2025-08-10T09:15:00Z
case.updatedAtLast updated.2025-08-10T09:25:00Z
case.acknowledgedAt / case.acknowledgedByAck time and actor (tagged union).{{ case.acknowledgedBy.coralogixUser.userEmail }}
case.closedAt / case.closedByClose time and actor (tagged union).2025-08-11T09:15:00Z
case.resolutionDetailsresolutionReason, resolvedAt, resolvedBy (tagged union).{{ case.resolutionDetails.resolutionReason }}
case.labelsCase labels. Array-shaped {key: [values]} — index [0].{{ case.labels["team"][0] }}
case.groupingsAggregated group-by values across indicators. Array-shaped.{{ case.groupings["service"][0] }}
case.indicatorsThe signals behind the Case — three arrays: alerts, genericIndicators, prometheusAlerts.{{ case.indicators.alerts[0].title }}
case.kpiBreaches.breachedKpis[]KPI breaches: id, createdAt, kpiType (TIME_TO_ACKNOWLEDGE, TIME_TO_RESOLVE, TIME_TO_UPDATE), casePriority, thresholdMinutes, breachedAt, mitigatedAt, breachStatus.{{ case.kpiBreaches.breachedKpis[0].breachStatus }}
case.ollyAnalysisOlly investigation: investigationSummary, rootCause, rootCauseConfidence (LOW / MEDIUM / HIGH), remediationRecommendations[], generatedAt.{{ case.ollyAnalysis.rootCause }}
case.impactedEntities[]Impacted entities: kind, language, name, system, url (deep link to the entity). Guard with default.{% for e in case.impactedEntities %}{{ e.name }}{% endfor %}
case.externalReferences[]Linked external items such as tickets: externalId, url, vendor.{{ case.externalReferences[0].url }}
case.notificationDeliveries[]Notifications already delivered for this Case: label, url, vendor.{{ case.notificationDeliveries[0].url }}

Alert indicators — case.indicators.alerts[0].*

A Case can hold multiple indicators — always index with [0] or loop.

Path (under case.indicators.alerts[0].)DescriptionExample
instanceIdThe specific alert event.instance-id-1
alertDefinitionIdStable alert-definition ID.987e4567-e89b-...
alertDefinitionVersionIdVersioned definition ID.ver12345-6789-...
titleAlert title.Test CPU Alert
descriptionAlert description.Triggers when average CPU usage...
alertTypeAlert type.METRIC_THRESHOLD
priorityAlert priority.P4
stateLifecycle state.TRIGGERED / RESOLVED
isNoDataNo-data alert flag.false
groupingTypeGrouping mode.COMBINATION_ALERT
groupByKeysGroup-by keys.["service", "region"]
groupingsGroup-by values — object, not array-shaped.{"service": "payment-api"}
labelsAlert labels — object, not array-shaped.{"metric": "cpu", "team": "platform"}
timeWindowEvaluation window, in seconds.300
thresholdConfigured threshold.80.0
triggeredAt / resolvedAtTrigger and resolve times.2025-08-10T09:14:00Z / null
alertQuery.queryStringThe alert query.avg(node_cpu_seconds_total{...}) > 0.8
alertQuery.typeQuery type.ALERT_QUERY_PROMQL
details.fromTimestamp / .toTimestampViolation window.2025-08-10T09:09:00Z
details.countOverThresholdMatches over threshold.12
details.valueOverThresholdValue that crossed the threshold.83.7
details.relativeHitCountRatio-alert denominator count.null
details.uniqueCountValuesListUnique-count alerts.null
details.logExample.*Sample log: text, applicationName, subsystemName, service, ipAddress, computerName, threadId, timestamp, category, logId.ERROR: CPU usage at 83.7%...

Other indicator types

PathFields
case.indicators.genericIndicators[0].id, externalId, indicatorType, status, priority, labels, lastTriggeredAt, lastResolvedAt, entityLinks[] (each: url)
case.indicators.prometheusAlerts[0].alertGroupId, alerts, externalUrl, groupLabels, priority, receivedAt, receiver, status, updatedAt

caseMetadata.* — why this notification fired

PathDescriptionExample
caseMetadata.notificationReasonLifecycle event that fired the notification. Values: caseActivated, caseUpdated, caseResolved, caseClosed.caseClosed
caseMetadata.changeWhat changed — a tagged union on $type. Fields across variants: $type, previousStatus / currentStatus, previousPriority / currentPriority, previousAssignee / currentAssignee, kpiType, thresholdMinutes. Only the fields matching $type are set.{"$type": "statusChanged", "previousStatus": "ACTIVE", "currentStatus": "CLOSED"}

Actor tagged unions

case.assignee, case.acknowledgedBy, case.closedBy, and case.resolutionDetails.resolvedBy are tagged unions: a $type discriminator plus one inner object. Check $type before reading inner fields.

$typeFields
coralogixUseruserEmail
serviceNowUseruserEmail
apiKeykeyName
slackUsercoralogixUserEmail, slackUserEmail, displayName
pagerDutyUsercoralogixUserEmail, pagerDutyUserEmail, displayName
microsoftTeamsUsercoralogixUserEmail, teamsUserEmail, displayName
prometheusAlertManagerreceiverName
system(empty — automated action)

_context.* — the notification envelope

PathDescriptionExample
_context.entityTypeSource type.cases
_context.entitySubTypeSubtype. Empty in the sample; preset overrides match on caseActivated, caseUpdated, caseResolved.""
_context.entityLabelsRouting and ownership labels. Array-shaped — index [0].{{ _context.entityLabels["environment"][0] }}
_context.groupingGrouping values in the notification context. Array-shaped.{"service": ["alerts", "notifications"]}
_context.systemCoralogix team: id, name.{{ _context.system.name }}
_context.triggertype (manual / automatic), manualTrigger.userEmail, automaticTrigger.{{ _context.trigger.type }}

Top-level variables and functions

NameDescription
correlationKeyStable per-Case key (mirrors case.id) — use as a dedup key for PagerDuty or ServiceNow-style integrations.
nameMirrors case.title.
priorityMirrors case.priority.
get_context()The whole context object. Useful for debugging — see the tip below.
now(), get_random(), range()Standard Tera functions.

Full example payload

The complete shape a Case notification passes to a template, as rendered by get_context() in the preview:

{
"_context": {
"entityType": "cases",
"entitySubType": "",
"entityLabels": { "environment": ["production"] },
"grouping": { "service": ["alerts", "notifications"] },
"trigger": {
"type": "manual",
"manualTrigger": { "userEmail": "user@email.com" },
"automaticTrigger": null
},
"system": { "id": "1234567", "name": "team-name" }
},
"case": {
"id": "76c411be-ff4d-4fb1-a987-5fce042deaaf",
"title": "Test Case",
"url": "https://team.coralogix.com/#/cases?id=CASE-123",
"links": {
"watchCase": "https://team.coralogix.com/#/cases?id=CASE-123",
"assignToMe": "https://team.coralogix.com/#/cases?id=CASE-123&action=assign",
"ackCase": "https://team.coralogix.com/#/cases?id=CASE-123&action=ack",
"resolveCase": "https://team.coralogix.com/#/cases?id=CASE-123&action=resolve",
"closeCase": "https://team.coralogix.com/#/cases?id=CASE-123&action=close"
},
"description": "This is the description of the Test Case",
"assignee": { "$type": "coralogixUser", "coralogixUser": { "userEmail": "test-user@coralogix.com" } },
"status": "ACKNOWLEDGED",
"priority": "P4",
"category": "AVAILABILITY",
"createdAt": "2025-08-10T09:15:00Z",
"updatedAt": "2025-08-10T09:25:00Z",
"acknowledgedAt": "2025-08-10T09:16:30Z",
"acknowledgedBy": { "$type": "coralogixUser", "coralogixUser": { "userEmail": "test-user@coralogix.com" } },
"resolutionDetails": {
"resolutionReason": "This was a false alert.",
"resolvedAt": "2025-08-11T09:15:00Z",
"resolvedBy": { "$type": "system", "system": {} }
},
"closedAt": "2025-08-11T09:15:00Z",
"closedBy": { "$type": "coralogixUser", "coralogixUser": { "userEmail": "test-user@coralogix.com" } },
"indicators": {
"alerts": [
{
"instanceId": "instance-id-1",
"alertDefinitionId": "987e4567-e89b-12d3-a456-426614174111",
"alertDefinitionVersionId": "ver12345-6789-abcd-ef01-234567890abc",
"title": "Test CPU Alert",
"description": "Triggers when average CPU usage on payment-api exceeds 80% over a 5-minute window.",
"alertType": "METRIC_THRESHOLD",
"priority": "P4",
"groupingType": "COMBINATION_ALERT",
"groupByKeys": ["service", "region"],
"timeWindow": 300,
"threshold": 80.0,
"groupings": { "service": "payment-api", "region": "us-west-2" },
"labels": { "metric": "cpu", "team": "platform" },
"state": "TRIGGERED",
"isNoData": false,
"triggeredAt": "2025-08-10T09:14:00Z",
"resolvedAt": null,
"alertQuery": {
"queryString": "avg(node_cpu_seconds_total{mode=\"system\",service=\"payment-api\"}) > 0.8",
"type": "ALERT_QUERY_PROMQL"
},
"details": {
"fromTimestamp": "2025-08-10T09:09:00Z",
"toTimestamp": "2025-08-10T09:14:00Z",
"countOverThreshold": 12,
"relativeHitCount": null,
"valueOverThreshold": 83.7,
"uniqueCountValuesList": null,
"logExample": {
"text": "ERROR: CPU usage at 83.7% on payment-api pod prod-worker-03",
"applicationName": "payment-service",
"subsystemName": "checkout",
"service": "payment-api",
"ipAddress": "10.0.1.21",
"computerName": "prod-worker-03",
"threadId": "main-thread",
"timestamp": "2025-08-10T09:13:45Z",
"category": "ERROR",
"logId": "log-def456abc789"
}
}
}
],
"genericIndicators": [
{
"id": "gi-1", "externalId": "ext-1", "indicatorType": "custom", "status": "TRIGGERED",
"priority": "P4", "labels": {}, "lastTriggeredAt": "2025-08-10T09:14:00Z",
"lastResolvedAt": null, "entityLinks": [ { "url": "https://team.coralogix.com/#/..." } ]
}
],
"prometheusAlerts": [
{
"alertGroupId": "pg-1", "alerts": [], "externalUrl": "https://alertmanager/...",
"groupLabels": {}, "priority": "P4", "receivedAt": "2025-08-10T09:14:00Z",
"receiver": "team-receiver", "status": "firing", "updatedAt": "2025-08-10T09:20:00Z"
}
]
},
"groupings": { "service": ["payment-api"], "region": ["us-west-2"] },
"labels": { "metric": ["cpu"], "team": ["platform"] },
"kpiBreaches": {
"breachedKpis": [
{ "id": "kpi-breach-1", "createdAt": "2025-08-10T09:20:00Z", "kpiType": "TIME_TO_ACKNOWLEDGE", "casePriority": "P4", "thresholdMinutes": 1, "breachedAt": "2025-08-10T09:20:00Z", "mitigatedAt": "2025-08-10T09:22:30Z", "breachStatus": "MITIGATED" }
]
},
"ollyAnalysis": {
"investigationSummary": "Olly correlated the Test CPU Alert with a deploy at 09:10 and observed sustained CPU saturation on payment-api.",
"rootCause": "Regression in payment-api v42.1 increased per-request allocations and pushed CPU above the threshold.",
"rootCauseConfidence": "MEDIUM",
"remediationRecommendations": [
"Roll back payment-api to v42.0.",
"Profile the request handler in v42.1 to locate the allocation regression."
],
"generatedAt": "2025-08-10T09:23:00Z"
},
"impactedEntities": [
{ "kind": "service", "language": "go", "name": "payment-api", "system": "apm", "url": "https://team.coralogix.com/#/apm/services/payment-api" }
],
"externalReferences": [
{ "externalId": "JIRA-123", "url": "https://example.atlassian.net/browse/JIRA-123", "vendor": "jira" }
],
"notificationDeliveries": [
{ "label": "#alerts-prod", "url": "https://example.slack.com/archives/C123/p456", "vendor": "slack" }
]
},
"caseMetadata": {
"notificationReason": "caseClosed",
"change": { "$type": "statusChanged", "previousStatus": "ACTIVE", "currentStatus": "CLOSED" }
},
"correlationKey": "76c411be-ff4d-4fb1-a987-5fce042deaaf",
"name": "Test Case",
"priority": "P4"
}

Gotchas

  • Array-shaped labels: case.labels, case.groupings, _context.entityLabels, and _context.grouping are {key: [values]} — read them with [0]. But case.indicators.alerts[0].labels / .groupings are plain objects ({key: value}) — no index.
  • Arrays need [0]: indicators, kpiBreaches, impactedEntities, externalReferences, and notificationDeliveries. Editor autocomplete only reveals element fields after an index.
  • Objects in JSON payloads: serialize with json_encode() | safe (add truncate(length=2990) for Slack's 3,000-character block limit).
  • Tagged unions (case.assignee and friends, caseMetadata.change): check $type before reading inner fields.
  • Possibly-absent fields: guard impactedEntities, externalReferences, notificationDeliveries, kpiBreaches.breachedKpis, and ollyAnalysis with default(...) or {% if %}.
Tip

To inspect the full payload for a specific Case, drop {{ get_context() | json_encode(pretty=true) }} into a draft preset body and read the preview.

Context reference

All templates also have access to the _context variable, which contains metadata about the notification source type, including system identifiers and trigger details. See Dynamic templating for details.

Migrating from legacy webhooks

If you are moving a legacy outbound webhook to a custom Case preset, see the webhook field mapping for the placeholder-to-template-path mapping. System presets already produce correct payloads, so this is only relevant for custom migrations.

Next steps

Last updated on