---
title: "Get Signal"
method: GET
path: "/{brand_id}/signals/{signal_id}"
tags: ["signals"]
---

# Get Signal

`GET /{brand_id}/signals/{signal_id}`

## Request

- Base URL: `https://api.scrunchai.com/v1`
- URL: `https://api.scrunchai.com/v1/{brand_id}/signals/{signal_id}`
- Auth: HTTP bearer

Fetch one signal by ID, including its full narrative (what happened, why it matters, what to do) when available. Returns 404 for IDs that exist but are not user-facing (non-fired or cluster-child rows) — the same population rule as `listSignals`.

## Path parameters

- `brand_id` integer, required
- `signal_id` integer, required

## Response `200`

Successful Response

- APISignal: A detected, statistically-tested movement in an AI-visibility metric.
  - `id` integer, required: Signal ID. Stable within one detection; use for `getSignal`.
  - `detected_for_date` string, date, required: Anchor date the nightly detection ran for (YYYY-MM-DD).
  - `fingerprint` string, required: Stable identity of the underlying issue across nightly re-detections (hash of the slice + metric). An ongoing signal is re-raised daily under the same fingerprint. It does not tell signals on the same slice apart: the brand's and each competitor's signals, and every `alert_type`, share it. Pair it with `subject_kind`, `competitor_id`, `alert_type` and `scope_qualifier` to follow one signal.
  - `subject_kind` 'brand' | 'competitor', required: Whose movement the signal describes: your `brand` or a `competitor`.
  - `competitor_id` integer, nullable: Competitor ID for `competitor` signals; null for `brand`.
  - `subject_name` string, nullable: Competitor name for `competitor` signals, as it was when the signal was detected. Null for `brand` signals and for some older competitor signals; use `competitor_id` there.
  - `alert_type` 'level_change' | 'trend' | 'level', required: Detection kind: `level_change` (step shift), `trend` (sustained drift) or `level` (standing in the current window alone, no baseline).
  - `scope` 'account' | 'account_platform' | 'topic' | 'topic_platform', required: Slice granularity: `account`, `account_platform`, `topic`, or `topic_platform`.
  - `scope_qualifier` string, required: Scope variant of the signal, e.g. `as_observed`. Part of its identity: signals that differ only here are tracked and reacted to separately.
  - `metric` string, required: Metric the signal fired on (e.g. `presence_rate`, `position_top_rate`, `cited_domain_rate`).
  - `platform` string, required: AI platform the signal was detected on. `(multi)` means the slice spans several platforms — see `slice.platforms` for the real list.
  - `direction` 'up' | 'down' | 'none', required: Direction of the movement: `up`, `down`, `none`.
  - `tier` 'high' | 'confident' | 'worth_a_look' | 'provisional' | 'low_confidence' | 'underpowered' | 'untested', required: Confidence tier, best first: `high`, `confident`, `worth_a_look`, `provisional`, then noise-floor tiers `low_confidence`, `underpowered`, `untested` (hidden by default).
  - `current_value` number, required: Metric value over the current window (0-1 rate).
  - `baseline_value` number, required: Reference value the current value is compared against (0-1 rate): the baseline-window metric for `level_change` and `trend`, the fixed threshold or competitor rate for `level`.
  - `delta_absolute` number, required: `current_value - baseline_value` (positive = above the reference).
  - `score` number, nullable: Engine priority score used for the default sort; null for legacy rows.
  - `narrative_what` string, required: One-line headline of what changed.
  - `narrative` APISignalNarrative: Engine-generated narrative for a signal.
    - `what_happened` string, nullable: Plain-language description of the detected change.
    - `why_it_matters` string, nullable: Why the change is significant for the brand.
    - `what_to_do` string, nullable: Suggested next step or investigation.
  - `slice` APISignalSlice, required: The data slice a signal was detected on.
    - `platforms` string[]: AI platforms the slice covers. Empty means all platforms.
    - `topic_labels` string[]: Topic labels the slice covers. Empty means all topics.
    - `geo_country` string, nullable: Country the slice is restricted to, when geo-scoped.
  - `window_current_start` string, date, nullable: Start of the current comparison window.
  - `window_current_end` string, date, nullable: End of the current comparison window.
  - `baseline_definition` string, nullable: Human-readable definition of the reference: the baseline window for `level_change` and `trend`, the threshold or competitor for `level`.
  - `url_movers` APISignalUrlMover[]: Per-URL citation movers behind the signal: the brand/competitor URLs whose distinct-response citation counts moved most between the baseline and current windows. Emitted for `cited_domain_rate` signals; empty for other metrics and older signals. Filterable via `mover_url`.
    - `normalized_url` string, required: Normalized cited URL (scheme and tracking params stripped).
    - `owner` 'brand' | 'competitor', required: Whose domain the URL belongs to: `brand` or `competitor`.
    - `competitor_id` integer, nullable: Competitor ID for `competitor`-owned URLs.
    - `competitor_name` string, nullable: Competitor name for `competitor`-owned URLs.
    - `current_responses` integer, required: Distinct responses citing the URL in the current window.
    - `baseline_responses` integer, required: Distinct responses citing the URL in the baseline window.
    - `current_prompts` integer, required: Distinct prompts whose responses cite the URL in the current window.
    - `baseline_prompts` integer, required: Distinct prompts whose responses cite the URL in the baseline window.
    - `contribution` number, nullable: Exact share of the signal's metric delta attributed to this URL. Brand-owned URLs only; null on competitor entries and older signals.
  - `query` APISignalChartQuery: Request body for `queryDataV2` (`POST /v2/query/{brand_id}`) that returns the chart series.
    - `start_date` string, date, required: First day of the chart (YYYY-MM-DD, inclusive): 60 days before `detected_for_date`.
    - `end_date` string, date, required: Last day of the chart (YYYY-MM-DD, inclusive): the `detected_for_date`.
    - `fields` string[], required: The date bucket followed by the metric the signal fired on.
    - `filters` APISignalChartQueryFilter[], required: The signal's slice (platforms, topics) and, for competitor signals, the competitor scope (`competitor_name`, `cited_competitor_name` for citation metrics, or `advertiser_competitor_name` for ad metrics).
      - `field` string, required: Dimension to filter on, e.g. `ai_platform`.
      - `values` string[], required: Values to keep (any of them matches).
    - `transform` APISignalChartQueryTransform: Series smoothing of a signal's chart query.
      - `ewma` boolean: Smooth the series the way the signal card draws it. Drop `transform` from the request for raw daily values.
  - `created_at` string, date-time, required: When the signal row was created (UTC).

## Other responses

- `422`: Validation Error

## Changes

- **2026-10-09** `02ff659cc930`: 2 info
  - added the optional property `query` to the response with the `200` status
  - added the optional property `subject_name` to the response with the `200` status
- **2026-10-08** `9b86067d188a`: 2 info
  - added the optional property `competitor_id` to the response with the `200` status
  - added the required property `scope_qualifier` to the response with the `200` status
- **2026-09-25** `df388e211328`: 1 warning
  - added the new `level` enum value to the `alert_type` response property for the response status `200`

[Operation history](https://skmtc.dev/scrunchai/apis/scrunch-data-api/changes/:brand_id/signals/:signal_id/get.md)

---

[API](https://skmtc.dev/scrunchai/apis/scrunch-data-api.md) - [All operations](https://skmtc.dev/scrunchai/apis/scrunch-data-api/llms.txt) - [OpenAPI document](https://skmtc.dev/scrunchai/apis/scrunch-data-api/revisions/de4fc679600a?raw)
