openapi: 3.1.0
info:
  title: HyperRep API
  version: 2.0.0
  description: >
    The HyperRep API is a RESTful API for accessing organizations, contacts,
    companies, agents, conversations, messages, sales, and analytics.
    All requests are authenticated with an API key passed in the X-API-KEY header.

servers:
  - url: https://api.hyperrep.ai

security:
  - ApiKeyAuth: []

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY

  schemas:

    Organization:
      type: object
      properties:
        organization_id:
          type: string
          example: gAAAAABexampleOrganizationIdReturnedByApi7mN4qP2xLs9dV5kTr8cY1hJ6uW3
        name:
          type: string
          example: Acme Roofing

    Contact:
      type: object
      properties:
        contact_id:
          type: string
          example: gAAAAABexampleContactIdReturnedByApi4pQ8xLm2sV7kRt1cN5hY9uJ3dF6
        name:
          type: string
          example: Diana Prince
        email:
          type: string
          example: diana.prince@example.com
        phone_number:
          type: string
          example: 513-867-5309
        created_at:
          type: string
          format: date-time
          example: "2026-03-12T00:32:13.782565Z"
        company_id:
          type: string
          nullable: true
          example: gAAAAABexampleCompanyIdReturnedByApi6vT2mQ9xLs4dK7pNc1hY5uJ8rF3
        notes:
          type: string
          nullable: true
          example: Prefers SMS
        company_role:
          type: string
          nullable: true
          example: Facilities Manager

    Company:
      type: object
      properties:
        company_id:
          type: string
          example: gAAAAABexampleCompanyIdReturnedByApi6vT2mQ9xLs4dK7pNc1hY5uJ8rF3
        name:
          type: string
          example: HyperRep Consumer Group
        domain:
          type: string
          nullable: true
          example: hyperrep.com
        notes:
          type: string
          nullable: true
          example: Priority account
        address:
          type: string
          nullable: true
          example: 123 Main St, Anytown USA
        agent_id:
          type: string
          nullable: true
          example: gAAAAABexampleAgentIdReturnedByApi5qN8xLm3sV6kRt2cY9hJ4uW1dF7
        created_at:
          type: string
          format: date-time
          example: "2026-03-10T12:00:00Z"

    Agent:
      type: object
      properties:
        agent_id:
          type: string
          example: gAAAAABexampleAgentIdReturnedByApi5qN8xLm3sV6kRt2cY9hJ4uW1dF7
        name:
          type: string
          example: Kara Danvers
        email:
          type: string
          nullable: true
          example: kara@example.com

    ConversationSummary:
      type: object
      properties:
        conversation_id:
          type: string
          example: gAAAAABexampleConversationIdReturnedByApi8kP3xLs7dV2mTr5cN9hY1uJ4
        start_at:
          type: string
          format: date-time
          example: "2026-04-29T14:00:00Z"
        last_activity_at:
          type: string
          format: date-time
          example: "2026-04-29T16:00:00Z"
        folder:
          type: string
          nullable: true
          example: inbox
        is_read:
          type: boolean
          example: false
        contact_id:
          type: string
          example: gAAAAABexampleContactIdReturnedByApi4pQ8xLm2sV7kRt1cN5hY9uJ3dF6

    EmailMetadata:
      type: object
      properties:
        email_message_id:
          type: string
          nullable: true
          example: "<177204662479.53482.15965180402643609222@mail.example.com>"
        cc_emails:
          type: array
          items:
            type: string
        bcc_emails:
          type: array
          items:
            type: string

    CallMetadata:
      type: object
      properties:
        duration:
          type: integer
          nullable: true
          description: Call duration in seconds.

    TrackedLink:
      type: object
      properties:
        link_id:
          type: string
          example: gAAAAABexampleTrackedLinkIdReturnedByApi3kL9xPs4qR2mTc7dN5hY8uV1
        url:
          type: string
          example: https://example.com/quote
          description: Original destination URL.
        click_count:
          type: integer
          example: 3
          description: Number of tracked clicks for this link.

    Message:
      type: object
      properties:
        message_id:
          type: string
          example: gAAAAABexampleMessageIdReturnedByApi9mT4xLs2qV7kRc5dN1hY8uJ3pF6
        conversation_id:
          type: string
          example: gAAAAABexampleConversationIdReturnedByApi8kP3xLs7dV2mTr5cN9hY1uJ4
        agent_id:
          type: string
          nullable: true
        modality:
          type: string
          example: email
          description: "Channel the message was sent through. Common values: email, call, text, live_chat."
        message_direction:
          type: string
          enum: [sent, received]
          example: sent
        is_form_request:
          type: boolean
          example: false
        subject:
          type: string
          nullable: true
          example: Following up on your inquiry
        content:
          type: string
          example: Hi Diana, just checking in on the quote we sent over last week.
        call_transcript:
          type: string
          nullable: true
        form_request_body:
          type: object
          nullable: true
          description: Submitted form data including UTM info and form fields. Null when is_form_request is false.
        sent_at:
          type: string
          format: date-time
          example: "2026-04-29T15:02:00Z"
        drafted_at:
          type: string
          format: date-time
          nullable: true
        email_metadata:
          $ref: '#/components/schemas/EmailMetadata'
        call_metadata:
          $ref: '#/components/schemas/CallMetadata'
        tracked_links:
          type: array
          items:
            $ref: '#/components/schemas/TrackedLink'

    AssociatedContact:
      type: object
      properties:
        contact_id:
          type: string
          example: gAAAAABexampleContactIdReturnedByApi4pQ8xLm2sV7kRt1cN5hY9uJ3dF6
        is_primary:
          type: boolean
          example: true

    QuoteProduct:
      type: object
      properties:
        quantity:
          type: integer
          example: 1
        unit_price:
          type: string
          example: "1200.00"
        product_name:
          type: string
          example: Legacy Seed Service

    QuoteDetails:
      type: object
      nullable: true
      properties:
        output:
          type: object
          properties:
            currency:
              type: string
              example: USD
            total_price:
              type: string
              example: "1200.00"
        arguments:
          type: object
          properties:
            products:
              type: array
              items:
                $ref: '#/components/schemas/QuoteProduct'

    StatusEvent:
      type: object
      properties:
        label:
          type: string
          example: Accepted
        status:
          type: string
          nullable: true
          description: Internal status key. null for the Qualified (first) stage.
          example: accepted
        changed_at:
          type: string
          format: date-time
          nullable: true
          example: "2026-03-13T01:28:41.829924Z"

    Sale:
      type: object
      properties:
        sale_id:
          type: string
          example: gAAAAABexampleSaleIdReturnedByApi2xLm8dV4kTr7cY1hJ5uN9qP3
        associated_conversation_ids:
          type: array
          items:
            type: string
        company_id:
          type: string
          example: gAAAAABexampleCompanyIdReturnedByApi6vT2mQ9xLs4dK7pNc1hY5uJ8rF3
        owner_id:
          type: string
          example: gAAAAABexampleAgentIdReturnedByApi5qN8xLm3sV6kRt2cY9hJ4uW1dF7
        associated_contacts:
          type: array
          items:
            $ref: '#/components/schemas/AssociatedContact'
        quote_details:
          $ref: '#/components/schemas/QuoteDetails'
        notes:
          type: string
          nullable: true
          example: Backfilled sale for new sales framework compatibility.
        current_status:
          $ref: '#/components/schemas/StatusEvent'
          nullable: true
        status_history:
          type: array
          items:
            $ref: '#/components/schemas/StatusEvent'
        created_at:
          type: string
          format: date-time
          example: "2026-03-12T01:28:41.829924Z"
        last_activity_at:
          type: string
          format: date-time
          example: "2026-03-12T01:28:41.829924Z"

    PipelineStage:
      type: object
      properties:
        name:
          type: string
          example: Qualified
        status:
          type: string
          nullable: true
          description: Internal status key. null for the first (Qualified) stage.
          example: null
        volume:
          type: integer
          example: 24
        value:
          type: string
          description: Total monetary value of sales in this stage as a decimal string.
          example: "28800.00"

    SalesAnalytics:
      type: object
      properties:
        pipeline:
          type: array
          items:
            $ref: '#/components/schemas/PipelineStage'
        salesRate:
          type: number
          format: float
          example: 0.46

    CursorPagination:
      type: object
      properties:
        limit:
          type: integer
          example: 25
        cursor:
          type: string
          nullable: true
        next_cursor:
          type: string
          nullable: true
        has_more:
          type: boolean

    OrganizationPage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Organization'

    ContactPage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Contact'
        pagination:
          $ref: '#/components/schemas/CursorPagination'

    CompanyPage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Company'
        pagination:
          $ref: '#/components/schemas/CursorPagination'

    AgentPage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Agent'
        pagination:
          $ref: '#/components/schemas/CursorPagination'

    ConversationPage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ConversationSummary'
        pagination:
          $ref: '#/components/schemas/CursorPagination'

    MessagePage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Message'
        pagination:
          $ref: '#/components/schemas/CursorPagination'

    SalePage:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Sale'
        pagination:
          $ref: '#/components/schemas/CursorPagination'

    CreateDraftRequest:
      type: object
      required: [modality]
      description: Request payload for creating a chat draft.
      properties:
        modality:
          type: string
          enum: [email, text]
          description: Draft delivery channel. The organization must have credentials configured for the selected modality.
        subject:
          type: string
          nullable: true
        body_html:
          type: string
          nullable: true
        to_user_name:
          type: string
          nullable: true
        to_email:
          type: string
          nullable: true
        to_phone_number:
          type: string
          nullable: true
        cc_emails:
          type: array
          items:
            type: string
        bcc_emails:
          type: array
          items:
            type: string
        autosend_draft:
          type: boolean
          default: false
        add_notification:
          type: boolean
          default: true
        folder:
          type: string
          nullable: true

    DraftCreateResponse:
      type: object
      required: [draft_id, queued_to_send, folder]
      description: Response payload after creating a chat draft.
      properties:
        draft_id:
          type: string
          example: gAAAAABexampleDraftIdReturnedByApi6pN8xLm3sV7kRt2cY5hJ9uW1dF4
        queued_to_send:
          type: boolean
        send_at:
          type: string
          format: date-time
          nullable: true
        folder:
          type: string
          example: drafts

    LegacySolution:
      type: object
      properties:
        uuid:
          type: string
          example: 550e8400-e29b-41d4-a716-446655440000
        name:
          type: string
          example: Acme Roofing

  parameters:
    organization_id:
      name: organization_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleOrganizationIdReturnedByApi7mN4qP2xLs9dV5kTr8cY1hJ6uW3

    contact_id:
      name: contact_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleContactIdReturnedByApi4pQ8xLm2sV7kRt1cN5hY9uJ3dF6

    company_id:
      name: company_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleCompanyIdReturnedByApi6vT2mQ9xLs4dK7pNc1hY5uJ8rF3

    agent_id:
      name: agent_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleAgentIdReturnedByApi5qN8xLm3sV6kRt2cY9hJ4uW1dF7

    conversation_id:
      name: conversation_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleConversationIdReturnedByApi8kP3xLs7dV2mTr5cN9hY1uJ4

    message_id:
      name: message_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleMessageIdReturnedByApi9mT4xLs2qV7kRc5dN1hY8uJ3pF6

    sale_id:
      name: sale_id
      in: path
      required: true
      schema:
        type: string
      example: gAAAAABexampleSaleIdReturnedByApi2xLm8dV4kTr7cY1hJ5uN9qP3

    limit:
      name: limit
      in: query
      required: false
      schema:
        type: integer
      description: Number of items to return.

    cursor:
      name: cursor
      in: query
      required: false
      schema:
        type: string
      description: Cursor value from a previous response to fetch the next page.

    start_date_optional:
      name: start_date
      in: query
      required: false
      schema:
        type: string
        format: date-time
      description: Optional. Filter results to items on or after this timestamp.
      example: "2026-04-01T00:00:00Z"

    end_date_optional:
      name: end_date
      in: query
      required: false
      schema:
        type: string
        format: date-time
      description: Optional. Filter results to items before this timestamp.
      example: "2026-04-30T23:59:59Z"

    start_date_required:
      name: start_date
      in: query
      required: true
      schema:
        type: string
        format: date-time
      description: Required. Inclusive start of the analytics window.
      example: "2026-04-01T00:00:00Z"

    end_date_required:
      name: end_date
      in: query
      required: true
      schema:
        type: string
        format: date-time
      description: Required. Exclusive end of the analytics window.
      example: "2026-04-30T23:59:59Z"

paths:

  # ── Organizations ──────────────────────────────────────────────────────────

  /api/v2/organizations:
    get:
      summary: List organizations
      operationId: listOrganizations
      tags: [Organizations]
      responses:
        '200':
          description: Organizations available to the API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrganizationPage'

  # ── Contacts ─────────────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/contacts:
    get:
      summary: List contacts
      operationId: listContacts
      tags: [Contacts]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
      responses:
        '200':
          description: Contacts for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContactPage'

  /api/v2/organizations/{organization_id}/contacts/{contact_id}:
    get:
      summary: Get a contact
      operationId: getContact
      tags: [Contacts]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/contact_id'
      responses:
        '200':
          description: A single contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'

  /api/v2/organizations/{organization_id}/contacts/{contact_id}/conversations:
    get:
      summary: List conversations for a contact
      operationId: listContactConversations
      tags: [Contacts]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/contact_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/start_date_optional'
        - $ref: '#/components/parameters/end_date_optional'
      responses:
        '200':
          description: Paginated conversations for the contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConversationPage'
        '404':
          description: Contact not found.

  # ── Companies ──────────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/companies:
    get:
      summary: List companies
      operationId: listCompanies
      tags: [Companies]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
      responses:
        '200':
          description: Companies for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyPage'

  /api/v2/organizations/{organization_id}/companies/{company_id}:
    get:
      summary: Get a company
      operationId: getCompany
      tags: [Companies]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/company_id'
      responses:
        '200':
          description: A single company.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Company'

  # ── Agents ─────────────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/agents:
    get:
      summary: List agents
      operationId: listAgents
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
      responses:
        '200':
          description: Agents for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentPage'

  /api/v2/organizations/{organization_id}/agents/{agent_id}:
    get:
      summary: Get an agent
      operationId: getAgent
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/agent_id'
      responses:
        '200':
          description: A single agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'

  /api/v2/organizations/{organization_id}/agents/{agent_id}/conversations:
    get:
      summary: List agent conversations
      operationId: listAgentConversations
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/agent_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/start_date_optional'
        - $ref: '#/components/parameters/end_date_optional'
      responses:
        '200':
          description: Paginated conversations owned by the agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConversationPage'

  /api/v2/organizations/{organization_id}/agents/{agent_id}/sales:
    get:
      summary: List agent sales
      operationId: listAgentSales
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/agent_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/start_date_optional'
        - $ref: '#/components/parameters/end_date_optional'
      responses:
        '200':
          description: Paginated sales owned by the agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SalePage'

  /api/v2/organizations/{organization_id}/agents/{agent_id}/analytics:
    get:
      summary: Get combined agent analytics
      operationId: getAgentAnalytics
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/agent_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Combined conversation and sales analytics for the agent.
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversations:
                    type: object
                    properties:
                      conversationsRespondedTo:
                        type: integer
                        description: Distinct conversations where the agent sent at least one response in the selected window.
                        example: 42
                      messagesSent:
                        type: integer
                        example: 118
                  sales:
                    $ref: '#/components/schemas/SalesAnalytics'

  /api/v2/organizations/{organization_id}/agents/{agent_id}/analytics/conversations:
    get:
      summary: Get agent conversation analytics
      operationId: getAgentConversationAnalytics
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/agent_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Conversation analytics for the agent.
          content:
            application/json:
              schema:
                type: object
                properties:
                  conversationsRespondedTo:
                    type: integer
                    description: Distinct conversations where the agent sent at least one response in the selected window.
                    example: 42
                  messagesSent:
                    type: integer
                    example: 118

  /api/v2/organizations/{organization_id}/agents/{agent_id}/analytics/sales:
    get:
      summary: Get agent sales analytics
      operationId: getAgentSalesAnalytics
      tags: [Agents]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/agent_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Sales analytics for the agent.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SalesAnalytics'

  # ── Conversations ──────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/conversations:
    get:
      summary: List conversations
      operationId: listConversations
      tags: [Conversations]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/start_date_optional'
        - $ref: '#/components/parameters/end_date_optional'
      responses:
        '200':
          description: Paginated conversations for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConversationPage'

  /api/v2/organizations/{organization_id}/conversations/{conversation_id}:
    get:
      summary: Get a conversation
      operationId: getConversation
      tags: [Conversations]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/conversation_id'
      responses:
        '200':
          description: A single conversation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConversationSummary'

  # ── Messages ───────────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/conversations/{conversation_id}/messages:
    get:
      summary: List messages
      operationId: listMessages
      tags: [Messages]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/conversation_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/start_date_optional'
        - $ref: '#/components/parameters/end_date_optional'
      responses:
        '200':
          description: Paginated messages for the conversation.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MessagePage'

  /api/v2/organizations/{organization_id}/conversations/{conversation_id}/messages/{message_id}:
    get:
      summary: Get a message
      operationId: getMessage
      tags: [Messages]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/conversation_id'
        - $ref: '#/components/parameters/message_id'
      responses:
        '200':
          description: A single message.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Message'

  /api/v2/organizations/{organization_id}/messages-drafts:
    post:
      summary: Create a message draft
      operationId: createMessageDraft
      tags: [Messages]
      parameters:
        - $ref: '#/components/parameters/organization_id'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDraftRequest'
      responses:
        '201':
          description: Created message draft.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DraftCreateResponse'
        '400':
          description: Invalid draft request.
        '404':
          description: Organization not found.

  # ── Analytics ──────────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/analytics/conversations:
    get:
      summary: Get combined conversation analytics
      operationId: getConversationAnalytics
      tags: [Analytics]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Combined conversation analytics for the organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  responseRateStats:
                    type: object
                    properties:
                      numConversationsRespondedTo:
                        type: integer
                        description: Conversations whose first inbound message landed in the selected window and whose first assistant response after that message exists.
                        example: 14
                      numConversationsReceived:
                        type: integer
                        description: Conversations whose first inbound message landed in the selected window.
                        example: 20
                      responseRate:
                        type: number
                        format: float
                        example: 0.7
                  responseTimeStats:
                    type: object
                    properties:
                      responseTime:
                        type: integer
                        description: Median response time in seconds.
                        example: 3600
                  volumeStats:
                    type: object
                    properties:
                      numMessagesReceived:
                        type: integer
                        example: 120
                      numMessagesSent:
                        type: integer
                        example: 118
                      totalConversations:
                        type: integer
                        example: 42
                  modalityStats:
                    type: object
                    properties:
                      textMessages:
                        type: integer
                        example: 10
                      calls:
                        type: integer
                        example: 4
                      emails:
                        type: integer
                        example: 20
                      liveChats:
                        type: integer
                        example: 6
                      formRequests:
                        type: integer
                        example: 2

  /api/v2/organizations/{organization_id}/analytics/conversations/response-rate:
    get:
      summary: Get response rate analytics
      operationId: getResponseRateAnalytics
      tags: [Analytics]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Response rate stats for the organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  numConversationsRespondedTo:
                    type: integer
                    description: Conversations whose first inbound message landed in the selected window and whose first assistant response after that message exists.
                    example: 14
                  numConversationsReceived:
                    type: integer
                    description: Conversations whose first inbound message landed in the selected window.
                    example: 20
                  responseRate:
                    type: number
                    format: float
                    example: 0.7

  /api/v2/organizations/{organization_id}/analytics/conversations/response-time:
    get:
      summary: Get response time analytics
      operationId: getResponseTimeAnalytics
      tags: [Analytics]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Response time stats for the organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  responseTime:
                    type: integer
                    description: Median response time in seconds.
                    example: 3600

  /api/v2/organizations/{organization_id}/analytics/conversations/volume:
    get:
      summary: Get conversation volume analytics
      operationId: getVolumeAnalytics
      tags: [Analytics]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Conversation volume stats for the organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  numMessagesReceived:
                    type: integer
                    example: 120
                  numMessagesSent:
                    type: integer
                    example: 118
                  totalConversations:
                    type: integer
                    example: 42

  /api/v2/organizations/{organization_id}/analytics/conversations/modality:
    get:
      summary: Get modality analytics
      operationId: getModalityAnalytics
      tags: [Analytics]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Distribution of first inbound conversation message modalities.
          content:
            application/json:
              schema:
                type: object
                properties:
                  textMessages:
                    type: integer
                    example: 10
                  calls:
                    type: integer
                    example: 4
                  emails:
                    type: integer
                    example: 20
                  liveChats:
                    type: integer
                    example: 6
                  formRequests:
                    type: integer
                    example: 2

  /api/v2/organizations/{organization_id}/analytics/sales:
    get:
      summary: Get sales analytics
      operationId: getSalesAnalytics
      tags: [Analytics]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Sales pipeline analytics for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SalesAnalytics'

  # ── Sales ──────────────────────────────────────────────────────────────────

  /api/v2/organizations/{organization_id}/sales:
    get:
      summary: List sales
      operationId: listSales
      tags: [Sales]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/limit'
        - $ref: '#/components/parameters/cursor'
        - $ref: '#/components/parameters/start_date_optional'
        - $ref: '#/components/parameters/end_date_optional'
      responses:
        '200':
          description: Paginated non-draft sales for the organization.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SalePage'

  /api/v2/organizations/{organization_id}/sales/{sale_id}:
    get:
      summary: Get a sale
      operationId: getSale
      tags: [Sales]
      parameters:
        - $ref: '#/components/parameters/organization_id'
        - $ref: '#/components/parameters/sale_id'
      responses:
        '200':
          description: A single sale.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Sale'

  # ── Legacy v1 ──────────────────────────────────────────────────────────────

  /api/v1/solutions:
    get:
      summary: List solutions (legacy)
      operationId: listSolutions
      tags: [Legacy v1]
      responses:
        '200':
          description: Array of legacy solutions available to the API key.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/LegacySolution'

  /api/v1/solutions/{solution_id}/analytics:
    get:
      summary: Get solution analytics (legacy)
      operationId: getSolutionAnalytics
      tags: [Legacy v1]
      parameters:
        - name: solution_id
          in: path
          required: true
          schema:
            type: string
          example: 550e8400-e29b-41d4-a716-446655440000
        - $ref: '#/components/parameters/start_date_required'
        - $ref: '#/components/parameters/end_date_required'
      responses:
        '200':
          description: Analytics for a legacy solution.
          content:
            application/json:
              schema:
                type: object
                properties:
                  responseRateStats:
                    type: object
                    properties:
                      numChatsSent:
                        type: integer
                      numPendingChats:
                        type: integer
                      responseRate:
                        type: number
                  responseTimeStats:
                    type: object
                    properties:
                      responseTime:
                        type: number
                      responseTimeBusinessHours:
                        type: number
                      numResponses:
                        type: integer
                      numResponsesBusinessHours:
                        type: integer
                  salesStats:
                    type: object
                    properties:
                      averageSpeedToSale:
                        type: number
                      numSalesCounted:
                        type: integer
                  valueStats:
                    type: object
                    properties:
                      salesValue:
                        type: number
                      quoteValue:
                        type: number
                  salesFunnelStats:
                    type: object
                    properties:
                      source:
                        type: object
                        properties:
                          sessionsDirectEmail:
                            type: integer
                          sessionsIndirectEmail:
                            type: integer
                          sessionsFormRequest:
                            type: integer
                      response:
                        type: object
                        properties:
                          sessionsLeadResponded:
                            type: integer
                          sessionsGhosted:
                            type: integer
                          sessionsResponseSent:
                            type: integer
                          sessionsPendingOutreach:
                            type: integer
                      outcome:
                        type: object
                        properties:
                          sessionsQuoted:
                            type: integer
                      sale:
                        type: object
                        properties:
                          sessionsSale:
                            type: integer
                  autonomyRateStats:
                    type: object
                    properties:
                      chatsSentWithChanges:
                        type: integer
                      chatsSentWithoutChanges:
                        type: integer
                      autonomyRate:
                        type: number
                  numLeads:
                    type: integer
                  leadsHandled:
                    type: integer
                  salesRate:
                    type: number
                  quoteRate:
                    type: number
                  ghostRate:
                    type: number
                  leadResponseScore:
                    type: number
