openapi: 3.0.3
info:
  title: Disco Reporting API V2
  version: "2.0.0"
  description: >
    Build flat, paginated channel reports with selectable metrics, UTC time
    grains, up to three breakdown columns, and filters. Authenticate with a
    management API key in the `x-api-key` header. Every request is scoped to
    the authenticated channel.
servers:
  - url: https://api.disconetwork.com
    description: Disco API
security:
  - ManagementApiKey: []
paths:
  /discobeat/reporting/v2/report/:
    get:
      summary: Build a report
      description: >
        Returns flat, paginated rows plus summary metrics across the complete
        filtered result. The response includes only the requested metrics and
        selected breakdown columns.
      operationId: getReportingV2Report
      parameters:
        - $ref: "#/components/parameters/From"
        - $ref: "#/components/parameters/To"
        - $ref: "#/components/parameters/Metrics"
        - $ref: "#/components/parameters/TimeGrain"
        - $ref: "#/components/parameters/GroupBy"
        - $ref: "#/components/parameters/PublisherIds"
        - $ref: "#/components/parameters/PageTypes"
        - $ref: "#/components/parameters/WidgetTypes"
        - $ref: "#/components/parameters/Offset"
        - $ref: "#/components/parameters/Limit"
      responses:
        "200":
          description: Paginated report rows and complete matching summary.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReportResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "405":
          $ref: "#/components/responses/MethodNotAllowed"
components:
  securitySchemes:
    ManagementApiKey:
      type: apiKey
      in: header
      name: x-api-key
  parameters:
    From:
      name: from
      in: query
      required: true
      description: Start date in UTC, inclusive.
      schema:
        type: string
        format: date
        example: "2026-07-18"
    To:
      name: to
      in: query
      required: true
      description: End date in UTC, inclusive. The requested range can span at most 90 days.
      schema:
        type: string
        format: date
        example: "2026-07-20"
    Metrics:
      name: metrics
      in: query
      required: true
      description: >
        Comma-separated metrics enabled for the authenticated channel. Metrics
        must be unique.
      style: form
      explode: false
      schema:
        type: array
        minItems: 1
        uniqueItems: true
        items:
          $ref: "#/components/schemas/Metric"
      example: [impressions, clicks, channel_payout, ctr]
    TimeGrain:
      name: time_grain
      in: query
      required: false
      description: >
        UTC row interval. Hour supports at most 3 days and one breakdown.
        Week and month edge periods are clipped to the requested date range.
      schema:
        type: string
        enum: [total, day, week, month, hour]
        default: total
    GroupBy:
      name: group_by
      in: query
      required: false
      description: >
        Comma-separated breakdown columns. Up to three are supported except
        hourly reports, which support at most one.
      style: form
      explode: false
      schema:
        type: array
        maxItems: 3
        uniqueItems: true
        items:
          type: string
          enum: [publisher, page_type, widget_type, widget_id]
      example: [publisher, page_type]
    PublisherIds:
      name: publisher_ids
      in: query
      required: false
      description: Comma-separated publisher UUID filter. Filtering does not add a report column.
      style: form
      explode: false
      schema:
        type: array
        maxItems: 250
        items:
          type: string
      example: [9aa17f8c-7746-4218-9025-83d38c406179]
    PageTypes:
      name: page_types
      in: query
      required: false
      description: Comma-separated page-type filter. Filtering does not add a report column.
      style: form
      explode: false
      schema:
        type: array
        maxItems: 250
        items:
          type: string
      example: [ORDER_TRACKING, THANK_YOU]
    WidgetTypes:
      name: widget_types
      in: query
      required: false
      description: Comma-separated widget-type filter. Filtering does not add a report column.
      style: form
      explode: false
      schema:
        type: array
        maxItems: 250
        items:
          type: string
      example: [APP_NATIVE_ESSENTIAL]
    Offset:
      name: offset
      in: query
      required: false
      description: Pagination offset.
      schema:
        type: integer
        minimum: 0
        default: 0
    Limit:
      name: limit
      in: query
      required: false
      description: JSON page size.
      schema:
        type: integer
        minimum: 1
        maximum: 250
        default: 50
  responses:
    BadRequest:
      description: Invalid query, unavailable metric or data, date outside the available window, or result over 10,000 rows.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          examples:
            metricNotAvailable:
              value:
                code: METRIC_NOT_AVAILABLE
                unsupported_metrics: [channel_payout]
                allowed_metrics: [impressions, clicks, ctr]
            outsideAvailableWindow:
              value:
                code: DATE_RANGE_OUTSIDE_AVAILABLE_WINDOW
                message: Reporting data is available from 2026-05-16 through 2026-07-22.
                available_window:
                  from: "2026-05-16"
                  to: "2026-07-22"
            rowLimit:
              value:
                code: REPORT_ROW_LIMIT_EXCEEDED
                message: Report exceeds the interactive row limit. Narrow the date range or remove one or more breakdowns.
                max_rows: 10000
                total_rows: 12000
    Unauthorized:
      description: Missing or invalid management API key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            detail: Invalid or expired management API key.
    MethodNotAllowed:
      description: Only GET is supported.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
          example:
            detail: Method "POST" not allowed.
  schemas:
    Metric:
      type: string
      enum:
        - impressions
        - clicks
        - conversions
        - channel_payout
        - revenue_with_email
        - revenue_without_email
        - sessions
        - feed_loads
        - ctr
        - cvr
        - rps
        - rpl
    MetricValues:
      type: object
      properties:
        impressions: { type: integer, example: 225072 }
        clicks: { type: integer, example: 8928 }
        conversions: { type: integer, example: 864 }
        channel_payout: { type: number, format: double, example: 6546.24 }
        revenue_with_email: { type: number, format: double, example: 4909.68 }
        revenue_without_email: { type: number, format: double, example: 1636.56 }
        sessions: { type: integer, example: 120000 }
        feed_loads: { type: integer, example: 135000 }
        ctr: { type: number, format: double, example: 0.0397 }
        cvr: { type: number, format: double, example: 0.0968 }
        rps: { type: number, format: double, example: 0.0546 }
        rpl: { type: number, format: double, example: 0.0485 }
    ReportRow:
      allOf:
        - type: object
          required: [period_start, period_end]
          properties:
            period_start:
              type: string
              format: date-time
              description: Inclusive UTC period boundary.
              example: "2026-07-18T00:00:00Z"
            period_end:
              type: string
              format: date-time
              description: Exclusive UTC period boundary.
              example: "2026-07-19T00:00:00Z"
            publisher_id:
              type: string
              nullable: true
              example: 9aa17f8c-7746-4218-9025-83d38c406179
            publisher_name:
              type: string
              nullable: true
              example: AfterShip Tracking Page
            page_type:
              type: string
              nullable: true
              example: ORDER_TRACKING
            widget_type:
              type: string
              nullable: true
              example: APP_NATIVE_ESSENTIAL
            widget_id:
              type: string
              nullable: true
              maxLength: 64
        - $ref: "#/components/schemas/MetricValues"
    Pagination:
      type: object
      required: [offset, limit, total, has_more]
      properties:
        offset: { type: integer, example: 0 }
        limit: { type: integer, example: 50 }
        total: { type: integer, example: 36 }
        has_more: { type: boolean, example: false }
    ReportMeta:
      type: object
      required: [timezone, data_through, request_id]
      properties:
        timezone:
          type: string
          enum: [UTC]
        data_through:
          type: string
          format: date-time
          nullable: true
          example: "2026-07-22T23:00:00Z"
        request_id:
          type: string
          nullable: true
          example: 7e9fe348-7558-4e28-b8c6-b26ea44899eb
    ReportResponse:
      type: object
      required: [data, summary, pagination, meta]
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ReportRow"
        summary:
          $ref: "#/components/schemas/MetricValues"
        pagination:
          $ref: "#/components/schemas/Pagination"
        meta:
          $ref: "#/components/schemas/ReportMeta"
    ErrorResponse:
      type: object
      additionalProperties: true
