---
title: "Update alert configuration"
method: PUT
path: "/api/v2/{org_id}/alerts/{alert_id}"
tags: ["Alerts"]
---

# Update alert configuration

`PUT /api/v2/{org_id}/alerts/{alert_id}`

## Request

- Base URL: `https://api.openobserve.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.openobserve.ai/api/v2/{org_id}/alerts/{alert_id}`
- Auth: API key in header `Authorization`
- TypeScript: <https://skmtc.dev/openobserve/apis/openobserve-api-http/docs/api/v2/:org_id/alerts/:alert_id/put.ts> (a function with typed inputs; its response is checked against the schema)

Updates an existing alert's configuration including conditions, queries, thresholds, notification destinations, and scheduling. Allows users to modify alert behavior and settings as monitoring requirements change.

## Path parameters

- `org_id` string, required
- `alert_id` string, required

## Query parameters

- `folder` string

## Request body

- object: HTTP request body for `UpdateAlert` endpoint. Updates an existing alert. Provide the full alert configuration — this replaces the existing alert entirely (not a partial update). The request body is the same structure as Alert. For anomaly detection configs, set `alert_type = "anomaly_detection"` and supply anomaly-specific fields directly at the top level (flat). Only fields present in the request body will be updated (partial update semantics for anomaly fields).
  - `context_attributes` object, nullable: Optional key-value attributes to include in alert notifications.
  - `creates_incident` boolean: When true, this alert routes notifications through the incident system instead of sending direct alert notifications.
  - `description` string: Human-readable description of what this alert monitors.
  - `destinations` string[]: List of destination names to notify when alert fires. Destinations must be pre-configured in the system. Accepts either `destinations` or `alert_destinations` as the JSON field name.
  - `enabled` boolean: Whether the alert is active. Disabled alerts are not evaluated.
  - `id` string, nullable: Unique identifier for the alert. Auto-generated on creation.
  - `incident_title_template` string, nullable: Incident title template; the generated title is used when no variable resolves.
  - `is_real_time` boolean: If true, alert evaluates in real-time as data arrives. If false, alert runs on a schedule defined by trigger_condition.frequency.
  - `keep_firing_for` integer: Seconds the condition must stay clear before the alert recovers. 0 recovers on the first clear evaluation.
  - `last_edited_by` string, nullable: Username who last edited the alert.
  - `last_satisfied_at` integer, nullable: Unix timestamp of when alert condition was last satisfied.
  - `last_triggered_at` integer, nullable: Unix timestamp of when alert was last triggered.
  - `name` string: Human-readable name for the alert. Must be unique within the organization.
  - `notify_on_recovery` boolean: Send one notification when this alert recovers; a multi-alert sends one per recovered group.
  - `oncall_team` string, nullable: On-call team (a team id) this alert pages, taking precedence over ownership discovery. Omitted or `null` means "work the owner out from the identity dimensions", which is the normal case. Validated at save against the on-call teams of the same org: a team id that names nothing routes nowhere, and a page that routes nowhere is silence rather than an error. Save is a full replace, like `tags` — sending the alert back without this field clears the binding.
  - `org_id` string: Organization ID. Usually set automatically from the request context.
  - `owner` string, nullable: Username of the alert owner.
  - `pending_period_sec` integer
  - `priority` integer, nullable: Priority 1..=5 (P1 = most urgent), Feature 2 / PT-1. Mutable configuration; display + propagation only — it does not affect when the alert fires. Omitted = unset. `value_type` is required because the enum serializes as an integer via serde `try_from`/`into`; without it the OpenAPI schema would advertise a string enum and lie about the payload.
  - `query_condition` QueryCondition
    - `aggregation` Aggregation
      - `function` 'avg' | 'min' | 'max' | 'sum' | 'count' | 'median' | 'p50' | 'p75' | 'p90' | 'p95' | 'p99', required
      - `group_by` string[], nullable
      - `having` Condition, required
        - `column` string, required
        - `ignore_case` boolean
        - `operator` '=' | '!=' | '>' | '>=' | '<' | '<=' | 'contains' | 'not_contains' | 'is_null' | 'is_not_null' | 'is_empty' | 'is_not_empty', required
        - `value` object, required
      - `multi_alert` boolean: Opt-in to per-group evaluation — multi-alerts, `alerts_2.md` M-9/D26. `#[serde(default)]` is the whole backward-compatibility guarantee: an aggregation stored before this field existed cannot contain it, so it deserializes to `false` and the alert keeps its legacy collapsed evaluation byte-for-byte. Nothing is inferred from `group_by` being present — that would silently change paging cadence and reset silence fingerprints for every existing grouped alert. Validated by [`grouping::validate_multi_alert`] (M-10): requires a non-empty `group_by`, an orderable `having.operator`, and "any group" count gates.
      - `warning_value` number, double, nullable: WARNING threshold, sharing `having.operator` and `having.column` with critical (alerts_2.md §4.4). `None` = single-level aggregation alert, i.e. exactly the legacy behaviour. Stored as f64 because aggregate values (averages, percentiles) are not integers. Same lenient deserialization as `promql_warning_value`, for the same reason (D61) — aggregate warnings are the field most likely to be fractional.
    - `conditions` object, nullable
    - `multi_time_range` CompareHistoricData[], nullable
      - `offSet` string, required
    - `promql` string, nullable
    - `promql_condition` Condition
      - `column` string, required
      - `ignore_case` boolean
      - `operator` '=' | '!=' | '>' | '>=' | '<' | '<=' | 'contains' | 'not_contains' | 'is_null' | 'is_not_null' | 'is_empty' | 'is_not_empty', required
      - `value` object, required
    - `promql_multi_alert` boolean: Per-group alerting for a PromQL alert (M-9), where a "group" is one returned SERIES. A sibling of `promql_condition` rather than a member of [`Aggregation::multi_alert`], because a PromQL alert has no `aggregation` at all — its grouping is expressed in the PromQL itself (`sum by (pod) (…)`), not in a `group_by` column list. The group key is the series' FULL label set. That is what a series' identity already is in Prometheus, and it means the expression stays the single place grouping is decided — a separate label picker could only ever disagree with the `by (…)` clause beside it. `#[serde(default)]` carries the same backward-compatibility guarantee as its aggregation counterpart: an alert stored before this field existed deserializes to `false` and keeps its collapsed evaluation byte-for-byte. Nothing is inferred from the query returning several series — that would change paging cadence for every existing PromQL alert that happens to be unaggregated.
    - `promql_rule_mode` boolean
    - `promql_warning_value` number, double, nullable: WARNING value for the PromQL condition (alerts_2.md Feature 1). A sibling field rather than a member of `Condition`, which is shared by every filter in the product and must not grow alert-specific knobs. Shares `promql_condition.operator` with critical. `None` = single-level. Lenient deserialization: this arrives through `CreateAlertRequestBody`'s `#[serde(flatten)]`, which buffers via `Value`, where `arbitrary_precision` makes a number a map (D61). Without it a FRACTIONAL warning is rejected while an integer one works — found by end-to-end testing.
    - `search_event_type` 'ui' | 'dashboards' | 'reports' | 'alerts' | 'values' | 'other' | 'rum' | 'derivedstream' | 'searchjob' | 'download' | 'insights' | 'public_dashboard'
    - `slo_condition` SloCondition: The SLO alert's condition, persisted in `alerts.query_slo_condition` (D42). `slo_id` is additionally written to the indexed `alerts.slo_id` column, which is authoritative for reverse lookups (D60).
      - `critical` number, double, required: Finite and strictly positive (SA-3). Lenient deserialization is required, not cosmetic: this struct arrives nested inside `CreateAlertRequestBody`'s `#[serde(flatten)]`, and a flatten buffers through `Value`, where `arbitrary_precision` represents every number as a map (D61). A plain `f64` fails there with `invalid type: map, expected f64`.
      - `kind` 'error_budget' | 'burn_rate', required: The two SLO-alert shapes we offer.
      - `long_window_secs` integer, nullable: `BurnRate` only. 1h–48h, ≤ the SLO window, an exact multiple of and ≥ 2× the slice interval (SA-8).
      - `multi_alert` boolean: Per-group fan-out — Feature 3's flag, same semantics (SA-13).
      - `operator` '=' | '!=' | '>' | '>=' | '<' | '<=' | 'contains' | 'not_contains' | 'is_null' | 'is_not_null' | 'is_empty' | 'is_not_empty', required
      - `short_window_secs` integer, nullable: `BurnRate` only. Defaults to long ÷ 12 (Google SRE workbook).
      - `slo_id` string, required
      - `warning` number, double, nullable
    - `sql` string, nullable
    - `type` 'custom' | 'sql' | 'promql' | 'slo'
    - `vrl_function` string, nullable
  - `recovery_destinations` string[]: Where the recovery message goes. Empty = the firing's own destinations. Ticket closes are unaffected: a resolve must reach whatever the firing opened.
  - `row_template` string: Template for formatting individual rows in the alert message.
  - `row_template_type` 'String' | 'Json'
  - `runbook_url` string, nullable: Where the fix for this alert is written down. Copied onto every on-call response record the alert opens, so whoever is woken is handed the link in the page instead of going to find it while the thing is on fire. Validated at save: `http://` or `https://` with a host, or the save is refused. A malformed link stored today is a dead click at 3am, and the moment it is read is the worst possible moment to discover it. Full replace, like `oncall_team`.
  - `scheduler_job_present` boolean, nullable: Whether a scheduler job exists for this alert (runtime status, not a stored field). Populated on the composite detail path; omitted otherwise.
  - `stream_name` string: Name of the stream to monitor.
  - `stream_type` 'logs' | 'metrics' | 'traces' | 'profiles' | 'service_graph' | 'enrichment_tables' | 'file_list' | 'metadata' | 'index'
  - `suppress_repeats` boolean: Notify once per state change instead of on every firing evaluation. Enterprise only.
  - `tags` string[]: Selection tags (PT-6): `prod`, `service:checkout`. Normalized and validated on save; omitted when empty.
  - `template` string, nullable: Optional template name. When specified, this template is used for all destinations instead of destination-level templates. This allows using different templates for different alerts while reusing the same destinations.
  - `trigger_condition` TriggerCondition
    - `align_time` boolean
    - `cron` string
    - `frequency` integer: (seconds)
    - `frequency_type` 'cron' | 'minutes'
    - `notify_on_warning` boolean, nullable: Whether a Warning-level match delivers a notification (D11). `None` = true — warnings notify unless explicitly opted out. Persisted in `trigger_thresholds`.
    - `operator` '=' | '!=' | '>' | '>=' | '<' | '<=' | 'contains' | 'not_contains' | 'is_null' | 'is_not_null' | 'is_empty' | 'is_not_empty'
    - `period` integer: (minutes)
    - `silence` integer: (minutes)
    - `threshold` integer
    - `timezone` string, nullable
    - `tolerance_in_secs` integer, nullable: (seconds)
    - `warning_threshold` integer, nullable: Warning threshold, sharing `operator` with `threshold` — one operator for both levels, no mixed directions (T-2). `None` = single-level alert, i.e. exactly the legacy behaviour. Validated by `level::validate_thresholds` — "less severe" is direction-dependent, so this is NOT simply `< threshold`.
  - `tz_offset` integer: Timezone offset in minutes. Negative values for western hemisphere.
  - `updated_at` integer, nullable: Unix timestamp of last modification.
  - `workflows` string[]: workflows to trigger when alert triggers
  - `alert_type` 'all' | 'scheduled' | 'realtime' | 'anomaly_detection' | 'slo' | 'composite': Filters the alert list by alert type (scheduled, realtime, anomaly detection, or all).
  - `anomaly_config` UpdateAnomalyAlertFields: Anomaly-detection-specific fields for `UpdateAlertRequestBody` (all optional).
    - `alert_budget_per_day` number, double, nullable: Absent leaves the stored budget; `null` clears it, back to the trained k.
    - `alert_direction` string, nullable: `both`, `above` or `below`; `null` clears to both.
    - `alert_enabled` boolean, nullable
    - `alert_window_buckets` integer, nullable: Window-share length in buckets, at least 1 and at most 24h of buckets; `null` clears to 1.
    - `alert_window_fire_pct` number, double, nullable: Percent of the window out of band that fires; `null` clears to 100.
    - `alert_window_recover_pct` number, double, nullable: Out-of-band percent below which the window recovers; `null` clears to the fire percent.
    - `band_width` number, double, nullable: Absent leaves the stored value, so pause/resume keeps it; `null` clears to auto.
    - `custom_sql` string, nullable
    - `description` string, nullable
    - `detection_function` string, nullable
    - `detection_function_field` string, nullable: Field to aggregate. Combined with `detection_function` into "avg(field)" before saving.
    - `detection_window_seconds` integer, nullable
    - `enabled` boolean, nullable
    - `filters` unknown
    - `folder_id` string, nullable: Moves the config to this folder. Naming a folder you cannot write to returns 403; omit it to leave the config where it is.
    - `histogram_interval` string, nullable
    - `level_half_width_seconds` integer, nullable: Accepted and stored, but ignored by the band model.
    - `name` string, nullable
    - `owner` string, nullable
    - `percentile` number, double, nullable: Legacy percentile; no longer selects the trained k outside budget mode. Alias `threshold`.
    - `query_mode` string, nullable
    - `retrain_interval_days` integer, nullable
    - `schedule_interval` string, nullable
    - `template` string, nullable: Absent leaves the stored template override; `null` or "" clears it.
    - `training_window_days` integer, nullable
  - `composite_condition` CompositeCondition: Composite expression and truth-policy configuration.
    - `expression` string, required: Boolean expression over child alert IDs, e.g. `{child_a} && ({child_b} || {child_c})`.
    - `stale_child_policy` 'use_last_state' | 'treat_as_false' | 'treat_as_true': How a composite treats a child whose latest state is stale (no recent evaluation within its freshness deadline). The `storage_id` mapping below is persisted in the `stale_child_policy` column and is **append-only**: never renumber an existing variant, or rows already on disk will silently decode to the wrong policy.
    - `warning_counts_as_firing` boolean: Whether a child at `warning` severity counts as firing (`true`) or only `critical` does (`false`). Defaults to `true`.

## Response `200`

Success

- HttpResponse: HTTP response code 200 is success code 400 is error code 404 is not found code 500 is internal server error code 503 is service unavailable code >= 1000 is custom error code message is the message or error message
  - `code` integer, required
  - `error_detail` string, nullable
  - `hint` string, nullable: One-line guidance on how to fix the error (agent self-correction, D4).
  - `id` string, nullable
  - `message` string, required
  - `name` string, nullable
  - `suggestions` string[], nullable: Closest valid alternatives for a mistyped field/function name.
  - `trace_id` string, nullable
  - `warnings` string[], nullable: Problems with a request that succeeded anyway. Distinct from `hint`, which explains a failure: these accompany a 200, and the caller is entitled to have meant it.

## Other responses

- `400`: Error
- `403`: Forbidden

---

[API](https://skmtc.dev/openobserve/apis/openobserve-api-http.md) - [All operations](https://skmtc.dev/openobserve/apis/openobserve-api-http/llms.txt) - [OpenAPI document](https://skmtc.dev/openobserve/apis/openobserve-api-http/revisions/0529b8a10252?raw)
