# Escalation Policy Updates

ilagent can listen for messages on a dedicated topic and automatically update escalation policy levels in ilert. This is useful for syncing on-call schedules from external systems (e.g. workforce management tools) into ilert.

## How it works

A policy update message contains an email address, a shift (escalation level), and one or more routing key fields that identify which escalation policy to update. ilagent:

1. Resolves the user by email
2. Resolves the escalation policy by routing key
3. Updates the corresponding escalation level with the resolved user

The target escalation level must already exist on the policy — ilagent updates the level in place but does not create new levels. The existing `escalationTimeout` of the level is preserved; only the assigned user is replaced.

## Payload format

Policy payloads can have any JSON structure — ilagent extracts the relevant fields based on your configuration flags (`--policy_routing_keys`, `--map_key_email`, `--map_key_shift`, `--filter_key`). Here is an example of a typical payload:

```json
{
  "location": "powerplant",
  "eventType": "active",
  "data": {
    "email": "oncall@example.com",
    "shift": "1"
  }
}
```

In this example, `location` is used as a routing key, `data.email` and `data.shift` are the default paths for email and shift, and `eventType` is used for filtering. All of these paths are configurable.

The `shift` field can be a string (`"1"`) or a number (`1`) — both are supported.

## Configuration

| Flag                    | Description                                                                                    | Default      |
| ----------------------- | ---------------------------------------------------------------------------------------------- | ------------ |
| `--policy_topic`        | Consumer topic to listen on for policy update messages                                         | *(disabled)* |
| `--policy_routing_keys` | Comma-separated JSON field names to extract routing key values from                            | *(required)* |
| `--map_key_email`       | JSON path for the email field (dot-notation for nested)                                        | `data.email` |
| `--map_key_shift`       | JSON path for the shift field (dot-notation for nested)                                        | `data.shift` |
| `--shift_offset`        | Offset applied to the shift value (e.g. `--shift_offset=-1` to convert 1-indexed to 0-indexed) | `0`          |

The `--filter_key` and `--filter_val` flags also apply to policy messages, allowing you to selectively process messages based on a field value.

## Shift offset

If your external system uses 1-indexed shift values but the ilert API expects 0-indexed levels, use `--shift_offset=-1` (the `=` is required to avoid `-1` being parsed as a separate CLI flag). The result is clamped to 0, so it will never go negative.

## MQTT example

```sh
ilagent daemon -v -v \
    -m 127.0.0.1 -q 1883 -n ilagent \
    --policy_topic 'user/logins' \
    --policy_routing_keys 'location,slot' \
    --map_key_email 'data.email' \
    --map_key_shift 'data.shift' \
    --shift_offset=-1 \
    --filter_key 'eventType' \
    --filter_val 'active' \
    --mqtt_qos 1 \
    --mqtt_buffer
```

When using `--mqtt_buffer`, all MQTT messages (including policy updates and events) are queued in SQLite and retried with exponential backoff (up to 60 seconds). Combined with `--mqtt_qos 1`, this provides at-least-once delivery guarantees.

See [MQTT Consumer](https://docs.ilert.com/developer-docs/client-libraries/ilagent/mqtt) for details on QoS and buffering options.

## Kafka example

```sh
ilagent daemon -v -v \
    --kafka_brokers localhost:9092 \
    --kafka_group_id ilagent \
    --policy_topic 'user-logins' \
    --policy_routing_keys 'location' \
    --map_key_email 'user.info.email' \
    --map_key_shift 'level' \
    --shift_offset=-1
```

In Kafka mode, the consumer offset is only committed after successful processing — failed policy updates will be redelivered automatically. The `--mqtt_buffer` and `--mqtt_qos` flags have no effect in Kafka mode.
