---
title: "Get alert details"
method: GET
path: "/api/v2/{org_id}/alerts/{alert_id}"
tags: ["Alerts"]
---

# Get alert details

`GET /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/get.ts> (a function with typed inputs; its response is checked against the schema)

Retrieves detailed information about a specific alert including its configuration, conditions, triggers, notification settings, and current status. Useful for viewing and understanding existing alert setups. Composite alerts return a composite-shaped body (alert_type="composite", composite_condition, children, evaluation) rather than GetAlertResponseBody.

## Path parameters

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

## Query parameters

- `folder` string

## Response `200`

Success

- object: HTTP response body for `GetAlert` endpoint.
  - `context_attributes` object, nullable
  - `creates_incident` boolean: When true, this alert creates/joins incidents instead of sending direct notifications. Notification is sent only when a new incident is created or a new alert type joins an existing incident. Repeated firings are suppressed. When false (default), the alert sends notifications directly and does not correlate to any incident.
  - `description` string
  - `destinations` string[]
  - `enabled` boolean
  - `id` string, nullable
  - `incident_title_template` string, nullable
  - `is_real_time` boolean
  - `keep_firing_for` integer: Seconds the condition must stay clear before the episode recovers. 0 recovers on the first clear evaluation, which is what every alert does today. Named after Prometheus' `keep_firing_for`, with the same meaning.
  - `last_edited_by` string, nullable
  - `last_satisfied_at` integer, nullable: Will be removed in the future.
  - `last_triggered_at` integer, nullable: Will be removed in the future.
  - `name` string
  - `notify_on_recovery` boolean: Send one notification when this alert, or each group of a multi-alert, stops firing. Off by default: an existing template that never mentions `{alert_status}` would otherwise render the firing wording twice.
  - `oncall_team` string, nullable: On-call team this alert pages, overriding ownership discovery. `None` means "work it out from the identity dimensions", which is the normal case — an explicit value is for the alert whose owner the dimensions cannot express.
  - `org_id` string
  - `owner` string, nullable
  - `pending_period_sec` integer
  - `priority` integer, nullable: How much humans care about this alert (PT-1). `None` = unset, which is every pre-Feature-2 alert. **Mutable** configuration — editable on any update, like `name`. Display + propagation only: it must never influence evaluation, silence, or delivery (PT-5 / D19). B-29 carved out one exception: when set, it takes precedence over the eval_level default for incident severity at creation/escalation — see `config::meta::alerts::priority` and `core::alerts::incidents::create_new_incident`. `value_type` is required here because the enum serializes as an integer via serde `try_from`/`into`; without it the generated OpenAPI 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 when it should not follow the firing. Empty = the firing's own destinations. Ticket closes are unaffected either way — a resolve has to carry the correlation key of the trigger that opened it, so it cannot be redirected.
  - `row_template` string
  - `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 the person woken is handed the runbook in the page. Validated at save — a malformed link is refused rather than stored, because the moment it is read is the one moment nobody has the patience to debug a URL.
  - `stream_name` string
  - `stream_type` 'logs' | 'metrics' | 'traces' | 'profiles' | 'service_graph' | 'enrichment_tables' | 'file_list' | 'metadata' | 'index'
  - `suppress_repeats` boolean: Notify once per state change; enterprise only, other builds ignore it.
  - `tags` string[]: Selection tags (PT-6): bare (`prod`) or `key:value` (`service:checkout`), normalized and validated at save by `tags::normalize_tags`. NOT `context_attributes` — that field is free-form KV shipped into notification payloads with no validation. These are the filtering / scoping primitive. Skipped when empty so alerts that set no tags serialize exactly as they did before Feature 2 (G5).
  - `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. The negative secs means the Western Hemisphere
  - `updated_at` string, date-time
  - `workflows` string[]
  - `locked_target_names` object: Display names of the alert's locked workflows and on-call team, by id, for the edit form.

## Other responses

- `404`: NotFound

---

[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)
