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

# What a campaign is doing right now

> Meant to be polled while a campaign runs. In flight is counted from leased contacts rather than from live channels: the dialer sets a campaign id as a channel variable, but the switch's channel listing does not surface custom variables, so it cannot be filtered by campaign.



## OpenAPI

````yaml /api-reference/openapi-public.json get /campaigns/{id}/stats
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:
  /campaigns/{id}/stats:
    get:
      tags:
        - Campaigns
      summary: What a campaign is doing right now
      description: >-
        Meant to be polled while a campaign runs. In flight is counted from
        leased contacts rather than from live channels: the dialer sets a
        campaign id as a channel variable, but the switch's channel listing does
        not surface custom variables, so it cannot be filtered by campaign.
      operationId: getCampaignsIdStats
      parameters:
        - in: path
          name: id
          required: true
          schema:
            format: uuid
            type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignStats'
          description: OK
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  schemas:
    CampaignStats:
      description: >-
        What a campaign is doing right now. The dialer's own counters come from
        the campaign row, because the pacer reads them every tick and an
        aggregate over call history would get slower exactly as a campaign got
        busier. Everything about the list is counted from the contact states.
      properties:
        abandon_rate:
          description: >-
            Abandoned as a percentage of ANSWERED calls, not of everything
            dialled -- the denominator a regulator measures, and the one the
            pacer's governor uses.
          type: number
        abandoned:
          description: >-
            Answered by a person who reached no agent. The figure
            max_abandon_pct governs.
          type: integer
        answer_rate:
          description: Answered as a percentage of dialled.
          type: number
        answered:
          type: integer
        campaign_id:
          format: uuid
          type: string
        dialed:
          type: integer
        done:
          type: integer
        failed:
          type: integer
        in_flight:
          description: >-
            Contacts currently leased to the dialer: a call has been placed and
            has not finished. Counted from the lease rather than from live
            channels, because `show channels` carries no campaign id.
          type: integer
        max_abandon_pct:
          description: The campaign's compliance ceiling, for comparison with abandon_rate.
          type: string
        name:
          type: string
        pending:
          type: integer
        scheduled:
          description: >-
            Running, but its start time has not arrived. Not a status of its own
            -- it is the difference between dialling nothing because it is
            waiting and dialling nothing because something is wrong.
          type: boolean
        start_at:
          format: date-time
          type: string
        status:
          type: string
        suppressed:
          description: 'On the list and never dialled: do-not-call or blacklisted.'
          type: integer
        total:
          type: integer
      required:
        - campaign_id
        - name
        - status
        - scheduled
        - dialed
        - answered
        - abandoned
        - in_flight
        - pending
        - done
        - failed
        - suppressed
        - total
        - answer_rate
        - abandon_rate
        - max_abandon_pct
      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:
    Unauthorized:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
      description: Missing, invalid or expired token
    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

````