---
title: "Customer Timeline"
method: GET
path: "/crm/contacts/{contact_id}/timeline"
tags: ["authenticated", "crm"]
---

# Customer Timeline

`GET /crm/contacts/{contact_id}/timeline`

## Request

- Base URL: `https://api-docs.upsmith.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api-docs.upsmith.com/crm/contacts/{contact_id}/timeline`
- Auth: one of:
  - API key in header `x-api-key`
  - HTTP bearer

## Path parameters

- `contact_id` string, required

## Query parameters

- `cursor` string, nullable
- `limit` integer
- `flatten_messages` boolean
- `flatten_events` boolean
- `group_voice_engagements` boolean
- `exclude_engagement_id` string, nullable
- `include_service_titan_events` boolean
- `include_ai_response_changes` boolean
- `include_call_tag_results` boolean
- `include_notes` boolean

## Headers

- `organization-id` string, nullable
- `x-user-id` string, nullable
- `timezone` string
- `x-actor-email` string, nullable
- `x-request-source` string, nullable
- `x-operation-id` string, nullable
- `x-commit-message` string, nullable
- `x-confirmation-id` string, nullable
- `x-chat-id` string, nullable

## Response `200`

Successful Response

- CustomerTimelinePagePublic
  - `items` union[], required
    - union
      - CustomerTimelineEngagementPublic
        - `kind` 'engagement'
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `status` string, required
        - `agent_id` string, nullable
        - `agent_name` string, nullable
        - `agent_roster_name` string, nullable
        - `is_voice` boolean
        - `voice_abort_reason` string, nullable
        - `call_duration_seconds` integer, nullable
        - `call_transferred_at` string, date-time, nullable
        - `messages` CustomerTimelineMessagePublic[], required
          - `id` string, required
          - `occurred_at` string, date-time, required
          - `role` string, required
          - `content` string, required
          - `status` string, required
          - `user_id` string, nullable
          - `user_name` string, nullable
          - `contact_method_id` string, nullable
          - `image_id` string, nullable
          - `image` string, nullable
          - `image_content_type` string, nullable
          - `delivery_failure_reason` string, nullable
          - `media_urls` string[]
      - CustomerTimelineMessageEventPublic
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `role` string, required
        - `content` string, required
        - `status` string, required
        - `user_id` string, nullable
        - `user_name` string, nullable
        - `contact_method_id` string, nullable
        - `image_id` string, nullable
        - `image` string, nullable
        - `image_content_type` string, nullable
        - `delivery_failure_reason` string, nullable
        - `media_urls` string[]
        - `kind` 'message'
        - `engagement_id` string, required
        - `agent_id` string, nullable
        - `agent_name` string, nullable
        - `agent_roster_name` string, nullable
      - CustomerTimelineEventPublic
        - `kind` 'event'
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `engagement_id` string, required
        - `source` string, nullable
        - `lsa_account_name` string, nullable
        - `agent_id` string, nullable
        - `agent_name` string, nullable
        - `agent_roster_name` string, nullable
        - `event` TimelineEventPublic, required
          - `id` string, required
          - `organization_id` string, required
          - `engagement_id` string, required
          - `origin` 'internal' | 'external', required
          - `role` 'user' | 'agent' | 'contact' | 'provider', required
          - `type` 'action' | 'interaction' | 'llm_response', required
          - `user_id` string, nullable
          - `created_at` string, date-time, required
          - `updated_at` string, date-time, required
          - `deleted_at` string, date-time, nullable
          - `user_initials` string, nullable
          - `interaction` TimelineEventInteractionPublic
            - `id` string, required
            - `channel_id` string, required
            - `contact_method_id` string, nullable
            - `image_id` string, nullable
            - `external_id` string, nullable
            - `twilio_message_status` string, nullable
            - `twilio_error_code` string, nullable
            - `telnyx_message_status` string, nullable
            - `telnyx_error_code` string, nullable
            - `metadata_json` object, nullable
            - `status` 'pending' | 'delivered' | 'received' | 'failed', required
            - `content` string, required
            - `translated_content` string, nullable
            - `deliver_after` string, date-time, nullable
            - `image` string, nullable
            - `image_content_type` string, nullable
            - `contact_method` ContactMethodPublic
              - …
          - `action` TimelineEventActionPublic
            - `id` string, required
            - `tool_module_id` string, required
            - `success` boolean, nullable
            - `type` 'booking' | 'booking_request'
            - `invocation_source` 'llm' | 'precall': Who invoked the tool that produced this action. ``LLM`` — the agent's model chose to call the tool mid-conversation. ``PRECALL`` — the system/operator ran the tool up front (before-turn hooks / pre-agent preload) and injected the result into the prompt; the model did not choose it. ``NULL`` means **legacy / unknown** — the row predates reliable tagging (ENG-4234) and is NOT necessarily LLM-invoked. Precalled tools were saved as actions before #4213 (2026-04-04), then not saved at all until ENG-4234, so historical rows are a mix we deliberately don't reconstruct. Readers must treat NULL as its own bucket, never fold it into ``LLM``. Only rows written after ENG-4234 shipped carry a trustworthy value.
            - `input` string, required
            - `output` string, required
            - `tool_module` ToolModulePublic
              - …
          - `llm_response` EventLLMResponsePublic
            - `id` string, required
            - `phase` 'ModelRequest' | 'ModelResponse', required: Phase for persisted LLM transcript rows. Like other engagement ``StrEnum`` + ``sa.Enum(native_enum=False)`` columns, PostgreSQL stores the member **name** (``REQUEST`` / ``RESPONSE``) for ``llmphase``. The **value** strings are pydantic-ai message kinds (``ModelRequest`` / ``ModelResponse``) and are not written to this column.
            - `model` string, required
            - `content` union
              - …
            - `duration_ms` integer, nullable
      - CustomerTimelineCallPublic
        - `kind` 'call'
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `call_id` integer, required
        - `upsmith_call_id` string, nullable
        - `matched_engagement_ids` string[]
        - `direction` string, required
        - `status` string, required
        - `call_type` string, nullable
        - `duration` string, nullable
        - `from_number` string, nullable
        - `to_number` string, nullable
        - `agent_name` string, nullable
        - `reason_name` string, nullable
        - `campaign_name` string, nullable
        - `has_voicemail` boolean
        - `has_audio` boolean, required
        - `has_transcript` boolean, required
        - `recovery_options` CustomerCallMediaRecoveryPublic[]
          - `kind` 'recording' | 'voicemail', required
          - `status` 'missing' | 'queued' | 'processing' | 'complete' | 'retryable' | 'unavailable', required
          - `can_recover` boolean, required
          - `will_transcribe` boolean, required
          - `reason` 'processing_disabled' | 'recording_length' | 'outbound_policy' | 'covered_by_other_recording' | 'not_found' | 'download_failed', nullable
        - `counterparty_type` 'customer' | 'technician' | 'employee' | 'unknown'
        - `counterparty_name` string, nullable
        - `tag_results` CallTagResultPublic[]
          - `id` string, required
          - `subject_type` 'engagement' | 'call' | 'both', required
          - `subject_id` string, required
          - `tag_definition_id` string, required
          - `tag_definition_revision` TagResultDefinitionRevisionPublic
            - `id` string, required
            - `revision_number` integer, required
            - `key` string, required
            - `label` string, required
            - `description` string, nullable
            - `value_type` 'string' | 'integer' | 'float' | 'boolean' | 'string_list' | 'integer_list' | 'json', required
            - `validation_schema` object, nullable
            - `success_values` unknown[], nullable
              - …
            - `optional` boolean, required
            - `sort_order` integer, required
            - `system_contract_version` integer, nullable
            - `system_input_policy` object, nullable
          - `tag_evaluation_run_id` string, nullable
          - `model_value` unknown
          - `user_override_value` unknown
          - `effective_value` unknown
          - `override_tag_definition_revision_id` string, nullable
          - `override_tag_evaluation_run_id` string, nullable
          - `override_provenance_state` 'not_overridden' | 'current' | 'stale'
          - `override_provenance_stale_reasons` OverrideProvenanceStaleReason[]
          - `override_reason` string, nullable
          - `reasoning` string, nullable
          - `tagged_by` 'system' | 'user', required
          - `tagged_at` string, date-time, nullable
          - `overridden_by_user_id` string, nullable
          - `overridden_at` string, date-time, nullable
          - `evidence` TagEvidencePublic[]
            - `id` string, required
            - `segment_id` string, nullable
            - `speaker_label` string, nullable
            - `start_seconds` number, nullable
            - `end_seconds` number, nullable
            - `excerpt` string, required
          - `upsmith_call_id` string, nullable
          - `service_titan_call_id` integer, nullable
      - CustomerTimelineScheduledActionPublic
        - `kind` 'scheduled_action'
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `engagement_id` string, required
        - `source` string, required
        - `trigger_type` string, nullable
        - `source_event_id` string, nullable
        - `hook_config_id` string, nullable
        - `hook_name` string, nullable
        - `agent_id` string, nullable
        - `agent_name` string, nullable
        - `agent_roster_name` string, nullable
      - CustomerTimelineServiceTitanEventPublic
        - `kind` 'service_titan_event'
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `event_type` string, required
        - `title` string, required
        - `description` string, nullable
        - `status` string, nullable
        - `amount` string, nullable
        - `job_id` integer, nullable
        - `appointment_id` integer, nullable
        - `campaign_id` integer, nullable
        - `scheduled_start` string, date-time, nullable
        - `scheduled_end` string, date-time, nullable
        - `fidelity` 'history' | 'snapshot', required
        - `job_number` string, nullable
        - `job_type_name` string, nullable
        - `technician_names` string[]
        - `service_titan_url` string, nullable
      - AiResponseChangeTimelinePublic
        - `kind` 'ai_response_change'
        - `id` string, required
        - `engagement_id` string, required
        - `occurred_at` string, date-time, required
        - `is_ai_allowed_to_respond` boolean, required
        - `source` string, required
        - `reason` string, nullable
        - `operator_name` string, nullable
      - CustomerTimelineNotePublic
        - `kind` 'note'
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `updated_at` string, date-time, required
        - `content` string, required
        - `created_by_user_id` string, required
        - `author_name` string, nullable
        - `can_edit` boolean
        - `can_delete` boolean
      - CustomerTimelineServiceTitanNotePublic
        - `kind` 'service_titan_customer_note' | 'service_titan_location_note', required
        - `id` string, required
        - `occurred_at` string, date-time, required
        - `updated_at` string, date-time, nullable
        - `content` string, required
        - `created_by_id` integer, nullable
        - `author_name` string, nullable
        - `is_pinned` boolean
        - `location_id` integer, nullable
        - `location_name` string, nullable
        - `location_address` string, nullable
  - `cursor` string, nullable
  - `has_service_titan_service_history` boolean, nullable
  - `latest_engagement_id` string, nullable
  - `customer_is_booked` boolean
  - `customer_can_unbook` boolean

## Other responses

- `422`: Validation Error

---

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