> ## Documentation Index
> Fetch the complete documentation index at: https://docs.particle.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a single alert delivery

> Returns one delivery with its embedded matches (paginated — see matches_cursor). The URL is keyed only by the delivery ID — the parent alert ID is intentionally omitted so a landing-page link can be shared publicly without leaking the alert identifier. Works for all cadences — immediate, daily, weekly digests. URL possession is the access factor; the endpoint is reachable without auth (the IDs are unguessable). Authenticated members of the delivery's owning organization receive the high-resolution payload (transcript Windows when `view=detailed`, mention variants, salience, delivery audit). For a member-viewed WEBHOOK delivery, has_webhook_payload is true and the exact POSTed JSON is available from GET /v1/alerts/deliveries/{id}/webhook-payload (not embedded here — it can be many MB). Unauthenticated and non-member callers receive a reduced public payload — alert title and kind, match entity and episode metadata, no internal fields.



## OpenAPI

````yaml /openapi.json get /v1/alerts/deliveries/{id}
openapi: 3.1.0
info:
  description: Public API for Particle — news intelligence, financial data, and analysis.
  title: Particle API
  version: 0.1.0
servers:
  - url: https://api.particle.pro
security:
  - ApiKeyHeader: []
  - BearerAuth: []
paths:
  /v1/alerts/deliveries/{id}:
    get:
      tags:
        - Alerts
        - tier:free
      summary: Get a single alert delivery
      description: >-
        Returns one delivery with its embedded matches (paginated — see
        matches_cursor). The URL is keyed only by the delivery ID — the parent
        alert ID is intentionally omitted so a landing-page link can be shared
        publicly without leaking the alert identifier. Works for all cadences —
        immediate, daily, weekly digests. URL possession is the access factor;
        the endpoint is reachable without auth (the IDs are unguessable).
        Authenticated members of the delivery's owning organization receive the
        high-resolution payload (transcript Windows when `view=detailed`,
        mention variants, salience, delivery audit). For a member-viewed WEBHOOK
        delivery, has_webhook_payload is true and the exact POSTed JSON is
        available from GET /v1/alerts/deliveries/{id}/webhook-payload (not
        embedded here — it can be many MB). Unauthenticated and non-member
        callers receive a reduced public payload — alert title and kind, match
        entity and episode metadata, no internal fields.
      operationId: get-alert-delivery
      parameters:
        - description: Delivery ID
          in: path
          name: id
          required: true
          schema:
            description: Delivery ID
            type: string
        - description: >-
            Hydration depth for the embedded matches. Both views include Episode
            metadata (episode title, podcast title, image) so the FE can render
            a card per match. 'summary' (default) omits transcript Windows;
            'detailed' includes them — pick 'detailed' when rendering a full
            landing page where each match expands to the spoken excerpt,
            'summary' for a list view.
          explode: false
          in: query
          name: view
          schema:
            default: summary
            description: >-
              Hydration depth for the embedded matches. Both views include
              Episode metadata (episode title, podcast title, image) so the FE
              can render a card per match. 'summary' (default) omits transcript
              Windows; 'detailed' includes them — pick 'detailed' when rendering
              a full landing page where each match expands to the spoken
              excerpt, 'summary' for a list view.
            enum:
              - summary
              - detailed
            type: string
        - description: >-
            Max embedded matches to return in this response (default and max
            100). The delivery's true total is always match_count; use
            matches_cursor to page through the rest.
          explode: false
          in: query
          name: matches_limit
          schema:
            default: 100
            description: >-
              Max embedded matches to return in this response (default and max
              100). The delivery's true total is always match_count; use
              matches_cursor to page through the rest.
            format: int64
            maximum: 100
            minimum: 1
            type: integer
        - description: >-
            Opaque cursor from a previous response's matches_cursor, to fetch
            the next page of embedded matches.
          explode: false
          in: query
          name: matches_cursor
          schema:
            description: >-
              Opaque cursor from a previous response's matches_cursor, to fetch
              the next page of embedded matches.
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AlertDeliveryDetail'
          description: OK
        default:
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/PlatformError'
          description: Error
      security: []
      x-codeSamples:
        - label: cURL
          lang: curl
          source: >-
            curl
            "https://api.particle.pro/v1/alerts/deliveries/{id}?view=summary&matches_limit=100"
components:
  schemas:
    AlertDeliveryDetail:
      additionalProperties: false
      properties:
        alert:
          $ref: '#/components/schemas/AlertRef'
          description: >-
            Lightweight reference to the parent alert. Lets the FE render a
            delivery landing page without a second GET /v1/alerts/{id} call.
        alert_id:
          description: ID of the parent alert.
          type: string
        channel:
          type: string
        created_at:
          format: date-time
          type: string
        error_message:
          type: string
        has_webhook_payload:
          description: >-
            Whether this delivery has a reconstructable webhook payload
            (member-viewed WEBHOOK deliveries only). When true, fetch the exact
            POSTed JSON from GET /v1/alerts/deliveries/{id}/webhook-payload — it
            is not embedded here because it can be many MB.
          type: boolean
        id:
          type: string
        match_count:
          format: int64
          type: integer
        matches:
          items:
            $ref: '#/components/schemas/AlertMatch'
          type:
            - array
            - 'null'
        matches_cursor:
          description: >-
            Opaque cursor; pass as ?matches_cursor= to fetch the next page of
            matches. Absent when there are no more.
          type: string
        matches_has_more:
          description: >-
            Whether more matches exist beyond this page. The true total is
            match_count.
          type: boolean
        monitor:
          $ref: '#/components/schemas/AlertRef'
          description: Deprecated — use alert. Lightweight reference to the parent alert.
        monitor_id:
          description: Deprecated — use alert_id. ID of the parent alert.
          type: string
        sent_at:
          format: date-time
          type: string
        status:
          description: >-
            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).
          type: string
        viewer_can_manage:
          description: >-
            Whether the caller is a member of the owning org (or an API key
            scoped to the owning project) and can manage this alert in-app. True
            responses carry the member-only fields; false responses are the
            public projection with those fields stripped. Clients must read this
            rather than inferring access from field presence.
          type: boolean
      required:
        - id
        - monitor_id
        - alert_id
        - channel
        - status
        - viewer_can_manage
        - match_count
        - created_at
        - matches
        - matches_has_more
        - has_webhook_payload
      type: object
    PlatformError:
      additionalProperties: false
      properties:
        detail:
          description: >-
            A human-readable explanation specific to this occurrence of the
            problem.
          examples:
            - Property foo is required but is missing.
          type: string
        error_code:
          type: string
        errors:
          description: Optional list of individual error details
          items:
            $ref: '#/components/schemas/ErrorDetail'
          type:
            - array
            - 'null'
        instance:
          description: >-
            A URI reference that identifies the specific occurrence of the
            problem.
          examples:
            - https://example.com/error-log/abc123
          format: uri
          type: string
        resolve:
          $ref: '#/components/schemas/ErrorResolve'
        status:
          description: HTTP status code
          examples:
            - 400
          format: int64
          type: integer
        title:
          description: >-
            A short, human-readable summary of the problem type. This value
            should not change between occurrences of the error.
          examples:
            - Bad Request
          type: string
        type:
          default: about:blank
          description: A URI reference to human-readable documentation for the error.
          examples:
            - https://example.com/errors/example
          format: uri
          type: string
      type: object
    AlertRef:
      additionalProperties: false
      properties:
        id:
          type: string
        kind:
          description: Inherited from the parent alert's kind. See AlertMatch.kind.
          enum:
            - ENTITY_MENTION
            - PODCAST_SPEAKER
          type: string
        organization_id:
          description: Owning organization. Omitted for non-member callers.
          type: string
        project_id:
          description: >-
            Owning project. Lets a deep-linked delivery select the right project
            in the dashboard. Omitted for non-member callers.
          type: string
        title:
          type: string
      required:
        - id
        - title
        - kind
      type: object
    AlertMatch:
      additionalProperties: false
      properties:
        alert_id:
          description: ID of the parent alert.
          type: string
        deliveries:
          items:
            $ref: '#/components/schemas/AlertDeliverySummary'
          type:
            - array
            - 'null'
        detected_at:
          format: date-time
          type: string
        entity_id:
          type: string
        entity_type:
          type: string
        episode:
          $ref: '#/components/schemas/AlertMatchEpisode'
          description: >-
            Optional episode + podcast metadata embedded so a single response
            renders a card without a follow-up /v1/episodes/{id} call. Populated
            for preview-sample matches (POST
            /v1/projects/{projectId}/alerts/preview's GET response) and for the
            landing-page GETs (GET /v1/alerts/deliveries/{id} in both summary
            and detailed views, GET /v1/alerts/matches/{id}); absent on the
            paginated live matches list.
        id:
          type: string
        is_backfilled:
          description: >-
            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.
          type: boolean
        kind:
          description: >-
            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 alerts carry mention_count and
            mention_variants; PODCAST_SPEAKER matches carry roles and a
            line-count in mention_count.
          enum:
            - ENTITY_MENTION
            - PODCAST_SPEAKER
          type: string
        llm_summary:
          description: >-
            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.
          type: string
        mention_count:
          format: int64
          type: integer
        mention_variants:
          items:
            type: string
          type:
            - array
            - 'null'
        monitor_id:
          description: Deprecated — use alert_id. ID of the parent alert.
          type: string
        relevance:
          description: >-
            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.)
          enum:
            - on_target
            - incidental
          type: string
        roles:
          description: >-
            Canonical speaker role(s) the matched entity appeared as. One of
            GUEST, PANELIST, CORRESPONDENT, or AUDIENCE (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.
          items:
            type: string
          type:
            - array
            - 'null'
        source_id:
          type: string
        source_type:
          type: string
        truncated:
          type: boolean
        windows:
          items:
            $ref: '#/components/schemas/AlertMatchWindow'
          type:
            - array
            - 'null'
      required:
        - id
        - monitor_id
        - alert_id
        - kind
        - entity_type
        - entity_id
        - source_type
        - source_id
        - detected_at
        - mention_count
        - deliveries
      type: object
    ErrorDetail:
      additionalProperties: false
      properties:
        location:
          description: >-
            Where the error occurred, e.g. 'body.items[3].tags' or
            'path.thing-id'
          type: string
        message:
          description: Error message text
          type: string
        value:
          description: The value at the given location
      type: object
    ErrorResolve:
      additionalProperties: false
      properties:
        action:
          type: string
        endpoint:
          type: string
        message:
          type: string
        method:
          type: string
        url:
          type: string
      required:
        - message
      type: object
    AlertDeliverySummary:
      additionalProperties: false
      properties:
        channel:
          type: string
        created_at:
          format: date-time
          type: string
        error_message:
          type: string
        id:
          type: string
        sent_at:
          format: date-time
          type: string
        status:
          description: >-
            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).
          type: string
      required:
        - id
        - channel
        - status
        - created_at
      type: object
    AlertMatchEpisode:
      additionalProperties: false
      properties:
        apple_podcasts_url:
          description: >-
            Apple Podcasts deep-link for the parent podcast. Omitted when the
            podcast has no iTunes ID.
          type: string
        audio_url:
          description: >-
            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.
          type: string
        duration_seconds:
          description: Total episode duration in seconds. Omitted when unknown.
          format: double
          type: number
        explicit:
          description: >-
            Whether the episode is flagged as containing explicit content by its
            publisher.
          type: boolean
        image_url:
          description: >-
            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.
          type: string
        podcast_bias:
          description: >-
            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.
          enum:
            - EXTREME_LEFT
            - LEANS_LEFT
            - LEFT
            - CENTER
            - RIGHT
            - LEANS_RIGHT
            - EXTREME_RIGHT
          type: string
        podcast_id:
          type: string
        podcast_image_url:
          description: >-
            Parent podcast's image. Suitable as a fallback when image_url is
            absent.
          type: string
        podcast_popularity:
          description: >-
            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.
          format: double
          type: number
        podcast_popularity_badge:
          description: >-
            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%.
          enum:
            - Top Podcast
            - Very Popular
            - Popular
          type: string
        podcast_slug:
          type: string
        podcast_title:
          type: string
        published_at:
          format: date-time
          type: string
        slug:
          type: string
        title:
          type: string
      required:
        - title
        - podcast_id
        - podcast_title
      type: object
    AlertMatchWindow:
      additionalProperties: false
      properties:
        clip_description:
          type: string
        clip_id:
          type: string
        clip_intro_statement:
          type: string
        clip_title:
          type: string
        clip_type:
          type: string
        end_seconds:
          format: double
          type: number
        lines:
          items:
            $ref: '#/components/schemas/AlertMatchLine'
          type:
            - array
            - 'null'
        segment_description:
          type: string
        segment_id:
          type: string
        segment_summary:
          type: string
        segment_title:
          type: string
        segment_type:
          type: string
        start_seconds:
          format: double
          type: number
      required:
        - start_seconds
        - end_seconds
        - lines
      type: object
    AlertMatchLine:
      additionalProperties: false
      properties:
        end_seconds:
          format: double
          type: number
        is_mention:
          type: boolean
        number:
          format: int64
          type: integer
        role:
          type: string
        speaker:
          type: string
        start_seconds:
          format: double
          type: number
        text:
          type: string
      required:
        - start_seconds
        - end_seconds
        - text
      type: object
  securitySchemes:
    ApiKeyHeader:
      description: Pass your API key in the X-API-Key header (recommended).
      in: header
      name: X-API-Key
      type: apiKey
    BearerAuth:
      description: Pass your API key as a Bearer token in the Authorization header.
      scheme: bearer
      type: http

````