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

# List engagement signals

> The people who engaged with posts your watches are following.

**To poll:** call with no cursor, process the events, save `next_cursor`, and pass it back next time to get whatever has arrived since. `next_cursor` comes back on every non-empty page, including the last one; `has_more: false` means you are caught up, not that the feed has ended.

**Delivery is at-least-once.** Each event carries a stable `id`; store the ids you have processed and skip repeats rather than assuming an event arrives exactly once.

Filter with `persona_id` to see only the engagers who matched a persona. Unfiltered, you get everyone the watch found, which is also how you tell "nobody relevant engaged" from "the personas are too narrow".

Distinct from [List ICP signals](/api-reference/icp-signal-watches/list-icp-signals), which reports things that happened to a *company*. Every event here is a *person* who did something.



## OpenAPI

````yaml /reference/openapi.yaml get /v2/engagement-signals
openapi: 3.1.0
info:
  title: Tamtam Public API
  version: 2.0.0
servers:
  - url: https://api.tamtam.ai/api
security: []
paths:
  /v2/engagement-signals:
    get:
      tags:
        - Engagement Watches
      summary: List engagement signals
      description: >-
        The people who engaged with posts your watches are following.


        **To poll:** call with no cursor, process the events, save
        `next_cursor`, and pass it back next time to get whatever has arrived
        since. `next_cursor` comes back on every non-empty page, including the
        last one; `has_more: false` means you are caught up, not that the feed
        has ended.


        **Delivery is at-least-once.** Each event carries a stable `id`; store
        the ids you have processed and skip repeats rather than assuming an
        event arrives exactly once.


        Filter with `persona_id` to see only the engagers who matched a persona.
        Unfiltered, you get everyone the watch found, which is also how you tell
        "nobody relevant engaged" from "the personas are too narrow".


        Distinct from [List ICP
        signals](/api-reference/icp-signal-watches/list-icp-signals), which
        reports things that happened to a *company*. Every event here is a
        *person* who did something.
      operationId: list-engagement-signals
      parameters:
        - description: >-
            Target account UUID. Required for staff callers; ignored for
            customer API keys (they always read their own account).
          explode: false
          in: query
          name: account_id
          schema:
            description: >-
              Target account UUID. Required for staff callers; ignored for
              customer API keys (they always read their own account).
            type: string
        - description: >-
            Only return engagers surfaced by this watch. Omit for every watch on
            the account.
          explode: false
          in: query
          name: watch_id
          schema:
            description: >-
              Only return engagers surfaced by this watch. Omit for every watch
              on the account.
            type: string
        - description: >-
            Repeatable. Only return engagers who matched at least one of these
            personas. Omit to include everyone the watch found, matched or not.
          explode: false
          in: query
          name: persona_id
          schema:
            description: >-
              Repeatable. Only return engagers who matched at least one of these
              personas. Omit to include everyone the watch found, matched or
              not.
            items:
              type: string
            type:
              - array
              - 'null'
        - description: >-
            Only return events detected at or after this RFC3339 timestamp.
            Prefer the cursor for sequential polling: since re-reads a window,
            the cursor advances through it.
          explode: false
          in: query
          name: since
          schema:
            description: >-
              Only return events detected at or after this RFC3339 timestamp.
              Prefer the cursor for sequential polling: since re-reads a window,
              the cursor advances through it.
            examples:
              - '2026-08-01T00:00:00Z'
            format: date-time
            type: string
        - description: >-
            Pagination cursor from a previous call. Save next_cursor and pass it
            back unchanged to fetch what has arrived since. Cursors stay valid
            indefinitely unless this endpoint returns a 400.
          explode: false
          in: query
          name: cursor
          schema:
            description: >-
              Pagination cursor from a previous call. Save next_cursor and pass
              it back unchanged to fetch what has arrived since. Cursors stay
              valid indefinitely unless this endpoint returns a 400.
            type: string
        - description: Maximum events to return.
          explode: false
          in: query
          name: limit
          schema:
            default: 100
            description: Maximum events to return.
            format: int32
            maximum: 500
            minimum: 1
            type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListEngagementSignalsResponseDto'
          description: OK
        default:
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ErrorModel'
          description: Error
      security:
        - apikeyAuth: []
        - bearerAuth: []
components:
  schemas:
    ListEngagementSignalsResponseDto:
      additionalProperties: false
      properties:
        events:
          description: >-
            Events in detection order, oldest first, so a consumer can walk
            forward without new arrivals reshuffling the page.
          items:
            $ref: '#/components/schemas/EngagementEventDto'
          type:
            - array
            - 'null'
        has_more:
          description: >-
            True when more events are already waiting. False means you are
            caught up, not that the feed is finished.
          type: boolean
        next_cursor:
          description: >-
            Pass back unchanged to fetch events detected after this page.
            Returned on every non-empty page, including the last: a feed has no
            end, only a current position.
          type: string
      required:
        - events
        - has_more
      type: object
    ErrorModel:
      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
        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
        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
    EngagementEventDto:
      additionalProperties: false
      properties:
        company_name:
          description: >-
            Their employer as LinkedIn reported it. Free text: this is not a
            resolved company, and carries no LinkedIn company ID.
          type: string
        country_code:
          description: >-
            Only present when we actually observed it. Absent means unknown,
            never assumed from the watch's own country filter.
          type: string
        detected_at:
          description: When we recorded it. This is the order the feed is paginated in.
          examples:
            - '2026-08-14T09:15:00Z'
          format: date-time
          type: string
        id:
          description: >-
            Stable event id. This feed is at-least-once: store processed ids and
            skip repeats rather than assuming each event arrives exactly once.
          examples:
            - 9b7d5f2e-1c3a-4f8b-9e6d-2a1b3c4d5e6f
          type: string
        interaction_type:
          description: How they engaged. Currently always Liker.
          examples:
            - Liker
          type: string
        job_title:
          description: >-
            Their job title as LinkedIn reported it alongside the reaction. Free
            text, not a resolved title.
          type: string
        matched_persona_ids:
          description: >-
            Which of the watch's personas this person matched. Empty means they
            matched none, or that the watch filters on no personas at all — both
            are kept, so widening a persona later surfaces people already
            collected.
          items:
            type: string
          type:
            - array
            - 'null'
        occurred_at:
          description: >-
            When the engagement happened. LinkedIn does not timestamp a
            reaction, so this is when the sweep saw it.
          examples:
            - '2026-08-14T09:14:22Z'
          format: date-time
          type: string
        payload:
          additionalProperties: {}
          description: Provider detail not promoted to a field.
          type: object
        post_url:
          description: The watched post they engaged with.
          type: string
        profile_url:
          description: LinkedIn profile URL of the person who engaged.
          examples:
            - https://www.linkedin.com/in/jane-doe
          type: string
        watch_id:
          description: The engagement watch that surfaced this person.
          type: string
      required:
        - id
        - watch_id
        - interaction_type
        - profile_url
        - matched_persona_ids
        - occurred_at
        - detected_at
        - payload
      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
  securitySchemes:
    apikeyAuth:
      description: Account API key passed in the Authorization header
      in: header
      name: Authorization
      type: apiKey
    bearerAuth:
      description: Bearer JWT obtained via the OAuth 2.1 authorization flow
      scheme: bearer
      type: http

````