---
title: "Search conversation events"
method: POST
path: "/api/conversation-events/search"
tags: ["conversation_events"]
---

# Search conversation events

`POST /api/conversation-events/search`

## Request

- Base URL: `https://beta.getsales.io/unibox/v1`
- URL: `https://beta.getsales.io/unibox/v1/api/conversation-events/search`
- Auth: HTTP bearer and API key in header `Team-SID`

Read a thread's timeline pills: the append-only facts between the message bubbles (what the agent classified, escalations, caps, person link and merge, workflow pause and resume, snoozes, dialog stages). conversation_sid.eq plus created_at.lt pages back past the events_tail get_conversation already returned; kind.eq plus a created_at window answers audit questions across threads. Merge with search_messages by created_at to narrate a thread. NOT the agent's execution ledger, which is its runs.

Contract:
- MCP tool `search_conversation_events`, registry package `mcp.unibox/conversation_events`, mount `unibox.inbox`.
- Operation `search`, response envelope `search`.
- Flags: read only.

## Request body

- SearchConversationEventsRequest: Request body of `search_conversation_events`.
  - `filter` object: Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row.
    - `sid` object: Event sid(s), ub_ev_ prefix - also the point lookup (there is no get tool).
      - `eq` string: Conversation event sid (ub_ev_…).
      - `in` string[]
    - `conversation_sid` object: The thread(s) to page; the main scope, paired with a created_at bound.
      - `eq` string: Conversation sid (ub_cv_…) - the thread the pill belongs to.
      - `in` string[]
    - `kind` object: One or more pill kinds, for the audit reads ("what did the agent escalate this week").
      - `eq` 'classified' | 'engagement' | 'workflow_paused' | 'workflow_resumed' | 'workflow_action' | 'person_link_suggested' | 'person_linked' | 'person_unlinked' | 'merged' | 'mode_override_changed' | 'escalated' | 'cap_reached' | 'agent_blocked' | 'snoozed' | 'task_created' | 'participants_added' | 'handed_over' | 'draft_withdrawn' | 'post_liked' | 'channel_notice' | 'dialog_engaged' | 'dialog_stage_advanced' | 'dialog_objective_reached' | 'dialog_ended' | 'dialog_fact_saved' | 'picked_up' | 'followups_planned' | 'followups_scheduled' | 'followups_declined'
      - `in` string[]
    - `created_at` object: ISO 8601 range; lt the oldest created_at you already hold is how you page a thread backwards.
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
  - `sort` object: One column and its direction; omit for the default order.
    - `field` 'created_at', required: The column to order by.
    - `direction` 'asc' | 'desc': asc or desc; default desc.
  - `page_size` integer: 0..500, default 50; 0 = counts only, 1 = the first row.
  - `cursor` string, nullable: pagination.next_cursor of the previous page.

## Response `200`

`search` success envelope.

- SearchConversationEventsResponse
  - `success` true, required
  - `operation` 'search', required
  - `items` object[], required
    - `item` object, required
      - `sid` string, required: Conversation event sid (ub_ev_…).
      - `team_sid` string, required: Owning team (ts_tm_…, external - gs.service.id).
      - `conversation_sid` string, required: The thread this pill sits on (ub_cv_…). A merge re-parents the pill onto the target thread by rewriting this field.
      - `kind` 'classified' | 'engagement' | 'workflow_paused' | 'workflow_resumed' | 'workflow_action' | 'person_link_suggested' | 'person_linked' | 'person_unlinked' | 'merged' | 'mode_override_changed' | 'escalated' | 'cap_reached' | 'agent_blocked' | 'snoozed' | 'task_created' | 'participants_added' | 'handed_over' | 'draft_withdrawn' | 'post_liked' | 'channel_notice' | 'dialog_engaged' | 'dialog_stage_advanced' | 'dialog_objective_reached' | 'dialog_ended' | 'dialog_fact_saved' | 'picked_up' | 'followups_planned' | 'followups_scheduled' | 'followups_declined', required: What happened. The client renders the pill from this plus payload; the set grows additively, so treat an unknown kind as a generic entry rather than an error.
      - `actor` object, required: Who caused the fact. actor_type system = an ingest or policy path, user = a person acting in the inbox, agent = the AI SDR.
        - `actor_type` 'user' | 'support' | 'api_key' | 'system' | 'agent', required
        - `actor_sid` string, nullable, required
        - `team_sid` string, required
        - `actor_name` string, nullable: The OAuth client that acted ("Claude", "n8n"); null for a user, an API key or a system job.
        - `oauth_client_sid` string, nullable: The acting OAuth client (id_oc_*); null off the OAuth path.
        - `reason` string, nullable: Why a system actor wrote the row (snapshot_capture_job, ...); null otherwise.
        - `permissions` object, required: Internal audit context: the grant set the actor held at write time. Not a contract.
        - `cluster_id` integer, nullable: Internal audit context: the cluster that served the write.
        - `trace_id` string, nullable: Internal audit context: the trace id of the request that wrote the row.
      - `payload` union, required: Kind-keyed detail: sids, scenario keys, dates, counts (classified carries scenario_key / confidence / reason / summary, two sentences by the classifier on where the lead stands, cap_reached carries cap / used / max / plan_sid, escalated carries trigger / custom_trigger / note / task_sid / deduped, snoozed carries snoozed_until / source / plan_sid). Never a message body. Serialized as [] when empty.
        - object
        - unknown[]
          - unknown
      - `created_at` string, required: ISO 8601 UTC - the timeline position, and the key the client merges pills and messages on.
      - `updated_at` string, required: ISO 8601 UTC. Not an edit marker: a pill is never rewritten, so this equals created_at unless a thread merge re-parented the row.
    - `included` object, required
  - `pagination` object, required
    - `next_cursor` string, nullable, required
    - `has_more` boolean, required
    - `total_count` integer, nullable, required
  - `applied_filters` object, required
  - `includes` string[], required
  - `meta` object, required
    - `trace_id` string, required: UUID v7; same 128-bit value as the X-Trace-Id header.
    - `span_id` string, required: 16 hex chars, root span of this request.
    - `timestamp` string, required: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
    - `duration_ms` integer, required: Server-side wall clock.
    - `team_sid` string, nullable: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
    - `actor_type` string, nullable: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
  - `counts` object
    - `total_count` integer, required: Events matching the filter (full filter scope, not the page).
    - `groups` union, required: Always empty: this entity declares no group axes, so the backend sends [].
      - object
      - unknown[]
        - unknown

## Other responses

- `4XX`: MCP error envelope. `error.code` is one of validation_failed, nothing_to_update, not_found, relation_not_found, invalid_transition, limit_exceeded, payment_required, duplicate_rejected, conflict, delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
- `5XX`: MCP error envelope with `error.code` internal_error or service_unavailable.

---

[API](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-unibox.md) - [All operations](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-unibox/llms.txt) - [OpenAPI document](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-unibox/revisions/8f1bc317897f?raw)
