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

# Retrieve campaign stats

> Funnel counts, reply and conversion rates, and why participants were not contacted, for one time window. The window defaults to the 30 days ending now.

All counts come from one consistent definition, so `replied` never exceeds `contacted`. Sailer's campaign dashboard also shows a stricter response rate, which counts only a contact's first reply after the campaign message; expect that figure to be somewhat lower than `reply_rate` here.



## OpenAPI

````yaml /api-reference/openapi.json get /v1/campaigns/{campaign_id}/stats
openapi: 3.1.0
info:
  description: >-
    The Sailer REST API for CRM, conversations, and campaigns.


    **Authentication.** Send a token as `Authorization: Bearer <token>`. A
    workspace

    token (`sk_live_...`) is created by a workspace administrator and its secret
    is

    shown once. An OAuth access token (`oat_live_...`) acts on behalf of the
    person

    who authorized it and sees only what they can see. Either way the workspace
    is

    implied by the token, so no tenant header is needed. Each token carries
    scopes;

    `GET /v1/me` lists them.


    **Pagination.** Collections return `{data, meta, links}`. Pass `links.next`
    back

    as `cursor` until it is `null`. Cursors are opaque and only valid for the
    query

    that produced them.


    **Errors.** Every non-2xx response is `{"error": {...}}` with a coarse
    `type`, a

    stable `code` and the offending `param`. Quote `error.request_id` (also the

    `X-Request-ID` header) when contacting support.


    **Retries.** Send an `Idempotency-Key` header on any write to make retrying
    it

    safe for 24 hours.


    **Rate limits.** Limits are per token. Every response carries

    `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; a
    `429`

    also carries `Retry-After`.


    **Custom fields.** Workspace-defined fields appear under `custom_fields`,
    keyed

    by field key. `GET /v1/fields` lists every field on a resource, built-in and

    custom.
  title: Sailer API
  version: 1.0.0
servers:
  - url: https://api.chatsailer.com
security:
  - SailerApiToken: []
tags:
  - description: Token introspection and workspace capabilities.
    name: Meta
  - description: >-
      People you talk to. Called *leads* in older Sailer surfaces; `contact` is
      the current name.
    name: Contacts
  - description: Companies that contacts belong to (B2B accounts).
    name: Organizations
  - description: Opportunities moving through a pipeline.
    name: Deals
  - description: Pipelines and their stages.
    name: Pipelines
  - description: Field definitions, including custom fields.
    name: Fields
  - description: Free-text annotations on CRM records.
    name: Notes
  - description: Scheduled and logged CRM activities.
    name: Activities
  - description: Per-entity label catalogs.
    name: Tags
  - description: Members of the workspace, for assigning records.
    name: Users
  - description: Message threads with contacts, across every channel.
    name: Conversations
  - description: Outbound campaigns and their participants.
    name: Campaigns
  - description: Named contact lists campaigns draw from.
    name: Audiences
  - description: The connections you talk to contacts through.
    name: Channels
  - description: Pre-approved WhatsApp message templates.
    name: Templates
  - description: >-
      Keeping another system in step with a workspace: the deletion feed.
      Changes are read from each resource's list with `updated_since`.
    name: Sync
  - description: >-
      Business outcomes your systems report — a sale closed, a meeting held —
      that your agreement may charge a success fee on. Append-only: a refund is
      a reversal, never an edit. Needs the `success_events:read` /
      `success_events:write` scopes.
    name: Success Events
paths:
  /v1/campaigns/{campaign_id}/stats:
    get:
      tags:
        - Campaigns
      summary: Retrieve campaign stats
      description: >-
        Funnel counts, reply and conversion rates, and why participants were not
        contacted, for one time window. The window defaults to the 30 days
        ending now.


        All counts come from one consistent definition, so `replied` never
        exceeds `contacted`. Sailer's campaign dashboard also shows a stricter
        response rate, which counts only a contact's first reply after the
        campaign message; expect that figure to be somewhat lower than
        `reply_rate` here.
      operationId: get_campaign_stats
      parameters:
        - in: path
          name: campaign_id
          required: true
          schema:
            description: Unique identifier for a campaign.
            examples:
              - camp_9f2ac41d8b7e4a51b0d3e6f7a1c2d3e4
            pattern: ^camp_[0-9a-f]{32}$
            title: Campaign Id
            type: string
        - description: Start of the window, inclusive. Needs a timezone offset.
          in: query
          name: since
          required: false
          schema:
            anyOf:
              - format: date-time
                type: string
              - type: 'null'
            description: Start of the window, inclusive. Needs a timezone offset.
            title: Since
        - description: End of the window, exclusive. Defaults to now.
          in: query
          name: until
          required: false
          schema:
            anyOf:
              - format: date-time
                type: string
              - type: 'null'
            description: End of the window, exclusive. Defaults to now.
            title: Until
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignStats'
          description: Successful Response
          headers:
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - SailerApiToken: []
components:
  schemas:
    CampaignStats:
      description: >-
        How a campaign performed over a time window.


        Counts cover participants the campaign messaged in

        `[window_start, window_end)` — except `enrolled`, which covers the whole

        campaign, and `not_contacted`, which counts participants whose status
        last

        changed in the window. Rates are fractions: 0.25 means 25%.
      properties:
        campaign_id:
          description: Unique identifier for a campaign.
          examples:
            - camp_9f2ac41d8b7e4a51b0d3e6f7a1c2d3e4
          pattern: ^camp_[0-9a-f]{32}$
          title: Campaign Id
          type: string
        contacted:
          description: Participants the campaign messaged successfully.
          minimum: 0
          title: Contacted
          type: integer
        conversion_rate:
          anyOf:
            - minimum: 0
              type: number
            - type: 'null'
          description: '`converted / contacted`. Null when nobody was contacted.'
          title: Conversion Rate
        converted:
          description: >-
            Distinct contacts the campaign messaged who were marked as won
            afterwards.
          minimum: 0
          title: Converted
          type: integer
        enrolled:
          description: Participants ever added to the campaign, in any status.
          minimum: 0
          title: Enrolled
          type: integer
        not_contacted:
          description: Every reason, in a fixed order, including those with zero.
          items:
            $ref: '#/components/schemas/NotContactedCount'
          title: Not Contacted
          type: array
        object:
          const: campaign_stats
          default: campaign_stats
          title: Object
          type: string
        replied:
          description: >-
            Contacted participants who replied. Replies that look automated
            (away messages, bots) are not counted here.
          minimum: 0
          title: Replied
          type: integer
        replied_automated:
          description: Contacted participants whose reply looks automated.
          minimum: 0
          title: Replied Automated
          type: integer
        reply_rate:
          anyOf:
            - minimum: 0
              type: number
            - type: 'null'
          description: '`replied / contacted`. Null when nobody was contacted.'
          title: Reply Rate
        window_end:
          format: date-time
          title: Window End
          type: string
        window_start:
          format: date-time
          title: Window Start
          type: string
      required:
        - campaign_id
        - window_start
        - window_end
        - enrolled
        - contacted
        - replied
        - replied_automated
        - converted
        - not_contacted
      title: CampaignStats
      type: object
    NotContactedCount:
      properties:
        count:
          minimum: 0
          title: Count
          type: integer
        reason:
          $ref: '#/components/schemas/NotContactedReason'
      required:
        - reason
        - count
      title: NotContactedCount
      type: object
    ApiErrorResponse:
      description: Every non-2xx response on the public API has this body.
      properties:
        error:
          $ref: '#/components/schemas/ApiError'
      required:
        - error
      title: ApiErrorResponse
      type: object
    NotContactedReason:
      description: >-
        Why a participant was not contacted.


        `meta_account`: a problem with the WhatsApp Business account (billing,

        limits, policy). `template_content`: the template was refused or could
        not

        be filled. `channel`: the sending channel was unavailable.
        `contact_data`:

        the contact's number or data is unusable. `unreachable`: the number is
        not

        on WhatsApp or did not accept the message. `in_conversation`: skipped

        because the contact was already in a conversation. `waiting_window`:
        held

        until the campaign's sending hours. `campaign_rule`: excluded by a
        campaign

        setting. `transient_or_ours`: a temporary or Sailer-side failure.
      enum:
        - meta_account
        - template_content
        - channel
        - contact_data
        - unreachable
        - in_conversation
        - waiting_window
        - campaign_rule
        - transient_or_ours
      title: NotContactedReason
      type: string
    ApiError:
      properties:
        code:
          description: Stable, machine-readable identifier.
          title: Code
          type: string
        detail:
          anyOf:
            - items:
                $ref: '#/components/schemas/ErrorDetail'
              type: array
            - type: 'null'
          default: null
          description: Per-field errors for validation failures.
          title: Detail
        documentation_url:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Documentation Url
        message:
          description: Human-readable explanation.
          title: Message
          type: string
        param:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Request field the error refers to, if any.
          title: Param
        request_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Echoes the X-Request-ID response header. Quote it in support
            requests.
          title: Request Id
        type:
          $ref: '#/components/schemas/ErrorType'
      required:
        - type
        - code
        - message
      title: ApiError
      type: object
    ErrorDetail:
      properties:
        code:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          title: Code
        field:
          description: Dotted path to the offending field.
          title: Field
          type: string
        message:
          title: Message
          type: string
      required:
        - field
        - message
      title: ErrorDetail
      type: object
    ErrorType:
      description: Coarse class of failure. Stable; new codes may appear under a type.
      enum:
        - invalid_request_error
        - authentication_error
        - permission_error
        - not_found_error
        - conflict_error
        - rate_limit_error
        - api_error
      title: ErrorType
      type: string
  headers:
    X-RateLimit-Limit:
      description: Requests allowed in the current window on this token.
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in the current window.
      schema:
        type: integer
    X-RateLimit-Reset:
      description: Seconds until the window resets and the allowance refills.
      schema:
        type: integer
    X-Request-ID:
      description: Unique id for this request. Quote it to support.
      schema:
        type: string
    Retry-After:
      description: Seconds to wait before retrying.
      schema:
        type: integer
  responses:
    BadRequest:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
      description: A query parameter, path segment or header is invalid.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
    Unauthorized:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
      description: The token is missing, unknown, revoked or expired.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
    Forbidden:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
      description: >-
        The token lacks a required scope, or the workspace's CRM write policy
        does not allow this change.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
    NotFound:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
      description: No such record in this workspace.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
    RateLimited:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
      description: Too many requests on this token. Retry after the delay.
      headers:
        Retry-After:
          $ref: '#/components/headers/Retry-After'
        X-RateLimit-Limit:
          $ref: '#/components/headers/X-RateLimit-Limit'
        X-RateLimit-Remaining:
          $ref: '#/components/headers/X-RateLimit-Remaining'
        X-RateLimit-Reset:
          $ref: '#/components/headers/X-RateLimit-Reset'
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
    InternalError:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
      description: Something went wrong on our side. Quote `error.request_id` to support.
      headers:
        X-Request-ID:
          $ref: '#/components/headers/X-Request-ID'
  securitySchemes:
    SailerApiToken:
      description: >-
        A workspace API token (`sk_live_...`) or an OAuth access token
        (`oat_live_...`). Create workspace tokens in Settings > API. Send either
        as `Authorization: Bearer <token>`.
      scheme: bearer
      type: http

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.