---
title: "Search timeline"
method: POST
path: "/api/timeline/search"
tags: ["timeline"]
---

# Search timeline

`POST /api/timeline/search`

## Request

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

Everything that happened to one person, newest first, one act one row: their messages on every channel (ours as sends with their outcomes, theirs as replies), the ledger's facts (invites, accepts, visits, likes, stage moves, tags, tables, workflow steps), the thread pills, the tasks and the live plan, merged from the inbox and the playtables ledger through one cursor. Scope by person_sid (the whole person) or conversation_sid (a thread; linked, it is its person's timeline). Read the row in the slot kind names; a child row (an open, a click, a bounce, an accept, the invite's note) names its parent in refers_to, so fold it rather than counting it twice. No total and no counts: page with the cursor while has_more. For a thread's signals (opened, clicked, no reply, and for how long) ask get_conversation with include signals instead. 503 playtables_unavailable when playtables does not answer the ledger read: never an empty page, try again later.

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

## Request body

- SearchTimelineRequest: Request body of `search_timeline`.
  - `filter` object, required: Exactly one of person_sid and conversation_sid; both or neither is a 422.
    - `person_sid` string: The person's whole timeline: every conversation of theirs on every channel and every ledger fact of the row.
    - `conversation_sid` string: A thread. Linked to a person, it reads as that person's timeline (every conversation, the ledger); unlinked, as its own rows.
  - `page_size` integer: 1..200, default 50: the merged page. Each source contributes up to that many rows, and a page may run shorter when a source holds rows back behind the watermark; has_more is the only end signal.
  - `cursor` string, nullable: The composite cursor from the previous page's pagination.next_cursor (opaque: every source's position). Omit it for the newest page.

## Response `200`

`search` success envelope.

- SearchTimelineResponse
  - `success` true, required
  - `operation` 'search', required
  - `items` object[], required
    - `item` object, required
      - `key` string, required: Stable per row: message:ub_ms_..., fact:cr_ac_..., event:ub_ev_..., task:ub_tk_..., plan:ub_pl_....
      - `kind` 'message' | 'fact' | 'event' | 'task' | 'plan', required: The store the row came from; read the slot it names (message, activity, event, task or plan) and nothing else.
      - `at` string, required: ISO 8601 UTC, the sort instant: a message's created_at, a fact's occurred_at, a pill's, a task's or a plan's created_at. Pages are ordered by it, newest first.
      - `conversation_sid` string, nullable, required: The rail: the thread the row belongs to. Null = the neutral rail, a fact of no conversation (a stage move, a tag, a table).
      - `channel` 'linkedin' | 'email', nullable, required: linkedin | email, or null on a pill, a task, the plan and a CRM fact.
      - `account_sid` string, nullable, required: The sender profile's channel account behind the row (the conversation's anchor of that channel; a fact's linkedin_account_sid / mailbox_sid), gtm's sid. Null when no account speaks for the row.
      - `refers_to` object, nullable, required: A child row's parent: set on an open, a click, a bounce, an accept, a withdrawal and the invite's note; null on every other row.
        - `kind` 'message' | 'invite', required: message: an open, a click or a bounce naming their email (ln_ms_... / em_ms_...); invite: an accept, a withdrawal or the invite's note naming their invite (ln_cr_...).
        - `gtm_sid` string, required: The parent's gtm sid. The parent is a message row (provider_message_sid) or the invite the ledger recorded; fold the child into it when it is in the window.
      - `context` object, nullable, required: The workflow context the ledger's sent fact lends a message row that carries no automation_ref of its own; null otherwise.
        - `workflow_sid` string, nullable, required: wf_wf_... or null.
        - `workflow_step_id` integer, nullable, required
        - `workflow_record_sid` string, nullable, required: wf_rc_... or null.
      - `message` object, nullable: kind message: the MessageDomain (// see ./messages.md), drafts included, a canceled draft never.
        - `sid` string, required
      - `activity` object, nullable: kind fact: the playtables ActivityDomain verbatim (type, category, payload, workflow_*, occurred_at, created_by; playtables // see activities.md).
        - `sid` string, required
      - `event` object, nullable: kind event: the ConversationEventDomain pill (// see ./conversation_events.md). workflow_action and engagement pills never appear here: the ledger's fact draws the act.
        - `sid` string, required
      - `task` object, nullable: kind task: the TaskDomain (// see ./tasks.md).
        - `sid` string, required
      - `plan` object, nullable: kind plan: the live AgentPlanDomain, proposed or active (// see ./agent_plans.md).
        - `sid` string, required
    - `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

## 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)
