---
title: "Get the status and result of an alert preview"
method: GET
path: "/v1/alerts/preview/{previewId}"
tags: ["Alerts", "tier:standard"]
---

# Get the status and result of an alert preview

`GET /v1/alerts/preview/{previewId}`

## Request

- Base URL: `https://api.particle.pro`
- URL: `https://api.particle.pro/v1/alerts/preview/{previewId}`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Returns the current state of an async preview sweep. Status transitions in_progress → completed (or failed). Previews are retained for 1 hour; expired IDs return 404.

## Path parameters

- `previewId` string, required: Opaque preview ID returned by POST /v1/projects/{projectId}/alerts/preview.

## Response `200`

OK

- GetAlertPreviewResponseBody
  - `by_day` AlertPreviewBucketResponse[], nullable: Per-day match count over the window (UTC dates), oldest day first.
    - `count` integer, required: Number of matches whose source episode aired on that day.
    - `date` string, required: UTC date in YYYY-MM-DD format.
  - `completed_at` string, date-time: Set once status is completed or failed.
  - `error` string: Set only when status is failed; safe to surface to the user.
  - `sample` AlertMatch[], nullable: Up to AlertPreviewSampleSize most-recent matches with payload fully hydrated. Empty until status is completed.
    - `alert_id` string, required: ID of the parent alert.
    - `deliveries` AlertDeliverySummary[], nullable, required
      - `channel` string, required
      - `created_at` string, date-time, required
      - `error_message` string
      - `id` string, required
      - `sent_at` string, date-time
      - `status` string, required: Delivery outcome — SENT (delivered; a partial success keeps this status with the failure noted in error_message), FAILED (an attempt failed; realtime retries within its budget and digests re-select within their window), SKIPPED (intentionally not delivered), or ABANDONED (realtime webhook delivery permanently gave up after exhausting its retry budget, so the match was dropped for that channel).
    - `detected_at` string, date-time, required
    - `entity_id` string, required
    - `entity_type` string, required: Type of the watched target: PERSON, COMPANY, or KNOWLEDGE_GRAPH_ENTITY for entity alerts, KEYWORD for KEYWORD_MENTION alerts.
    - `episode` AlertMatchEpisode
      - `apple_podcasts_url` string: Apple Podcasts deep-link for the parent podcast. Omitted when the podcast has no iTunes ID.
      - `audio_url` string: CDN-fronted URL for the full episode audio, playable directly in a browser <audio> element without auth (the podcast's own public media). Clients play a specific window by loading this and seeking to the window's start_seconds. Omitted when the episode has no stored audio yet. Present on both the member and public landing-page tiers so a shared link can play the clip.
      - `duration_seconds` number, double: Total episode duration in seconds. Omitted when unknown.
      - `explicit` boolean: Whether the episode is flagged as containing explicit content by its publisher.
      - `image_url` string: Episode-specific image. Omitted when the episode has no dedicated image. Clients should fall back to podcast_image_url for a card thumbnail in that case.
      - `podcast_bias` 'EXTREME_LEFT' | 'LEANS_LEFT' | 'LEFT' | 'CENTER' | 'RIGHT' | 'LEANS_RIGHT' | 'EXTREME_RIGHT': Political bias rating for the parent podcast. Omitted when the podcast is not substantively political or has not been evaluated yet. Fetch GET /v1/podcasts/{id}/bias for the full analysis including reasoning and evidence.
      - `podcast_id` string, required
      - `podcast_image_url` string: Parent podcast's image. Suitable as a fallback when image_url is absent.
      - `podcast_popularity` number, double: Parent podcast's global popularity percentile in (0,1] — a cume_dist ranking over all currently-charting podcasts (Apple Podcasts charts). Higher is more popular; 1.0 is the most popular show. Omitted when the podcast is not currently charting.
      - `podcast_popularity_badge` 'Top Podcast' | 'Very Popular' | 'Popular': Human-facing reach tier derived from podcast_popularity: Top Podcast (top 1%), Very Popular (top 5%), or Popular (top 10%). Omitted for shows outside the top 10%.
      - `podcast_slug` string
      - `podcast_title` string, required
      - `published_at` string, date-time
      - `slug` string
      - `title` string, required
    - `id` string, required
    - `is_backfilled` boolean: True for matches written by the post-create historical sweep. Backfilled matches are real matches the live pipeline would have produced, with DetectedAt set to the source episode's publish time. They never trigger delivery (no email is sent) — the field lets the UI label them so users can distinguish 'past' from 'going-forward' matches.
    - `keyword` string: KEYWORD_MENTION matches only: the phrase this match fired on. It stays the phrase that matched even if the alert's keyword is later edited.
    - `kind` 'ENTITY_MENTION' | 'PODCAST_SPEAKER' | 'KEYWORD_MENTION', required: Inherited from the parent alert's kind so clients can render mention vs appearance semantics without a follow-up alert lookup. Match payloads from ENTITY_MENTION and KEYWORD_MENTION alerts carry mention_count and mention_variants; PODCAST_SPEAKER matches carry roles and a line-count in mention_count.
    - `llm_summary` string: AI-generated narrative summary of this match with prior-mention context from the past 7 days for the same (alert, entity). Generated asynchronously after match creation. Absent (field omitted) when the summarizer hasn't processed the row yet OR when the LLM exhausted its retry budget — clients should treat both states the same: no summary to render. Visible to both org members and the public landing-page tier; the summary describes the mention itself, not the alert configuration.
    - `mention_count` integer, required
    - `mention_variants` string[], nullable
    - `monitor_id` string, required: Deprecated — use alert_id. ID of the parent alert.
    - `relevance` 'on_target' | 'incidental': How this match relates to the watched entity, classified by the summarizer: on_target (the entity is the mention's subject or a substantive reference) or incidental (a correct but passing reference in service of another story). Absent when unjudged. Lets a client tell a substantive mention from a fly-by one. (A third internal verdict, wrong_entity, marks knowledge-graph name collisions; those matches are suppressed before delivery and never appear here.)
    - `roles` string[], nullable: Canonical speaker role(s) the matched entity appeared as, drawn from the alert's speaker roles: by default GUEST, PANELIST, CORRESPONDENT, AUDIENCE, or SOUNDBITE_SPEAKER (an excerpted clip of them, not a live appearance), and HOST only when speaker_roles includes it. Raw STT/LLM labels like CALLER, REPORTER, LISTENER are normalized to these buckets on write. Populated only for PODCAST_SPEAKER matches; sorted alphabetically for deterministic order.
    - `source_id` string, required
    - `source_type` string, required
    - `truncated` boolean
    - `windows` AlertMatchWindow[], nullable
      - `clip_description` string
      - `clip_id` string
      - `clip_intro_statement` string
      - `clip_title` string
      - `clip_type` string
      - `end_seconds` number, double, required
      - `lines` AlertMatchLine[], nullable, required
        - `end_seconds` number, double, required
        - `is_mention` boolean
        - `number` integer
        - `role` string
        - `speaker` string
        - `start_seconds` number, double, required
        - `text` string, required
      - `segment_description` string
      - `segment_id` string
      - `segment_summary` string
      - `segment_title` string
      - `segment_type` string
      - `start_seconds` number, double, required
  - `started_at` string, date-time, required
  - `status` 'in_progress' | 'completed' | 'failed', required: State of the sweep. Clients should poll until the value is 'completed' or 'failed' (TTL 1h).
  - `total_matches` integer, required
  - `window_days` integer, required

## Other responses

- `default`: Error

---

[API](https://skmtc.dev/particle/apis/particle-api.md) · [All operations](https://skmtc.dev/particle/apis/particle-api/llms.txt) · [OpenAPI document](https://skmtc.dev/particle/apis/particle-api/revisions/416ba82ab9d7?raw)
