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

# Get apiv1campaigns analytics



## OpenAPI

````yaml https://backend.aflux.ai/openapi get /api/v1/campaigns/{campaignId}/analytics
openapi: 3.0.3
info:
  title: AdFlux Backend API
  version: v1
servers:
  - url: /
security: []
tags:
  - name: auth
  - name: users
  - name: uploads
  - name: projects
  - name: campaigns
  - name: placements
  - name: billing
  - name: payments
  - name: image-generations
paths:
  /api/v1/campaigns/{campaignId}/analytics:
    get:
      tags:
        - campaigns
      operationId: campaignsGetAnalytics
      parameters:
        - in: path
          name: campaignId
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CampaignAnalytics'
        default:
          $ref: '#/components/responses/DefaultError'
      security:
        - Bearer: []
components:
  schemas:
    CampaignAnalytics:
      type: object
      required:
        - budget
        - spent
        - reserved
        - remaining
        - currency
        - perChannel
        - performance
      description: >-
        Campaign money and campaign-level totals. Per-channel audience facts
        live on CampaignPlacement, not here. spent + reserved + remaining always
        equals budget, where spent is what actually left the account (PAID and
        every status after it), reserved is committed on approval but not yet
        paid out, and remaining is the uncommitted budget a further approval can
        still spend.
      properties:
        budget:
          $ref: '#/components/schemas/MoneyAmount'
        spent:
          $ref: '#/components/schemas/MoneyAmount'
        reserved:
          $ref: '#/components/schemas/MoneyAmount'
        remaining:
          $ref: '#/components/schemas/MoneyAmount'
        currency:
          type: string
        perChannel:
          type: array
          items:
            $ref: '#/components/schemas/CampaignChannelAnalytics'
        performance:
          $ref: '#/components/schemas/CampaignPerformance'
    MoneyAmount:
      type: string
      pattern: ^-?\d+(\.\d{1,6})?$
      example: '125.500000'
    CampaignChannelAnalytics:
      type: object
      required:
        - placementId
        - status
        - amount
      description: >-
        One placement's money. amount is the price agreed with the manager;
        status says whether it was paid, is merely held, or came to nothing.
        Placements with no agreed price are absent.
      properties:
        placementId:
          type: string
          format: uuid
        channelUsername:
          type: string
          nullable: true
        channelTitle:
          type: string
          nullable: true
        status:
          $ref: '#/components/schemas/CampaignPlacementStatus'
        amount:
          $ref: '#/components/schemas/MoneyAmount'
    CampaignPerformance:
      type: object
      required:
        - dataAvailable
        - measuredPlacements
      description: >-
        What the campaign delivered, against what it was forecast to deliver.
        views and reactions are measured by the parser on the posts that were
        actually published: they converge to the figure reached roughly 48h
        after each post went up and then stop growing, because tracking
        retention ends there and the placement completes — this is a settled
        result, not a live counter. clicks are measured on our own redirect:
        every link in a published post points at go.aflux.ai first, so following
        it is counted before the reader is sent on to the advertiser. Those two
        clocks do NOT run together, and ctr is the field that suffers for it —
        views stop at ~48h while clicks keep accruing for as long as the post
        stays up, so a campaign's ctr drifts DOWNWARD over the weeks after it
        finishes and is only comparable between campaigns of similar age.
        targetViews is the only forecast here (summed from the channels'
        statistics before the campaign ran); everything else is measured.
      properties:
        dataAvailable:
          type: boolean
          description: >-
            Whether anything has been measured yet; false means
            views/reactions/cpm are all absent
        views:
          type: integer
          format: int64
          nullable: true
          description: >-
            Views measured on the published posts, summed over the measured
            placements. Null (never 0) while nothing has been measured
        reactions:
          type: integer
          format: int64
          nullable: true
          description: >-
            Reactions measured on the same posts, summed the same way; null
            while nothing has been measured
        measuredPlacements:
          type: integer
          format: int32
          description: >-
            How many of the campaign's placements the measured figures cover, so
            a partial total is not read as the whole campaign («по 3 размещениям
            из 5»). 0 when nothing has been measured
        capturedAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            When the newest snapshot behind these figures was taken, i.e. how
            fresh views is
        cpm:
          $ref: '#/components/schemas/MoneyAmount'
          nullable: true
          description: >-
            Actual cost per 1000 views of the measured placements ONLY — their
            own payouts divided by their own views, not the campaign's whole
            spent over a measured subset of its audience. Always read it
            together with measuredPlacements: while some placements are still
            unmeasured this is a partial price, not the campaign's final cost
            per view. Null while nothing has been measured
        clicks:
          type: integer
          format: int64
          nullable: true
          description: >-
            Times a link in one of this campaign's published posts was followed,
            summed over every placement. Counted on our own redirect, so it
            includes repeat clicks by the same person — uniqueClicks is what
            separates the two. Null (never 0) while nothing has been clicked
        uniqueClicks:
          type: integer
          format: int64
          nullable: true
          description: >-
            The same clicks counted one per IP, over the whole campaign — a
            reader who clicked in two of its channels is one person here, which
            is why this is not the sum of the placements' own unique counts.
            clicks minus uniqueClicks is the readers who came back. Null (never
            0) while nothing has been clicked
        ctr:
          type: string
          nullable: true
          description: >-
            Click-through rate as a FRACTION, not a percent: clicks divided by
            measured views, so 0.0238 means 2.38%. Uses total clicks (repeat
            clicks included), matching how the figure is quoted in the market.
            Drifts downward over time — views stop growing ~48h after each post
            while clicks keep arriving — so compare it between campaigns of
            similar age, not across a fresh one and a finished one. Null while
            there are no clicks or no measured views
        costPerClick:
          type: string
          nullable: true
          description: >-
            What one click cost: the same measured-placements-only money cpm
            divides, over total clicks. Read it together with measuredPlacements
            for the same reason cpm must be — while placements are still
            unmeasured this is a partial price. Null while nothing has been
            clicked
        targetViews:
          type: integer
          format: int64
          nullable: true
          description: >-
            Pre-campaign forecast: expected views summed over every placement
            that can still deliver a post or already has. Null when no channel
            carries usable reach
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: string
    CampaignPlacementStatus:
      type: string
      enum:
        - NEW
        - AWAITING_CONTACT_VERIFICATION
        - IN_PROGRESS
        - AWAITING_CREATIVE_APPROVAL
        - PENDING_APPROVAL
        - APPROVED
        - PAYMENT_PENDING
        - PAYMENT_FAILED
        - PAID
        - AWAITING_POST
        - PUBLISHED
        - VERIFIED
        - COMPLETED
        - REJECTED
        - ESCALATED
        - CANCELLED
        - BREACH
  responses:
    DefaultError:
      description: Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    Bearer:
      type: http
      scheme: bearer
      bearerFormat: JWT

````