openapi: 3.0.3

info:
  title: SentryAgent.ai — Compliance & SOC 2 Type II Service
  version: 1.0.0
  description: |
    The Compliance Service exposes endpoints supporting SentryAgent.ai's
    **SOC 2 Type II** audit readiness programme.

    Two categories of control are surfaced:

    **Audit chain verification** (`GET /audit/verify`) — Confirms cryptographic
    integrity of the immutable audit log chain across an optional date range.
    This endpoint provides auditors and compliance tooling with a single call to
    assert that no audit events have been tampered with, deleted, or reordered
    after initial capture.

    **SOC 2 control status** (`GET /compliance/controls`) — Returns a live status
    snapshot for each of the five in-scope SOC 2 Trust Services Criteria controls
    monitored by the platform. Designed as a lightweight, public health-style
    endpoint so that monitoring infrastructure can poll without bearer credentials.

    **In-scope SOC 2 controls:**
    | Control ID | Name | Description |
    |------------|------|-------------|
    | `CC6.1` | Encryption at Rest | Verifies database and secrets store encryption is active |
    | `CC6.7` | TLS Enforcement | Confirms TLS 1.2+ is enforced on all inbound connections |
    | `CC7.2` | Audit Log Integrity | Validates audit chain hash continuity |
    | `CC9.2` | Secrets Rotation | Checks that all managed secrets are within rotation policy |
    | `CC7.1` | Webhook Dead-Letter Monitoring | Asserts dead-letter queue depth is within threshold |

    **Required scope (audit chain verify only):** `audit:read`

servers:
  - url: http://localhost:3000/api/v1
    description: Local development server
  - url: https://api.sentryagent.ai/v1
    description: Production server

tags:
  - name: Audit Chain
    description: Cryptographic integrity verification of the immutable audit event chain
  - name: Compliance Controls
    description: SOC 2 Type II control status — public health-style monitoring endpoint

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        JWT access token with `audit:read` scope, obtained via `POST /token`.
        Include as: `Authorization: Bearer <token>`

  schemas:
    ChainVerificationResult:
      type: object
      description: |
        Result of an audit event chain integrity verification run.

        The audit log is structured as a hash-linked chain. Each event stores a
        reference to the hash of the preceding event. `verified: true` means every
        event in the requested window was checked and no breaks in the chain were
        detected.

        When `verified` is `false`, `brokenAtEventId` identifies the first event
        where the chain integrity check failed, enabling targeted forensic investigation.
      required:
        - verified
        - checkedCount
        - brokenAtEventId
      properties:
        verified:
          type: boolean
          description: >
            `true` if every audit event in the checked range maintains an unbroken
            cryptographic hash chain; `false` if at least one chain break was detected.
          example: true
        checkedCount:
          type: integer
          description: Total number of audit events examined during this verification run.
          minimum: 0
          example: 2847
        brokenAtEventId:
          type: string
          format: uuid
          nullable: true
          description: >
            UUID of the first audit event where chain continuity failed, or `null`
            when `verified` is `true`. Only the first detected break is reported;
            subsequent events are not checked after a break is found.
          example: null
        fromDate:
          type: string
          format: date-time
          description: >
            The ISO 8601 lower bound of the date range that was verified.
            Present only when a `fromDate` query parameter was supplied.
          example: "2026-03-01T00:00:00.000Z"
        toDate:
          type: string
          format: date-time
          description: >
            The ISO 8601 upper bound of the date range that was verified.
            Present only when a `toDate` query parameter was supplied.
          example: "2026-03-31T23:59:59.999Z"

    ControlStatus:
      type: string
      description: Operational status of a SOC 2 control at the time of the last check.
      enum:
        - passing
        - failing
        - unknown
      example: passing

    ComplianceControl:
      type: object
      description: Status record for a single SOC 2 Trust Services Criteria control.
      required:
        - id
        - name
        - status
        - lastChecked
      properties:
        id:
          type: string
          description: SOC 2 Trust Services Criteria control identifier.
          enum:
            - CC6.1
            - CC6.7
            - CC7.2
            - CC9.2
            - CC7.1
          example: "CC6.1"
        name:
          type: string
          description: Human-readable name of the control.
          example: "Encryption at Rest"
        status:
          $ref: '#/components/schemas/ControlStatus'
        lastChecked:
          type: string
          format: date-time
          description: ISO 8601 timestamp of the most recent automated check for this control.
          example: "2026-03-31T06:00:00.000Z"

    ComplianceControlsResponse:
      type: object
      description: SOC 2 compliance control status summary for all in-scope controls.
      required:
        - controls
      properties:
        controls:
          type: array
          description: Status record for each of the five in-scope SOC 2 controls.
          minItems: 5
          maxItems: 5
          items:
            $ref: '#/components/schemas/ComplianceControl'
          example:
            - id: "CC6.1"
              name: "Encryption at Rest"
              status: "passing"
              lastChecked: "2026-03-31T06:00:00.000Z"
            - id: "CC6.7"
              name: "TLS Enforcement"
              status: "passing"
              lastChecked: "2026-03-31T06:00:00.000Z"
            - id: "CC7.2"
              name: "Audit Log Integrity"
              status: "passing"
              lastChecked: "2026-03-31T06:00:00.000Z"
            - id: "CC9.2"
              name: "Secrets Rotation"
              status: "passing"
              lastChecked: "2026-03-31T06:00:00.000Z"
            - id: "CC7.1"
              name: "Webhook Dead-Letter Monitoring"
              status: "passing"
              lastChecked: "2026-03-31T06:00:00.000Z"

    ErrorResponse:
      type: object
      description: Standard error response envelope used across all SentryAgent.ai APIs.
      required:
        - code
        - message
      properties:
        code:
          type: string
          description: Machine-readable error code.
          example: "UNAUTHORIZED"
        message:
          type: string
          description: Human-readable description of the error.
          example: "A valid Bearer token is required."
        details:
          type: object
          description: Optional structured details providing additional context.
          additionalProperties: true
          example: {}

  responses:
    Unauthorized:
      description: Missing or invalid Bearer token.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: "UNAUTHORIZED"
            message: "A valid Bearer token is required to access this resource."

    Forbidden:
      description: Valid token but insufficient permissions. Requires `audit:read` scope.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: "INSUFFICIENT_SCOPE"
            message: "The 'audit:read' scope is required to verify the audit chain."

    TooManyRequests:
      description: |
        Rate limit exceeded. Retry after the reset time indicated in `X-RateLimit-Reset`.
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
          description: Maximum requests allowed per minute.
          example: 30
        X-RateLimit-Remaining:
          schema:
            type: integer
          description: Requests remaining in the current window.
          example: 0
        X-RateLimit-Reset:
          schema:
            type: integer
          description: Unix timestamp when the rate limit window resets.
          example: 1743155400
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: "RATE_LIMIT_EXCEEDED"
            message: "Too many requests. Please retry after the rate limit window resets."

    InternalServerError:
      description: Unexpected server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            code: "INTERNAL_SERVER_ERROR"
            message: "An unexpected error occurred. Please try again later."

paths:
  /audit/verify:
    get:
      operationId: verifyAuditChain
      tags:
        - Audit Chain
      summary: Verify audit log chain integrity
      description: |
        Triggers a full integrity verification pass over the immutable audit event
        chain. Each event in the log contains a cryptographic hash of the previous
        event; this endpoint traverses the chain and confirms no breaks exist.

        **Use cases:**
        - Auditor evidence collection for SOC 2 Type II assessment
        - Continuous compliance monitoring (cron-driven)
        - Incident response — confirm audit log has not been tampered with

        **Requires:** Bearer token with `audit:read` scope.

        **Rate limit:** 30 requests/minute per `client_id`. Audit chain verification
        is a computationally intensive operation and is rate-limited more aggressively
        than standard read endpoints. For continuous monitoring, poll no more than
        once per minute.

        **Date range filtering:** Supply `fromDate` and/or `toDate` to restrict
        verification to a specific window. When omitted, the entire retained audit
        log is verified. `fromDate` must be before or equal to `toDate` when both
        are provided.

        **Result interpretation:**
        - `verified: true` — chain is intact across all checked events
        - `verified: false` — at least one chain break detected; `brokenAtEventId`
          identifies the first affected event
      security:
        - BearerAuth: []
      parameters:
        - name: fromDate
          in: query
          description: |
            ISO 8601 date-time lower bound for the verification window (inclusive).
            When omitted, verification starts from the earliest available audit event.
            Must be before or equal to `toDate` when both are supplied.
          required: false
          schema:
            type: string
            format: date-time
          example: "2026-03-01T00:00:00.000Z"
        - name: toDate
          in: query
          description: |
            ISO 8601 date-time upper bound for the verification window (inclusive).
            When omitted, verification runs up to and including the most recent
            audit event. Must be after or equal to `fromDate` when both are supplied.
          required: false
          schema:
            type: string
            format: date-time
          example: "2026-03-31T23:59:59.999Z"
      responses:
        '200':
          description: |
            Audit chain verification completed. Inspect `verified` to determine
            whether chain integrity is intact. A `200` is returned regardless of
            whether verification passed or failed — check the response body.
          headers:
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Maximum requests allowed per minute for this endpoint.
              example: 30
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining in the current rate limit window.
              example: 29
            X-RateLimit-Reset:
              schema:
                type: integer
              description: Unix timestamp when the rate limit window resets.
              example: 1743155400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChainVerificationResult'
              examples:
                chainIntact:
                  summary: Verification passed — chain is intact
                  value:
                    verified: true
                    checkedCount: 2847
                    brokenAtEventId: null
                    fromDate: "2026-03-01T00:00:00.000Z"
                    toDate: "2026-03-31T23:59:59.999Z"
                chainBroken:
                  summary: Verification failed — chain break detected
                  value:
                    verified: false
                    checkedCount: 1203
                    brokenAtEventId: "c4d5e6f7-a8b9-0123-cdef-456789012345"
                    fromDate: "2026-03-01T00:00:00.000Z"
                    toDate: "2026-03-31T23:59:59.999Z"
                noDateRange:
                  summary: Full log verified (no date range supplied)
                  value:
                    verified: true
                    checkedCount: 18504
                    brokenAtEventId: null
        '400':
          description: Invalid query parameter value or date range.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                invalidFromDate:
                  summary: fromDate is not a valid ISO 8601 date-time
                  value:
                    code: "VALIDATION_ERROR"
                    message: "Invalid query parameter value."
                    details:
                      field: "fromDate"
                      reason: "Must be a valid ISO 8601 date-time string (e.g. 2026-03-01T00:00:00.000Z)."
                invalidToDate:
                  summary: toDate is not a valid ISO 8601 date-time
                  value:
                    code: "VALIDATION_ERROR"
                    message: "Invalid query parameter value."
                    details:
                      field: "toDate"
                      reason: "Must be a valid ISO 8601 date-time string (e.g. 2026-03-31T23:59:59.999Z)."
                invalidDateRange:
                  summary: fromDate is after toDate
                  value:
                    code: "VALIDATION_ERROR"
                    message: "Invalid date range."
                    details:
                      reason: "fromDate must be before or equal to toDate."
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /compliance/controls:
    get:
      operationId: getComplianceControls
      tags:
        - Compliance Controls
      summary: Get SOC 2 control status summary
      description: |
        Returns a live status snapshot for each of the five in-scope SOC 2 Type II
        Trust Services Criteria controls monitored by the SentryAgent.ai platform.

        **No authentication required.** This endpoint is intentionally public
        (analogous to a health check) so that external monitoring infrastructure,
        status pages, and audit tooling can poll it without bearer credentials.

        **Controls monitored:**
        | Control ID | Name | What is checked |
        |------------|------|-----------------|
        | `CC6.1` | Encryption at Rest | Database and secrets store encryption is active and configured |
        | `CC6.7` | TLS Enforcement | TLS 1.2+ is enforced on all platform inbound connections |
        | `CC7.2` | Audit Log Integrity | Audit chain hash continuity — shorthand of `/audit/verify` |
        | `CC9.2` | Secrets Rotation | All managed secrets are within the rotation policy window |
        | `CC7.1` | Webhook Dead-Letter Monitoring | Dead-letter queue depth is within the acceptable threshold |

        **Status values:**
        - `passing` — control is operating within policy
        - `failing` — control has breached policy; immediate attention required
        - `unknown` — automated check could not complete (e.g. dependency unavailable)

        **Caching note:** Responses may be cached for up to 60 seconds by
        intermediate proxies. The `lastChecked` field on each control indicates
        the timestamp of the most recent automated evaluation.

        **Rate limit:** 120 requests/minute per IP address.
      security: []
      responses:
        '200':
          description: SOC 2 control status summary returned successfully.
          headers:
            Cache-Control:
              schema:
                type: string
              description: >
                Downstream caches may serve this response for up to 60 seconds.
              example: "public, max-age=60"
            X-RateLimit-Limit:
              schema:
                type: integer
              description: Maximum requests allowed per minute for this endpoint.
              example: 120
            X-RateLimit-Remaining:
              schema:
                type: integer
              description: Requests remaining in the current rate limit window.
              example: 119
            X-RateLimit-Reset:
              schema:
                type: integer
              description: Unix timestamp when the rate limit window resets.
              example: 1743155400
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComplianceControlsResponse'
              examples:
                allPassing:
                  summary: All controls passing
                  value:
                    controls:
                      - id: "CC6.1"
                        name: "Encryption at Rest"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC6.7"
                        name: "TLS Enforcement"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC7.2"
                        name: "Audit Log Integrity"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC9.2"
                        name: "Secrets Rotation"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC7.1"
                        name: "Webhook Dead-Letter Monitoring"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                oneControlFailing:
                  summary: One control failing (secrets rotation overdue)
                  value:
                    controls:
                      - id: "CC6.1"
                        name: "Encryption at Rest"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC6.7"
                        name: "TLS Enforcement"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC7.2"
                        name: "Audit Log Integrity"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC9.2"
                        name: "Secrets Rotation"
                        status: "failing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC7.1"
                        name: "Webhook Dead-Letter Monitoring"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                unknownControl:
                  summary: One control in unknown state (dependency unavailable)
                  value:
                    controls:
                      - id: "CC6.1"
                        name: "Encryption at Rest"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC6.7"
                        name: "TLS Enforcement"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC7.2"
                        name: "Audit Log Integrity"
                        status: "unknown"
                        lastChecked: "2026-03-31T05:00:00.000Z"
                      - id: "CC9.2"
                        name: "Secrets Rotation"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
                      - id: "CC7.1"
                        name: "Webhook Dead-Letter Monitoring"
                        status: "passing"
                        lastChecked: "2026-03-31T06:00:00.000Z"
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'
