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

# Get contact-level analytics (7 modules)

> Aggregates 7 analytics modules for a single contact: engagement score, pipeline position, calls, conversations, channel preferences, AI-vs-human handling and a paginated activity timeline. Results are cached server-side for 5 minutes per contact unless `force=true` is passed.



## OpenAPI

````yaml /api-reference/openapi.yaml get /api/contact-analytics/{contactId}
openapi: 3.0.3
info:
  title: Tether Relay and Tether API
  version: 1.0.0
  description: >-
    Route-derived OpenAPI contract generated from tether-relay backend sources.
    Regenerate with scripts/sync-openapi-from-backend.mjs.
servers:
  - url: https://your-instance.example.com
    description: Production
  - url: http://localhost:2212
    description: Local API service
security: []
tags:
  - name: AI
  - name: Applications
  - name: Approval
  - name: Auth
  - name: Automations
  - name: Calls
  - name: Campaigns
  - name: Contact Analytics
  - name: Contact Metrics
  - name: Contact Notes
  - name: Contacts
  - name: Conversation Monitor
  - name: Conversations
  - name: Departments
  - name: Email
  - name: Escalation Dashboard
  - name: Event Logs
  - name: Google Sheets
  - name: Marketplace
  - name: Messages
  - name: Notification Sounds
  - name: Notifications
  - name: Org Snapshots
  - name: Organizations
  - name: Outreach
  - name: Outreach Metrics
  - name: Outreach Sources
  - name: Pipelines
  - name: Processes
  - name: Prompts
  - name: Reminders
  - name: Sms
  - name: Templates
  - name: Traces
  - name: Training
  - name: Upload
  - name: User Snapshots
  - name: Users
  - name: Vertical
  - name: Webchats
  - name: Webhook
paths:
  /api/contact-analytics/{contactId}:
    get:
      tags:
        - Contact Analytics
      summary: Get contact-level analytics (7 modules)
      description: >-
        Aggregates 7 analytics modules for a single contact: engagement score,
        pipeline position, calls, conversations, channel preferences,
        AI-vs-human handling and a paginated activity timeline. Results are
        cached server-side for 5 minutes per contact unless `force=true` is
        passed.
      operationId: get_contact_analytics
      parameters:
        - in: path
          name: contactId
          required: true
          schema:
            type: string
        - in: query
          name: timelineLimit
          required: false
          schema:
            type: string
        - in: query
          name: timelinePage
          required: false
          schema:
            type: string
        - in: query
          name: force
          required: false
          schema:
            type: string
            enum:
              - 'true'
          description: >-
            Pass `true` to bypass the 5-minute in-memory cache (used by the
            refresh button).
      responses:
        '200':
          description: Contact analytics returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactAnalyticsResponse'
        '400':
          description: Invalid contact ID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactAnalyticsErrorResponse'
        '404':
          description: Contact not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactAnalyticsErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactAnalyticsErrorResponse'
      security:
        - bearerAuth: []
components:
  schemas:
    ContactAnalyticsResponse:
      type: object
      properties:
        success:
          type: boolean
          enum:
            - true
        data:
          type: object
          properties:
            engagement:
              $ref: '#/components/schemas/ContactAnalyticsEngagement'
            pipeline:
              $ref: '#/components/schemas/ContactAnalyticsPipeline'
            calls:
              $ref: '#/components/schemas/ContactAnalyticsCalls'
            conversations:
              $ref: '#/components/schemas/ContactAnalyticsConversations'
            channels:
              $ref: '#/components/schemas/ContactAnalyticsChannels'
            aiVsHuman:
              $ref: '#/components/schemas/ContactAnalyticsAiVsHuman'
            timeline:
              $ref: '#/components/schemas/ContactAnalyticsTimeline'
          required:
            - engagement
            - pipeline
            - calls
            - conversations
            - channels
            - aiVsHuman
            - timeline
          additionalProperties: true
      required:
        - success
        - data
      additionalProperties: true
      example:
        success: true
        data:
          engagement:
            score: 72
            trend: warming
            label: Active
            daysSinceLastInteraction: 2
          pipeline:
            currentStage: qualified
            daysInCurrentStage: 4
            stageHistory: []
          calls:
            total: 8
            answered: 5
            unanswered: 3
            answerRate: 0.625
          conversations:
            total: 4
            resolved: 3
            resolutionRate: 0.75
            csatAverage: 4.6
          channels:
            preferred: sms
            ranked:
              - sms
              - email
            breakdown:
              sms: 12
              email: 4
          aiVsHuman:
            breakdown:
              AI: 9
              HUMAN: 7
            escalationCount: 1
          timeline:
            total: 47
            page: 1
            limit: 25
            totalPages: 2
            events: []
    ContactAnalyticsErrorResponse:
      type: object
      description: >-
        Error envelope returned by contact-analytics endpoints. Errors are
        returned as `{ error: <message> }`.
      properties:
        error:
          type: string
      additionalProperties: true
      example:
        error: Contact not found
    ContactAnalyticsEngagement:
      type: object
      properties:
        score:
          type: integer
          description: 0–100 engagement score (recency + activity vs baseline).
        trend:
          type: string
          enum:
            - warming
            - cooling
            - stable
        label:
          type: string
          enum:
            - Active
            - Moderate
            - Inactive
        daysSinceLastInteraction:
          type: integer
          nullable: true
        baselinePerMonth:
          type: number
        recentInteractions:
          type: integer
        callsLast30d:
          type: integer
        messagesLast30d:
          type: object
          properties:
            inbound:
              type: integer
            outbound:
              type: integer
          additionalProperties: true
        messagesLast7d:
          type: object
          properties:
            inbound:
              type: integer
            outbound:
              type: integer
          additionalProperties: true
      additionalProperties: true
      example:
        score: 72
        trend: warming
        label: Active
        daysSinceLastInteraction: 2
        baselinePerMonth: 8.5
        recentInteractions: 14
        callsLast30d: 3
        messagesLast30d:
          inbound: 7
          outbound: 11
        messagesLast7d:
          inbound: 2
          outbound: 3
    ContactAnalyticsPipeline:
      type: object
      properties:
        currentStage:
          type: string
          nullable: true
        currentPipelineId:
          type: string
          nullable: true
        daysInCurrentStage:
          type: integer
          nullable: true
        stageHistory:
          type: array
          items:
            $ref: '#/components/schemas/ContactAnalyticsStageHistoryEntry'
      additionalProperties: true
      example:
        currentStage: qualified
        currentPipelineId: 66f0a0b0c0d0e0f0a0b0c0d0
        daysInCurrentStage: 4
        stageHistory:
          - fromStage: new
            toStage: qualified
            enteredAt: '2026-04-05T10:00:00.000Z'
            exitedAt: '2026-04-12T15:30:00.000Z'
            daysInStage: 7
    ContactAnalyticsCalls:
      type: object
      properties:
        total:
          type: integer
        answered:
          type: integer
        unanswered:
          type: integer
        answerRate:
          type: number
          description: 0..1 fraction.
        totalDurationSeconds:
          type: integer
        avgDurationSeconds:
          type: integer
        inbound:
          type: integer
        outbound:
          type: integer
        answeredByHuman:
          type: integer
        answeredByMachine:
          type: integer
        peakReachabilityHour:
          type: integer
          nullable: true
          description: 0..23 hour of day with the most completed calls.
      additionalProperties: true
      example:
        total: 8
        answered: 5
        unanswered: 3
        answerRate: 0.625
        totalDurationSeconds: 1240
        avgDurationSeconds: 248
        inbound: 2
        outbound: 6
        answeredByHuman: 4
        answeredByMachine: 1
        peakReachabilityHour: 14
    ContactAnalyticsConversations:
      type: object
      properties:
        total:
          type: integer
        resolved:
          type: integer
        resolutionRate:
          type: number
          description: 0..1 fraction.
        avgResolutionHours:
          type: number
          nullable: true
        csatAverage:
          type: number
          nullable: true
        csatCount:
          type: integer
        autopilotHandled:
          type: integer
      additionalProperties: true
      example:
        total: 4
        resolved: 3
        resolutionRate: 0.75
        avgResolutionHours: 18.4
        csatAverage: 4.6
        csatCount: 2
        autopilotHandled: 2
    ContactAnalyticsChannels:
      type: object
      properties:
        preferred:
          type: string
          nullable: true
        ranked:
          type: array
          items:
            type: string
        breakdown:
          type: object
          description: Channel → weighted-inbound count.
          additionalProperties:
            type: integer
      additionalProperties: true
      example:
        preferred: sms
        ranked:
          - sms
          - email
          - webchat
        breakdown:
          sms: 12
          email: 4
          webchat: 1
    ContactAnalyticsAiVsHuman:
      type: object
      properties:
        breakdown:
          type: object
          description: >-
            Sender type → message count. Senders are normalised: `CONTACT` is
            reported as `HUMAN`.
          additionalProperties:
            type: integer
        escalationCount:
          type: integer
      additionalProperties: true
      example:
        breakdown:
          AI: 9
          HUMAN: 7
          SYSTEM: 1
        escalationCount: 1
    ContactAnalyticsTimeline:
      type: object
      properties:
        total:
          type: integer
        page:
          type: integer
        limit:
          type: integer
        totalPages:
          type: integer
        events:
          type: array
          items:
            $ref: '#/components/schemas/ContactAnalyticsTimelineEvent'
      additionalProperties: true
      example:
        total: 47
        page: 1
        limit: 25
        totalPages: 2
        events:
          - _id: 67a0a0b0c0d0e0f0a0b0c0d0
            type: message
            createdAt: '2026-05-18T13:45:00.000Z'
            direction: inbound
            channelType: sms
            senderType: HUMAN
            preview: Yes please, let's book the demo.
    ContactAnalyticsStageHistoryEntry:
      type: object
      properties:
        fromStage:
          type: string
        toStage:
          type: string
        enteredAt:
          type: string
          format: date-time
        exitedAt:
          type: string
          format: date-time
          nullable: true
        daysInStage:
          type: integer
        pipelineId:
          type: string
          nullable: true
      additionalProperties: true
      example:
        fromStage: new
        toStage: qualified
        enteredAt: '2026-04-05T10:00:00.000Z'
        exitedAt: '2026-04-12T15:30:00.000Z'
        daysInStage: 7
        pipelineId: 66f0a0b0c0d0e0f0a0b0c0d0
    ContactAnalyticsTimelineEvent:
      type: object
      description: Polymorphic timeline event. `type` discriminates the shape.
      properties:
        _id:
          type: string
        type:
          type: string
          enum:
            - message
            - call
            - note
            - stage_change
        createdAt:
          type: string
          format: date-time
        direction:
          type: string
          enum:
            - inbound
            - outbound
          description: message/call only.
        channelType:
          type: string
          description: message only.
        senderType:
          type: string
          description: message only.
        preview:
          type: string
          nullable: true
          description: message/note only — first 100 chars.
        status:
          type: string
          description: call only.
        duration:
          type: integer
          description: call only — seconds.
        fromStage:
          type: string
          description: stage_change only.
        toStage:
          type: string
          description: stage_change only.
      additionalProperties: true
      example:
        _id: 67a0a0b0c0d0e0f0a0b0c0d0
        type: message
        createdAt: '2026-05-18T13:45:00.000Z'
        direction: inbound
        channelType: sms
        senderType: HUMAN
        preview: Yes please, let's book the demo.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````