---
title: "Get pipeline by ID"
method: GET
path: "/api/{org_id}/pipelines/{pipeline_id}"
tags: ["Pipelines"]
---

# Get pipeline by ID

`GET /api/{org_id}/pipelines/{pipeline_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/{org_id}/pipelines/{pipeline_id}`
- Auth: API key in header `Authorization`
- TypeScript: <https://skmtc.dev/openobserve/apis/openobserve-api-http/docs/api/:org_id/pipelines/:pipeline_id/get.ts> (a function with typed inputs; its response is checked against the schema)

Retrieves the details of a specific data processing pipeline by its ID, including its status, trigger info, and any recent errors

## Path parameters

- `org_id` string, required
- `pipeline_id` string, required

## Response `200`

Success

- object
  - `description` string
  - `edges` Edge[], required
    - `id` string, required: Edge identifier, format: "e{source_id}-{target_id}"
    - `source` string, required: Source node id (data flows from this node)
    - `source_handle` string, nullable: Which output handle of the source node this edge leaves from, for multi-output nodes such as Branch. Absent on every pre-existing edge, so it must not serialize.
    - `target` string, required: Target node id (data flows to this node)
  - `enabled` boolean
  - `last_error` PipelineErrorInfo
    - `error_summary` string, nullable
    - `last_error_timestamp` integer, required
    - `node_errors` unknown
  - `name` string, required
  - `nodes` Node[], required
    - `data` object, required: Node configuration. Structure depends on node_type: - stream: { "node_type": "stream", "org_id": "org", "stream_name": "name", "stream_type": "logs"|"metrics"|"traces" } - function: { "node_type": "function", "name": "func_name", "after_flatten": bool } - condition: { "node_type": "condition", "conditions": {...} } - query: { "node_type": "query", "org_id": "org", "stream_type": "logs", "query_condition": {...}, "trigger_condition": {...} } - remote_stream: { "node_type": "remote_stream", "org_id": "org", "destination_name": "dest" }
    - `id` string, required: Unique identifier for the node (use UUID format)
    - `io_type` string, required: Node role in the pipeline. MUST be one of: - "input": Source stream node (first node in pipeline) - "output": Destination stream node (last node in pipeline) - "default": Processing node (function, condition, etc.)
    - `is_disabled` boolean
    - `meta` object, nullable
    - `position` Position, required
      - `x` number, float, required
      - `y` number, float, required
    - `style` NodeStyle
      - `backgroundColor` string, nullable
  - `org` string
  - `paused_at` integer, nullable
  - `pipeline_id` string
  - `source` union: Pipeline source type determines when the pipeline runs. Use "realtime" for processing data as it arrives, "scheduled" for periodic batch processing.
    - object: Real-time pipeline: processes data immediately as it's ingested. Example: { "source_type": "realtime" }
      - `org_id` string
      - `stream_name` string
      - `stream_type` 'logs' | 'metrics' | 'traces' | 'profiles' | 'service_graph' | 'enrichment_tables' | 'file_list' | 'metadata' | 'index'
      - `source_type` 'realtime', required
    - object: Scheduled pipeline: runs periodically based on trigger_condition. Example: { "source_type": "scheduled", "org_id": "default", "stream_type": "logs", "query_condition": {...}, "trigger_condition": {...} }
      - `delay` integer, nullable
      - `org_id` string
      - `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
      - `start_at` integer, nullable: The datetime from when the pipeline should check for ingested data
      - `stream_type` 'logs' | 'metrics' | 'traces' | 'profiles' | 'service_graph' | 'enrichment_tables' | 'file_list' | 'metadata' | 'index'
      - `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
      - `source_type` 'scheduled', required
  - `version` integer

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