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

# Get Posture Reports

> Retrieve completed Microsoft 365 security posture reports for the tenants in your organization. By default this returns the most recent completed report for each tenant, newest first. Each report includes the score and grade, a rollup of control results, the Global Administrators review, the top risks, and every individual check with its status, severity, current state, and suggested fix. Results reflect any edits made to the report in the Petra dashboard, so they match the PDF your clients see.

<Note>For common API errors, see [API Troubleshooting](/docs/api-reference/troubleshooting).</Note>

<Note>This route is limited to **10 requests per minute**.</Note>

Posture reports are generated from the Petra dashboard under Reporting, then Posture Report. This endpoint returns completed reports only. By default you get the latest report for each tenant; pass `latestOnly=false` to see report history.

Each report includes every assessed control under `checks`. Values reflect any edits made to the report in the dashboard, so the API matches the PDF your clients see.

You can find a tenant's Petra ID in the URL when viewing a tenant in the dashboard (e.g. `app.petrasecurity.com/tenant/<tenantId>`). You can also pass a Microsoft tenant ID and the endpoint will resolve it automatically.


## OpenAPI

````yaml GET /v1/posture-reports
openapi: 3.0.3
info:
  title: Petra Security API
  description: >-
    The Petra Security API provides programmatic access to security data and
    functionality within your Petra portal.
  version: 1.0.0
  contact:
    name: Petra Security Support
    email: support@petrasecurity.com
servers:
  - url: https://api.petrasecurity.com
    description: Production server
security:
  - bearerAuth: []
paths:
  /v1/posture-reports:
    get:
      tags: []
      summary: Get posture reports
      description: >-
        Retrieve completed Microsoft 365 security posture reports for the
        tenants in your organization. By default this returns the most recent
        completed report for each tenant, newest first. Each report includes the
        score and grade, a rollup of control results, the Global Administrators
        review, the top risks, and every individual check with its status,
        severity, current state, and suggested fix. Results reflect any edits
        made to the report in the Petra dashboard, so they match the PDF your
        clients see.
      operationId: getPostureReports
      parameters:
        - name: tenantId
          in: query
          required: false
          description: >-
            Filter to a specific tenant. Accepts either a Petra tenant ID or a
            Microsoft tenant ID. You can find a tenant's Petra ID in the URL
            when viewing a tenant in the dashboard (e.g.
            app.petrasecurity.com/tenant/<tenantId>). Returns 404 if the tenant
            is not in your organization.
          schema:
            type: string
        - name: latestOnly
          in: query
          required: false
          description: >-
            When true (the default), return only the most recent completed
            report per tenant. Set to false to return report history, newest
            first.
          schema:
            type: boolean
            default: true
        - name: startDate
          in: query
          required: false
          description: >-
            Only return reports completed on or after this date. Accepts ISO
            8601 format, either date only (e.g. 2026-03-01) or full date-time
            (e.g. 2026-03-05T00:53:10.402Z).
          schema:
            type: string
            format: date-time
        - name: limit
          in: query
          required: false
          description: Maximum number of reports to return. Defaults to 100, maximum 500.
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 500
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetPostureReportsResponse'
        '400':
          description: Bad Request - Invalid startDate
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized - Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found - The specified tenant was not found in your organization
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Too Many Requests - Rate limit exceeded for this route
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security:
        - bearerAuth: []
components:
  schemas:
    GetPostureReportsResponse:
      type: object
      properties:
        totalReports:
          type: integer
          description: Number of reports in this response
        reports:
          type: array
          items:
            $ref: '#/components/schemas/PostureReport'
      example:
        totalReports: 1
        reports:
          - id: 7c1a4a1e-3b2f-4a55-9d7e-1f0c2b3d4e5f
            url: >-
              https://app.petrasecurity.com/reporting/posture/editor?scanId=7c1a4a1e-3b2f-4a55-9d7e-1f0c2b3d4e5f
            tenant:
              petraTenantId: ZZk90t
              name: Acme Corp.
              microsoftTenantId: 0f3b9a4e-6c7d-4e8f-9a0b-1c2d3e4f5a6b
            reportType: FOLLOW_UP
            baseline:
              id: 2d9e8f7a-6b5c-4d3e-8f2a-1b0c9d8e7f6a
              score: 58
              completedAt: '2026-05-02T14:10:22.000Z'
            createdAt: '2026-08-01T10:00:00.000Z'
            completedAt: '2026-08-01T10:04:37.000Z'
            activityLookbackDays: 90
            score: 81
            grade: B
            previousScore: 58
            previousGrade: D
            controls:
              assessed: 27
              secure: 17
              fixed: 5
              inProgress: 1
              open: 4
              drifted: 0
              notAssessed: 2
            globalAdmins:
              count: 3
              previousCount: 6
              bestPractice: 4 or fewer
              strongMfaCount: 3
              dataComplete: true
              admins:
                - userPrincipalName: admin@acmecorp.com
                  status: secure
                  mfaEnforced: Conditional Access
                  mfaStrength: Authenticator app
                  mfaStrengthStrong: true
                  passwordAge: 41 days
                  passwordAgeWarning: false
                  failedSignIns: 0
            topRisks:
              - controlId: blockLegacyAuth
                name: Block legacy sign-in protocols that bypass MFA
                status: open
                severity: critical
            checks:
              - controlId: blockLegacyAuth
                category: conditionalAccess
                name: Block legacy sign-in protocols that bypass MFA
                status: open
                severity: critical
                currentState: No Conditional Access policy blocks legacy authentication.
                previousState: null
                why: Legacy protocols skip MFA entirely
                suggestedFix: Block legacy authentication tenant-wide
                observedUsage: '90d: 0 legacy sign-ins. Fixing breaks nothing.'
              - controlId: disableSmtpAuth
                category: exchange
                name: Disable SMTP AUTH tenant-wide
                status: fixed
                severity: high
                currentState: SMTP AUTH is disabled tenant-wide.
                previousState: Enabled
                why: SMTP AUTH bypasses modern authentication
                suggestedFix: Disabled
                observedUsage: null
              - controlId: globalAdmins
                category: globalAdmins
                name: Limit the number of Global Administrators
                status: secure
                severity: high
                currentState: 3 Global Administrators.
                previousState: '6'
                why: Each admin is a high value target
                suggestedFix: Limit to 4 or fewer Global Administrators
                observedUsage: null
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Error code
            message:
              type: string
              description: Human-readable error message
            details:
              type: string
              description: Additional error details
      example:
        error:
          code: UNAUTHORIZED
          message: Invalid API key
          details: The provided API key is invalid or has been revoked
    PostureReport:
      type: object
      properties:
        id:
          type: string
          description: Report identifier
        url:
          type: string
          description: Link to open this report in the Petra dashboard
        tenant:
          $ref: '#/components/schemas/IncidentTenant'
        reportType:
          type: string
          enum:
            - BASELINE
            - FOLLOW_UP
          description: >-
            BASELINE is a first assessment. FOLLOW_UP compares against an
            earlier assessment and carries fixed and drifted results. Older
            follow-ups may have a null baseline while still reporting
            previousScore and previousGrade.
        baseline:
          nullable: true
          type: object
          description: >-
            The baseline this follow-up compares against, or null for a baseline
            report
          properties:
            id:
              type: string
            score:
              type: integer
              nullable: true
            completedAt:
              type: string
              format: date-time
              nullable: true
        createdAt:
          type: string
          format: date-time
          description: When the report was requested
        completedAt:
          type: string
          format: date-time
          nullable: true
          description: When the report finished generating
        activityLookbackDays:
          type: integer
          description: Sign-in and mail activity window used for the observed-usage lines
        score:
          type: integer
          description: >-
            Posture score, 0 to 100, severity-weighted share of assessed
            controls that meet best practice
        grade:
          type: string
          description: Letter grade for the score
        previousScore:
          type: integer
          nullable: true
          description: Score at the baseline, for follow-up reports
        previousGrade:
          type: string
          nullable: true
        controls:
          $ref: '#/components/schemas/PostureControlsRollup'
        globalAdmins:
          $ref: '#/components/schemas/PostureGlobalAdmins'
        topRisks:
          type: array
          description: The highest likelihood x impact findings, ranked
          items:
            type: object
            properties:
              controlId:
                type: string
              name:
                type: string
              status:
                type: string
                enum:
                  - secure
                  - fixed
                  - open
                  - drifted
                  - in-progress
                  - not-assessed
                description: >-
                  secure: meets best practice. fixed: was a gap and is now
                  secure (follow-up reports). open: does not meet best practice.
                  drifted: was secure and has regressed (follow-up reports).
                  in-progress: a fix is underway. not-assessed: Petra could not
                  evaluate this control (missing license or permission).
              severity:
                type: string
                nullable: true
                enum:
                  - critical
                  - high
                  - medium
                  - low
                description: >-
                  How much the client should care if this control is
                  misconfigured.
        checks:
          type: array
          description: Every assessed control, in report section order
          items:
            $ref: '#/components/schemas/PostureCheck'
    IncidentTenant:
      type: object
      properties:
        petraTenantId:
          type: string
          description: >-
            The Petra tenant ID (found in the dashboard URL:
            app.petrasecurity.com/tenant/<petraTenantId>)
        name:
          type: string
          description: Display name of the tenant
        microsoftTenantId:
          type: string
          description: The Microsoft tenant ID
    PostureControlsRollup:
      type: object
      description: Counts of controls by result. assessed excludes notAssessed.
      properties:
        assessed:
          type: integer
        secure:
          type: integer
        fixed:
          type: integer
        inProgress:
          type: integer
        open:
          type: integer
        drifted:
          type: integer
        notAssessed:
          type: integer
    PostureGlobalAdmins:
      type: object
      properties:
        count:
          type: integer
          description: Current number of Global Administrators
        previousCount:
          type: integer
          nullable: true
        bestPractice:
          type: string
        strongMfaCount:
          type: integer
          description: Admins whose MFA method is strong or phishing-resistant
        dataComplete:
          type: boolean
          description: false when Microsoft returned only a partial administrator list
        admins:
          type: array
          items:
            $ref: '#/components/schemas/PostureGlobalAdmin'
    PostureCheck:
      type: object
      properties:
        controlId:
          type: string
          description: Stable identifier for the control, e.g. blockLegacyAuth
        category:
          type: string
          enum:
            - conditionalAccess
            - accounts
            - globalAdmins
            - appsDirectory
            - externalSharing
            - exchange
        name:
          type: string
        status:
          type: string
          enum:
            - secure
            - fixed
            - open
            - drifted
            - in-progress
            - not-assessed
          description: >-
            secure: meets best practice. fixed: was a gap and is now secure
            (follow-up reports). open: does not meet best practice. drifted: was
            secure and has regressed (follow-up reports). in-progress: a fix is
            underway. not-assessed: Petra could not evaluate this control
            (missing license or permission).
        severity:
          type: string
          nullable: true
          enum:
            - critical
            - high
            - medium
            - low
          description: How much the client should care if this control is misconfigured.
        currentState:
          type: string
          description: Plain-English description of the current configuration
        previousState:
          type: string
          nullable: true
          description: Prior value for fixed or drifted results
        why:
          type: string
          nullable: true
          description: One line on why this control matters
        suggestedFix:
          type: string
          nullable: true
          description: Recommended change to meet best practice
        observedUsage:
          type: string
          nullable: true
          description: >-
            What the tenant's own activity logs show about this control's
            real-world use over the lookback window
    PostureGlobalAdmin:
      type: object
      properties:
        userPrincipalName:
          type: string
        status:
          type: string
          enum:
            - secure
            - fixed
            - open
            - drifted
            - in-progress
            - not-assessed
          description: >-
            secure: meets best practice. fixed: was a gap and is now secure
            (follow-up reports). open: does not meet best practice. drifted: was
            secure and has regressed (follow-up reports). in-progress: a fix is
            underway. not-assessed: Petra could not evaluate this control
            (missing license or permission).
        mfaEnforced:
          type: string
          description: How MFA is enforced for this admin
        mfaStrength:
          type: string
          description: Strongest registered MFA method
        mfaStrengthStrong:
          type: boolean
        passwordAge:
          type: string
        passwordAgeWarning:
          type: boolean
          description: true when the password is older than 100 days
        failedSignIns:
          type: integer
          description: >-
            Failed sign-in attempts observed on the account over the lookback
            window
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Bearer token authentication. Include your API key in the Authorization
        header as 'Bearer YOUR_API_KEY'

````