openapi: 3.1.0
info:
  title: "Analytics API — Headless AI SDR (Reply.io)"
  version: "3.0"
  description: |
    Outcome reports for optimizing agents — channel overviews, activity feeds,
    team performance, channel efficiency, and the meetings list. All report
    endpoints are POST queries (filters in the body) under /v3/reporting/* and
    require the `reporting:read` scope. This is a summary specification for AI
    agents covering 7 of the group's 11 operations; /reporting/tasks/overview
    and the /reporting/calls, /reporting/linkedin, and /reporting/tasks
    activity lists follow the same request/response pattern. The authoritative,
    complete reference is
    https://docs.reply.io/api-reference/reports/get-email-reporting-overview
    and the full platform OpenAPI at
    https://docs.reply.io/api-reference/bundled.yaml.
  contact:
    name: Reply.io
    url: https://reply.io
servers:
  - url: https://api.reply.io/v3
security:
  - bearerAuth: []
tags:
  - name: Reports
paths:
  /reporting/emails/overview:
    post:
      tags: [Reports]
      operationId: getEmailOverview
      summary: Get email reporting overview
      description: |
        Requires the `reporting:read` scope. Returns email delivery and
        engagement metrics (delivered, opened, replied, interested, bounced,
        meetingsBooked, and percentage rates), with optional trend comparison
        via `compareTo`.
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Aggregated email metrics with counts and percentage rates.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailOverview"
        "429":
          $ref: "#/components/responses/RateLimited"
  /reporting/calls/overview:
    post:
      tags: [Reports]
      operationId: getCallsOverview
      summary: Get calls reporting overview
      description: |
        Requires the `reporting:read` scope. Returns aggregated call statistics
        with per-member breakdown — total calls, average duration,
        positive/answered counts, and inbound missed calls.
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Aggregated call statistics.
  /reporting/linkedin/overview:
    post:
      tags: [Reports]
      operationId: getLinkedInOverview
      summary: Get LinkedIn reporting overview
      description: |
        Requires the `reporting:read` scope. Returns LinkedIn engagement
        metrics — connection requests, messages, InMails, and profile views.
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Aggregated LinkedIn engagement metrics.
  /reporting/channel-efficiency/overview:
    post:
      tags: [Reports]
      operationId: getChannelEfficiencyOverview
      summary: Get channel efficiency overview
      description: |
        Requires the `reporting:read` scope. Returns cross-channel efficiency
        statistics comparing performance across email, calls, LinkedIn, and
        other channels — the input for channel-mix decisions.
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Cross-channel efficiency comparison.
  /reporting/team-performance/overview:
    post:
      tags: [Reports]
      operationId: getTeamPerformanceOverview
      summary: Get team performance overview
      description: |
        Requires the `reporting:read` scope. Returns team performance metrics —
        meetings booked, contacts engaged, conversion rates, touches per
        contact, and response times, with per-member breakdown.
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Team performance metrics with per-member breakdown.
  /reporting/emails:
    post:
      tags: [Reports]
      operationId: listEmailActivity
      summary: List email activity
      description: |
        Requires the `reporting:read` scope. Returns a paginated list of
        individual email activity records matching the filters. Paginate with
        the `top` and `skip` query parameters.
      parameters:
        - $ref: "#/components/parameters/top"
        - $ref: "#/components/parameters/skip"
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Paginated email activity records with a hasMore flag.
  /reporting/team-performance/meetings:
    post:
      tags: [Reports]
      operationId: listMeetings
      summary: List meetings
      description: |
        Requires the `reporting:read` scope. Returns a paginated list of
        meetings booked, matching the filters — the outcomes ledger. Booking
        itself happens through Reply's scheduling product; this endpoint only
        reports the results.
      parameters:
        - $ref: "#/components/parameters/top"
        - $ref: "#/components/parameters/skip"
      requestBody:
        $ref: "#/components/requestBodies/ReportQuery"
      responses:
        "200":
          description: Paginated booked-meeting records.
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: "#/components/schemas/MeetingListItem"
                  hasMore:
                    type: boolean
        "403":
          $ref: "#/components/responses/Forbidden"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: |
        Reply.io API key sent as a Bearer token. Create one in the Reply.io app
        under Settings → API Key. See
        https://docs.reply.io/api-reference/authentication.
  parameters:
    top:
      name: top
      in: query
      required: false
      schema:
        type: integer
      description: Page size for activity-list endpoints.
    skip:
      name: skip
      in: query
      required: false
      schema:
        type: integer
      description: Number of records to skip for pagination.
  requestBodies:
    ReportQuery:
      required: true
      content:
        application/json:
          schema:
            type: object
            required: [filters]
            properties:
              filters:
                $ref: "#/components/schemas/ReportingFilters"
              compareTo:
                type: object
                description: |
                  Optional comparison period (overview endpoints only) —
                  returns trend deltas against this window.
                properties:
                  from:
                    type: string
                    format: date-time
                  to:
                    type: string
                    format: date-time
  schemas:
    ReportingFilters:
      type: object
      description: |
        Base filters shared across all reporting endpoints. Defaults to
        lastWeek when neither dateRangePreset nor from/to are provided.
        Channel-specific endpoints accept extra filters (e.g. bounceTypes and
        sentiments on email reports).
      properties:
        from:
          type: string
          format: date-time
          description: Start of the reporting period. Cannot be combined with dateRangePreset.
        to:
          type: string
          format: date-time
          description: End of the reporting period.
        dateRangePreset:
          type: string
          enum: [lastWeek, lastMonth, lastYear, allTime]
          description: Predefined date range shortcut.
        sequenceIds:
          type: array
          items:
            type: integer
        teamIds:
          type: array
          items:
            type: integer
        userIds:
          type: array
          items:
            type: integer
        industries:
          type: array
          items:
            type: string
        titles:
          type: array
          items:
            type: string
        companySizes:
          type: array
          items:
            type: string
        countries:
          type: array
          items:
            type: string
    EmailOverview:
      type: object
      description: Aggregated email metrics. Each count has a matching percentage field.
      properties:
        contacted:
          type: integer
        delivered:
          type: integer
        opened:
          type: integer
        replied:
          type: integer
        interested:
          type: integer
        bounced:
          type: integer
        meetingsBooked:
          type: integer
        deliveredPercentage:
          type: number
        repliedPercentage:
          type: number
        interestedPercentage:
          type: number
    MeetingListItem:
      type: object
      description: A booked-meeting record in the team performance meetings list.
      properties:
        userId:
          type: integer
          description: User who booked the meeting.
        source:
          type: string
          description: "Channel that produced the meeting (e.g. automatedEmail, manualEmail, call, linkedIn, whatsApp)."
        contactFullName:
          type: string
        sequenceName:
          type: string
        bookedAt:
          type: string
          format: date-time
    Problem:
      type: object
      description: RFC 7807 problem document (application/problem+json).
      properties:
        type: { type: string }
        title: { type: string }
        status: { type: integer }
        detail: { type: string }
  responses:
    Forbidden:
      description: The API key is missing the required reporting:read scope.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
    RateLimited:
      description: |
        Rate limit exceeded (100 requests/minute, 3,000/hour per user; the
        /v3/reporting/* endpoints may throttle earlier than the general
        quota). Honor the Retry-After header.
      content:
        application/problem+json:
          schema:
            $ref: "#/components/schemas/Problem"
