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

# Aggregate stats for a campaign

> Counters for every run of the campaign, written by the post-call pipeline — all zero until the first call finishes.

**Note:** Scores, conversions, and sentiment are computed by LLMs — best effort, with room to be wrong. We are continuously closing the tracking gaps, but for sensitive workloads we recommend running your own analysis on the transcripts delivered over [webhooks](/voice-agents/webhooks/overview).



## OpenAPI

````yaml /voice-agents/api-reference/openapi.yaml get /campaigns/{campaignId}/stats
openapi: 3.1.0
info:
  title: UpliftAI Voice Agents API
  version: '1.0'
  description: >-
    Build voice assistants, start conversations on the web or the phone, run
    calling campaigns, and receive outcomes by webhook. All endpoints take a
    bearer API key unless noted otherwise.
servers:
  - url: https://api.upliftai.org/v1
security:
  - apiKey: []
tags:
  - name: Assistants
  - name: Authoring an assistant
  - name: Starting a conversation
  - name: Sessions & call records
  - name: Campaigns
  - name: Campaign outcomes
  - name: Contacts
  - name: Google Sheet sources
  - name: Integrations & delivery health
paths:
  /campaigns/{campaignId}/stats:
    get:
      tags:
        - Campaign outcomes
      summary: Aggregate stats for a campaign
      description: >-
        Counters for every run of the campaign, written by the post-call
        pipeline — all zero until the first call finishes.


        **Note:** Scores, conversions, and sentiment are computed by LLMs — best
        effort, with room to be wrong. We are continuously closing the tracking
        gaps, but for sensitive workloads we recommend running your own analysis
        on the transcripts delivered over
        [webhooks](/voice-agents/webhooks/overview).
      operationId: getCampaignStats
      parameters:
        - name: campaignId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          example: cb5401ef-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      responses:
        '200':
          description: >-
            The campaign's counters — zero across the board before the first
            call completes.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignStats'
              example:
                dialed: 412
                connected: 168
                booked: 74
                notInterested: 51
                wrongPerson: 9
                voicemail: 96
                noAnswer: 121
                silentPickup: 19
                failed: 6
                analysisFailed: 2
                callbacks: 12
                scored: 168
                avgScore: 76
                great: 83
                ok: 61
                low: 24
                totalDurationSec: 9284
                avgDurationSec: 55
                totalContacts: 850
                attemptedContacts: 318
                resolvedContacts: 262
                retrying: 44
                exhausted: 33
                projectedRevenue: 333000
                sentiment:
                  happy: 91
                  neutral: 52
                  annoyed: 14
                  unknown: 11
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: No campaign under that id in the API key's project.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                message: 'Campaign not found: 00000000-0000-4000-8000-000000000000'
                error: Not Found
                statusCode: 404
components:
  schemas:
    CampaignStats:
      type: object
      description: >-
        Counters for one campaign. A dial lands in at most one of `connected`,
        `voicemail`, `noAnswer`, `silentPickup`, `failed` and `analysisFailed`,
        so those sum to `dialed` or just under. Grading, sentiment and revenue
        figures cover the `connected` subset.
      properties:
        dialed:
          type: integer
          description: Call attempts placed. A contact retried twice counts twice.
        connected:
          type: integer
          description: Attempts that reached a person and were graded.
        booked:
          type: integer
          description: >-
            Conversions recorded — appointments booked, leads qualified,
            payments promised, depending on the campaign's goal.
        notInterested:
          type: integer
        wrongPerson:
          type: integer
        voicemail:
          type: integer
        noAnswer:
          type: integer
        silentPickup:
          type: integer
          description: >-
            Answered, but the callee never spoke — a dead line, an unannounced
            machine, or a carrier answering on the callee's behalf. Not graded.
        failed:
          type: integer
          description: >-
            Attempts that never reached the callee (carrier rejection, no route,
            no credit). Busy and unreachable dials count in `dialed` but land in
            no bucket here.
        analysisFailed:
          type: integer
          description: >-
            Calls that reached a person but could not be scored. They count in
            no other counter here, not even `connected`.
        callbacks:
          type: integer
          description: >-
            Calls where the contact asked to be rung back. The campaign
            callbacks endpoint lists them.
        scored:
          type: integer
          description: >-
            Graded calls with a score, equal to `great` + `ok` + `low`. A call
            whose every rule was N/A has `score: null` and is left out.
        avgScore:
          type:
            - integer
            - 'null'
          description: Mean score over `scored`, rounded. `null` until a call has a score.
        great:
          type: integer
          description: Scored 80 or above.
        ok:
          type: integer
          description: Scored 60 to 79.
        low:
          type: integer
          description: Scored under 60.
        totalDurationSec:
          type: integer
        avgDurationSec:
          type: integer
          description: Rounded mean over the calls that reported a duration.
        totalContacts:
          type: integer
          description: Contacts enrolled, counted across every run.
        attemptedContacts:
          type: integer
          description: Contacts dialed at least once.
        resolvedContacts:
          type: integer
          description: >-
            Contacts the campaign is finished with — reached, out of retries, or
            skipped.
        retrying:
          type: integer
          description: Contacts waiting out a retry backoff before the next attempt.
        exhausted:
          type: integer
          description: >-
            Contacts that used every retry without reaching anyone. Counted in
            `resolvedContacts` too.
        projectedRevenue:
          type: integer
          description: >-
            `booked` priced with the campaign's `config.economics`, in the same
            unit those values used. 0 when economics were never configured.
        sentiment:
          type: object
          description: How post-call analysis read the contact's mood.
          properties:
            happy:
              type: integer
            neutral:
              type: integer
            annoyed:
              type: integer
            unknown:
              type: integer
              description: Connected calls the grader left unlabelled.
    Error:
      type: object
      properties:
        message:
          description: >-
            One message per failed field for validation errors, a single string
            otherwise.
          oneOf:
            - type: string
            - type: array
              items:
                type: string
        error:
          type: string
        statusCode:
          type: integer
  responses:
    Unauthorized:
      description: A bearer key was sent but is not recognized.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: invalid authorization
            error: Unauthorized
            statusCode: 401
    Forbidden:
      description: No API key sent, or the key lacks permission for this resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            message: Forbidden resource
            error: Forbidden
            statusCode: 403
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      description: Project API key (`sk_api_…`).

````