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

# The conversation for a call

> Keyed on the call rather than the conversation, for the call-detail screen. Scoped through the CDR.



## OpenAPI

````yaml /api-reference/openapi-public.json get /cdrs/{uuid}/conversation
openapi: 3.0.3
info:
  description: >-
    The API your own systems use: place and follow calls, have an AI agent call
    someone, run campaigns and get their results, keep contacts in step with
    your CRM, and receive signed webhooks. Authenticate with an integration key
    (Authorization: Bearer ft_...), used only from the IP addresses it allows.
  title: FireTone API
  version: 0.1.0
servers:
  - description: Your platform's API host
    url: https://{host}/api/v1
    variables:
      host:
        default: api.firet.one
security:
  - bearerAuth: []
tags:
  - name: Auth
  - description: >-
      Live calls and what can be done to them: hang up, hold, transfer, park,
      merge, monitor, whisper; the Desk's own call.
    name: Calls
  - description: 'Outbound campaigns: contacts, attempts, outcomes.'
    name: Campaigns
  - description: 'Customers: who called, what is known about them, and their memory.'
    name: Contacts
  - description: What was said on an AI call, and the review of it.
    name: Conversations
  - description: >-
      Your own systems: HTTP connections an IVR calls mid-call, and webhooks for
      call events. Tenant URLs must be public https addresses.
    name: Integrations
  - name: Live
  - name: Provisioning
  - name: Reporting
  - description: Tickets raised by people, agents and the API.
    name: Tickets
  - description: Messages left for an extension or a queue.
    name: Voicemail
paths:
  /cdrs/{uuid}/conversation:
    get:
      tags:
        - Conversations
      summary: The conversation for a call
      description: >-
        Keyed on the call rather than the conversation, for the call-detail
        screen. Scoped through the CDR.
      operationId: getCdrsUuidConversation
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ConversationDetail'
          description: OK
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  schemas:
    ConversationDetail:
      allOf:
        - $ref: '#/components/schemas/Conversation'
        - properties:
            assembled_context:
              description: Exactly what the agent was told before it spoke.
              type: string
            turns:
              items:
                $ref: '#/components/schemas/ConversationTurn'
              type: array
          type: object
    Conversation:
      properties:
        agent_id:
          format: uuid
          type: string
        agent_kind:
          enum:
            - human
            - virtual
          type: string
        ai_billing_mode:
          description: >-
            byo means the tenant's own credential paid, so they were billed by
            the provider directly and no amount appears here.
          enum:
            - byo
            - rated
          type: string
        ai_cost_amount:
          description: >-
            What the operator paid the provider. Absent without margin:read, and
            absent whenever the tenant's own key paid.
          type: string
        ai_sell_amount:
          description: >-
            What the AI on this call cost, as an exact decimal string. ABSENT,
            never zero, in three situations that must not be confused: the
            caller lacks billing:read, no price row matched the model, or the
            tenant's own credential paid the provider so there is nothing for us
            to charge.
          type: string
        audio_split_known:
          description: >-
            False when the provider itemised no audio tokens at all. It changes
            how every figure here should be read: tokens_audio is then "not
            reported" rather than "none", and the audio was priced at the TEXT
            rate because there is no other number to price it at. Reported so an
            approximate amount is not read as an exact one. Gemini reports no
            split.
          type: boolean
        call_uuid:
          format: uuid
          type: string
        contact_e164:
          type: string
        contact_id:
          format: uuid
          type: string
        direction:
          enum:
            - inbound
            - outbound
          type: string
        ended_at:
          format: date-time
          nullable: true
          type: string
        flags:
          description: >-
            The post-call review of an AI agent's conversation. competitor: an
            agent turn named one of the profile's competitor_names (seq is the
            turn). never_searched: the knowledge base was too large to give the
            agent whole and it answered without searching it. Empty when the
            review found nothing, or did not run (a human agent).
          items:
            properties:
              detail:
                type: string
              kind:
                enum:
                  - competitor
                  - never_searched
                type: string
              seq:
                type: integer
            type: object
          type: array
        id:
          format: uuid
          type: string
        model:
          type: string
        organisation_id:
          format: uuid
          type: string
        provider:
          description: Null for a human-handled call.
          type: string
        started_at:
          format: date-time
          type: string
        summary:
          type: string
        tokens_audio:
          description: >-
            The audio PORTION of tokens_input, not a third total. Adding it to
            input charges the audio twice. Counts as the provider reported them,
            not money: prices change, and an amount computed from a hardcoded
            price is silently wrong later.
          type: integer
        tokens_input:
          type: integer
        tokens_output:
          type: integer
        turn_count:
          type: integer
        virtual_agent_profile_id:
          description: >-
            The profile that handled this call, as it was at the time. Not a
            live reference to the agent's current profile.
          format: uuid
          type: string
        virtual_agent_profile_name:
          description: >-
            The profile's name as recorded when the call ran, so a later rename
            does not restate history.
          type: string
      type: object
    ConversationTurn:
      properties:
        at:
          format: date-time
          type: string
        role:
          enum:
            - caller
            - agent
            - system
            - tool
          type: string
        seq:
          description: >-
            Explicit ordering. Timestamps collide at realtime speeds, and a
            transcript in the wrong order reads as the agent answering before
            the question.
          type: integer
        text:
          type: string
        tool_args:
          type: object
        tool_name:
          type: string
        tool_result:
          type: object
      type: object
    Error:
      properties:
        error:
          properties:
            code:
              enum:
                - invalid_request
                - invalid_credentials
                - unauthenticated
                - forbidden
                - not_found
                - conflict
                - internal
              type: string
            message:
              type: string
          required:
            - code
            - message
          type: object
      required:
        - error
      type: object
  responses:
    Forbidden:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Outside the caller's scope, or insufficient role
    NotFound:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Not found, or not visible to the caller
  securitySchemes:
    bearerAuth:
      bearerFormat: JWT or API key
      description: >-
        Every request sends `Authorization: Bearer <token>`. The token is either
        a panel session (a JWT from /auth/login, 12 hours) or an API key
        `ft_<id>_<secret>`. An API key is accepted only from an address on its
        IP allowlist (403 ip_not_allowed otherwise; 403 ip_allowlist_required
        for an old key that has none), is limited to its rate per minute (429
        rate_limited with Retry-After; X-RateLimit-Limit/Remaining/Reset on
        every response), and at most 60 call placements a minute.
      scheme: bearer
      type: http

````