openapi: 3.1.0
info:
  title: Protege External Review API
  version: 1.0.1
  license:
    name: Proprietary
    url: https://tryprotege.com/terms
  description: |
    The Protege External Review API gives client applications a secure, tenant-scoped way to submit
    content for compliance review, monitor asynchronous review jobs, and retrieve the reference data
    needed to configure review and scanning workflows.

    Use this API to:
    - Discover brands, policy groups, policies, and document evaluation types available to your tenant.
    - Submit text or file-based document reviews and retrieve structured findings.
    - Create and manage scanner jobs that monitor web content over time.
    - Inspect scanner reports and historical scanner runs.

    Authentication is handled with a Protege-issued bearer API key. Every request is scoped to the
    tenant and workspace associated with that key, so clients only see data they are authorized to access.

    Collection endpoints use offset-based pagination with `limit` and `offset` query parameters. Review
    creation supports both synchronous (`mode=sync`) and asynchronous (`mode=async`) execution patterns.

servers:
  - url: https://sandbox.tryprotege.com
    description: Sandbox environment for partner integration and testing.

tags:
  - name: Reference Data
    description: Lookup endpoints for the tenant-specific metadata required to drive review and scanner workflows.
  - name: Document Reviews
    description: Submit documents for review, track processing status, and retrieve completed findings.
  - name: Scanner Jobs
    description: Configure ongoing website monitoring jobs and inspect their latest run history.
  - name: Reports
    description: Retrieve scanner report summaries and detailed page-level report output.

security:
  - bearerApiKey: []

components:
  securitySchemes:
    bearerApiKey:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: >
        Supply the Protege external API key in the `Authorization` header using the format
        `Bearer <api_key>`.

  schemas:
    ErrorResponse:
      description: Standard error envelope returned when a request cannot be fulfilled.
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Human-readable explanation of the failure.
          example: Invalid query parameters

    ReviewMode:
      description: Controls whether the review should complete inline or be queued for background processing.
      type: string
      enum: [sync, async]
      default: sync

    ReviewStatus:
      description: Current processing state of a submitted document review.
      type: string
      enum: [queued, processing, completed, failed]

    TextReviewDocument:
      description: Plain-text document content submitted directly in the JSON request body.
      type: object
      required:
        - type
        - text
      properties:
        type:
          type: string
          enum: [text]
          description: Identifies the document payload type.
        title:
          type: string
          description: Client-friendly document title shown in review metadata.
        externalId:
          type: string
          description: Client-supplied identifier used to correlate Protege reviews with your own records.
        text:
          type: string
          description: Full plain-text content to review.
        metadata:
          type: object
          description: Optional client-defined metadata that Protege stores with the review.
          additionalProperties: true

    TextReviewRequest:
      description: JSON request body for creating a review from plain text content.
      type: object
      required:
        - documentEvaluationTypeId
        - document
      properties:
        mode:
          $ref: '#/components/schemas/ReviewMode'
        documentEvaluationTypeId:
          type: string
          format: uuid
          description: Identifier of the review configuration to apply.
        document:
          $ref: '#/components/schemas/TextReviewDocument'

    MultipartFileReviewRequest:
      description: Multipart form payload for uploading a single file to review.
      type: object
      required:
        - documentEvaluationTypeId
        - file
      properties:
        mode:
          $ref: '#/components/schemas/ReviewMode'
        documentEvaluationTypeId:
          type: string
          format: uuid
          description: Identifier of the review configuration to apply.
        title:
          type: string
          description: Optional title to associate with the uploaded document.
        externalId:
          type: string
          description: Client-supplied identifier used for downstream reconciliation.
        metadata:
          type: string
          description: JSON-encoded object string for document metadata.
          example: '{"sourceSystem":"partner-api","documentCategory":"msa"}'
        file:
          type: string
          format: binary
          description: >
            Upload a single file. Supported types are `.docx`, `.pdf`, `.png`,
            `.jpg`, and `.jpeg`.

    PolicyRef:
      description: Lightweight policy reference attached to a finding.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    TrademarkRef:
      description: Lightweight trademark reference attached to a finding.
      type: object
      required:
        - id
        - name
        - proprietary
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        proprietary:
          type: boolean
        approval:
          oneOf:
            - type: string
            - type: 'null'
        markType:
          oneOf:
            - type: string
            - type: 'null'

    Finding:
      description: >
        Structured review output describing a policy, trademark, or claim-related issue found in the document.
        The populated fields depend on the `kind` value.
      oneOf:
        - $ref: '#/components/schemas/PolicyFeedbackFinding'
        - $ref: '#/components/schemas/ClaimFinding'
        - $ref: '#/components/schemas/TrademarkInstanceFinding'
      discriminator:
        propertyName: kind
        mapping:
          policy_feedback: '#/components/schemas/PolicyFeedbackFinding'
          claim: '#/components/schemas/ClaimFinding'
          trademark_instance: '#/components/schemas/TrademarkInstanceFinding'

    FindingBase:
      description: Fields shared across every finding kind.
      type: object
      required:
        - kind
        - text
        - comment
        - feedbackLocation
        - status
        - details
      properties:
        kind:
          type: string
          enum: [policy_feedback, claim, trademark_instance]
          description: Category of finding returned by Protege.
        text:
          oneOf:
            - type: string
            - type: 'null'
          description: Text snippet or extracted value associated with the finding, when available.
        comment:
          oneOf:
            - type: string
            - type: 'null'
          description: Reviewer-facing explanation of the issue or recommendation.
        riskLevel:
          oneOf:
            - type: string
            - type: 'null'
          description: Severity or risk classification assigned by the review.
        feedbackLocation:
          type: string
          description: Machine-readable indicator of the content medium where the finding was detected (e.g. 'text', 'image_ocr_text').
        location:
          $ref: '#/components/schemas/FindingLocation'
        status:
          type: string
          description: Resolution or approval status associated with the finding.
        approval:
          oneOf:
            - type: string
            - type: 'null'
          description: Approval guidance for trademark-related findings, when applicable.
        metadata:
          oneOf:
            - type: object
            - type: 'null'
          description: Additional model-specific or workflow-specific metadata.
        formattedOutput:
          oneOf:
            - type: string
            - type: 'null'
          description: Richly formatted version of the finding when available.

    FindingLocation:
      description: Location metadata for a finding within a document.
      type: object
      required:
        - pageNumber
      properties:
        pageNumber:
          type: integer

    PolicyFeedbackFinding:
      description: A finding produced by a policy evaluation, such as a brand compliance violation.
      allOf:
        - $ref: '#/components/schemas/FindingBase'
        - type: object
          required:
            - policy
            - details
          properties:
            policy:
              $ref: '#/components/schemas/PolicyRef'
            trademark:
              oneOf:
                - $ref: '#/components/schemas/TrademarkRef'
                - type: 'null'
            details:
              type: object
              description: Policy-specific detail payload.
              properties:
                policyOutputId:
                  oneOf:
                    - type: string
                    - type: 'null'
                  description: Identifier of the policy output that produced this finding.
                recommendation:
                  oneOf:
                    - type: string
                    - type: 'null'
                  description: Actionable recommendation for resolving the finding.
                suggestions:
                  type: array
                  items:
                    type: string
                  description: Suggested alternative text or actions for the finding.

    ClaimFinding:
      description: A finding representing an extracted claim, such as a marketing guarantee or warranty statement.
      allOf:
        - $ref: '#/components/schemas/FindingBase'
        - type: object
          required:
            - details
          properties:
            policy:
              oneOf:
                - $ref: '#/components/schemas/PolicyRef'
                - type: 'null'
            trademark:
              oneOf:
                - $ref: '#/components/schemas/TrademarkRef'
                - type: 'null'
            details:
              type: object
              description: Claim-specific detail payload.
              properties:
                claim:
                  oneOf:
                    - type: string
                    - type: 'null'
                  description: Canonical claim text extracted from the document.
                disclosureText:
                  oneOf:
                    - type: string
                    - type: 'null'
                  description: Recommended disclosure or qualifying text for a claim finding.
                userFixedText:
                  oneOf:
                    - type: string
                    - type: 'null'
                  description: User-provided replacement text for a claim finding.
                approvalLimitations:
                  oneOf:
                    - type: string
                    - type: 'null'
                  description: Scope or limitations tied to an approved claim finding.
                approvalExpireAt:
                  oneOf:
                    - type: string
                      format: date-time
                    - type: 'null'
                  description: Expiration timestamp for an approved claim finding.
                suggestions:
                  type: array
                  items:
                    type: string
                  description: Suggested alternative text or actions for the finding.

    TrademarkInstanceFinding:
      description: A finding representing a potential trademark usage issue detected in the document.
      allOf:
        - $ref: '#/components/schemas/FindingBase'
        - type: object
          required:
            - trademark
            - details
          properties:
            policy:
              oneOf:
                - $ref: '#/components/schemas/PolicyRef'
                - type: 'null'
            trademark:
              $ref: '#/components/schemas/TrademarkRef'
            details:
              type: object
              description: Trademark-specific detail payload.
              properties:
                suggestedFixCasing:
                  type: boolean
                  description: Whether the trademark instance suggests a casing fix.
                recommendedMarkType:
                  type: string
                  description: Recommended mark type for a trademark instance (e.g. 'trademark', 'registered').
                suggestedMarkExplanation:
                  type: string
                  description: Explanation for the recommended mark type.
                suggestedMarkRecord:
                  oneOf:
                    - type: object
                    - type: 'null'
                  description: USPTO record details when a trademark match is found.
                  properties:
                    keyword:
                      type: string
                    registrationNumber:
                      type: string
                    registrationDate:
                      type: string
                    statusLabel:
                      type: string
                    ownerName:
                      type: string
                    logo:
                      type: string
                      format: uri

    RateLimitError:
      description: Returned when the client has exceeded the allowed request rate.
      type: object
      required:
        - error
        - retryAfter
      properties:
        error:
          type: string
          description: Human-readable description of the rate-limit violation.
          example: Rate limit exceeded
        retryAfter:
          type: integer
          description: Number of seconds the client should wait before retrying.
          example: 60

    ReviewDocumentSummary:
      description: Summary metadata about the reviewed source document.
      type: object
      required:
        - title
        - fileType
      properties:
        title:
          type: string
          description: Title associated with the reviewed document.
        fileType:
          type: string
          enum: [TEXT, PDF, WEBPAGE, IMAGE, WEBSITE]
          description: Protege document type classification for the reviewed content.
        externalId:
          oneOf:
            - type: string
            - type: 'null'
          description: Client-provided identifier echoed back in review responses.

    CompletedReviewResponse:
      description: Final response returned when a document review has completed successfully.
      type: object
      required:
        - id
        - status
        - mode
        - documentId
        - documentEvaluationTypeId
        - document
        - findings
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [completed]
        mode:
          $ref: '#/components/schemas/ReviewMode'
        documentId:
          type: string
          format: uuid
        documentEvaluationTypeId:
          type: string
          format: uuid
        document:
          $ref: '#/components/schemas/ReviewDocumentSummary'
        findings:
          type: array
          description: Structured findings produced by the completed review.
          items:
            $ref: '#/components/schemas/Finding'

    PendingReviewResponse:
      description: Review response returned while an asynchronous review is still queued, processing, or has failed.
      type: object
      required:
        - id
        - status
        - mode
        - documentId
        - documentEvaluationTypeId
        - document
        - findings
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [queued, processing, failed]
        mode:
          type: string
          enum: [async]
        documentId:
          type: string
          format: uuid
        documentEvaluationTypeId:
          type: string
          format: uuid
        document:
          $ref: '#/components/schemas/ReviewDocumentSummary'
        findings:
          type: array
          description: Findings accumulated so far. This is typically empty until processing finishes.
          items:
            $ref: '#/components/schemas/Finding'
        error:
          type: string
          description: Failure message when the asynchronous review ends in a `failed` state.

    DocumentReviewSummary:
      description: Summary representation of a review returned by the list endpoint.
      type: object
      required:
        - id
        - status
        - documentId
        - documentEvaluationTypeId
        - document
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
        status:
          $ref: '#/components/schemas/ReviewStatus'
        documentId:
          type: string
          format: uuid
        documentEvaluationTypeId:
          type: string
          format: uuid
        document:
          $ref: '#/components/schemas/ReviewDocumentSummary'
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        error:
          type: string
          description: Failure message for reviews that completed with an error.

    DocumentReviewListResponse:
      description: Paginated collection of reviews visible to the calling API key.
      type: object
      required:
        - documentReviews
        - page
      properties:
        documentReviews:
          type: array
          items:
            $ref: '#/components/schemas/DocumentReviewSummary'
        page:
          $ref: '#/components/schemas/PageMetadata'

    DocumentEvaluationType:
      description: Review configuration that determines which checks, policies, and workflows are applied to a document.
      type: object
      required:
        - id
        - name
        - description
        - useCase
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
        useCase:
          type: string
          enum: [marketing_review, document_qa]
          description: >
            Determines what the evaluation type is optimized for.
            `marketing_review` analyzes documents and web content for compliance
            against brand policies.
            `document_qa` extracts structured content from documents and
            websites for specific queries and document-level grouping.

    DocumentEvaluationTypeListResponse:
      description: Paginated list of document evaluation types available to the API key's tenant.
      type: object
      required:
        - documentEvaluationTypes
        - page
      properties:
        documentEvaluationTypes:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/DocumentEvaluationType'
              - $ref: '#/components/schemas/ExpandedDocumentEvaluationType'
        page:
          $ref: '#/components/schemas/PageMetadata'

    PolicyGroupRef:
      description: Lightweight reference to a policy group.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    PolicyPrePolicyRef:
      description: Reference to a prerequisite or pre-check policy associated with a policy group.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    NestedPolicy:
      description: Policy summary embedded under parent resources such as policy groups.
      type: object
      required:
        - id
        - name
        - description
        - useCase
        - enabled
        - riskLevel
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
        useCase:
          type: string
          enum: [marketing_review, document_qa]
          description: >
            Determines what the evaluation type is optimized for.
            `marketing_review` analyzes documents and web content for compliance
            against brand policies.
            `document_qa` extracts structured content from documents and
            websites for specific queries and document-level grouping.
        enabled:
          type: boolean
          description: Whether the policy is currently active and evaluated.
        riskLevel:
          type: string
          description: Severity or risk classification assigned to this policy.

    Policy:
      description: Full policy record returned by the policies endpoint.
      allOf:
        - $ref: '#/components/schemas/NestedPolicy'
        - type: object
          properties:
            policyGroup:
              oneOf:
                - $ref: '#/components/schemas/PolicyGroupRef'
                - type: 'null'

    PolicyListResponse:
      description: Paginated collection of policies.
      type: object
      required:
        - policies
        - page
      properties:
        policies:
          type: array
          items:
            $ref: '#/components/schemas/Policy'
        page:
          $ref: '#/components/schemas/PageMetadata'

    PolicyGroup:
      description: Grouping of related review policies used to organize evaluation coverage.
      type: object
      required:
        - id
        - name
        - description
        - useCase
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
        useCase:
          type: string
          enum: [marketing_review, document_qa]
          description: >
            Determines what the evaluation type is optimized for.
            `marketing_review` analyzes documents and web content for compliance
            against brand policies.
            `document_qa` extracts structured content from documents and
            websites for specific queries and document-level grouping.
        prePolicy:
          oneOf:
            - $ref: '#/components/schemas/PolicyPrePolicyRef'
            - type: 'null'

    ExpandedPolicyGroup:
      allOf:
        - $ref: '#/components/schemas/PolicyGroup'
        - type: object
          required:
            - policies
          properties:
            policies:
              type: array
              items:
                $ref: '#/components/schemas/NestedPolicy'

    PolicyGroupListResponse:
      description: Paginated collection of policy groups.
      type: object
      required:
        - policyGroups
        - page
      properties:
        policyGroups:
          type: array
          items:
            oneOf:
              - $ref: '#/components/schemas/PolicyGroup'
              - $ref: '#/components/schemas/ExpandedPolicyGroup'
        page:
          $ref: '#/components/schemas/PageMetadata'

    ExpandedDocumentEvaluationType:
      description: Expanded document evaluation type including its policy groups and nested policies.
      allOf:
        - $ref: '#/components/schemas/DocumentEvaluationType'
        - type: object
          required:
            - policyGroups
          properties:
            policyGroups:
              type: array
              items:
                $ref: '#/components/schemas/ExpandedPolicyGroup'

    Brand:
      description: Brand available to the authenticated tenant for filtering scanners and reports.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    BrandListResponse:
      description: Paginated collection of brands.
      type: object
      required:
        - brands
        - page
      properties:
        brands:
          type: array
          items:
            $ref: '#/components/schemas/Brand'
        page:
          $ref: '#/components/schemas/PageMetadata'

    PageMetadata:
      description: Standard offset-based pagination metadata.
      type: object
      required:
        - limit
        - offset
        - count
        - total
      properties:
        limit:
          type: integer
          default: 25
        offset:
          type: integer
          default: 0
        count:
          type: integer
        total:
          type: integer

    ReportBrand:
      description: Lightweight brand reference attached to a scanner report.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    ReportListItem:
      description: Summary representation of a scanner report.
      type: object
      required:
        - id
        - name
        - createdAt
        - documentCount
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        brand:
          oneOf:
            - $ref: '#/components/schemas/ReportBrand'
            - type: 'null'
        documentCount:
          type: integer

    ReportDetailSummary:
      description: Top-level report metadata returned with detailed report responses.
      type: object
      required:
        - id
        - name
        - createdAt
        - documentCount
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        brand:
          oneOf:
            - $ref: '#/components/schemas/ReportBrand'
            - type: 'null'
        documentCount:
          type: integer

    ReportPage:
      description: Page or document captured within a scanner report.
      type: object
      required:
        - documentId
        - title
        - fileType
        - createdAt
      properties:
        documentId:
          type: string
          format: uuid
        title:
          type: string
        link:
          oneOf:
            - type: string
            - type: 'null'
        fileType:
          type: string
        createdAt:
          type: string
          format: date-time
        lastScannedAt:
          oneOf:
            - type: string
              format: date-time
            - type: 'null'

    ReportListResponse:
      description: Paginated collection of scanner reports.
      type: object
      required:
        - reports
        - page
      properties:
        reports:
          type: array
          items:
            $ref: '#/components/schemas/ReportListItem'
        page:
          $ref: '#/components/schemas/PageMetadata'

    ReportDetail:
      description: Report detail including captured pages and page-level metadata.
      allOf:
        - $ref: '#/components/schemas/ReportDetailSummary'
        - type: object
          required:
            - pages
          properties:
            pages:
              type: array
              items:
                $ref: '#/components/schemas/ReportPage'

    ScannerJobBrand:
      description: Brand assigned to a scanner job.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    ScannerJobDocumentEvaluationType:
      description: Review configuration applied to content discovered by the scanner job.
      type: object
      required:
        - id
        - name
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string

    ScannerJobRunSummary:
      description: High-level status for a single execution of a scanner job.
      type: object
      required:
        - id
        - status
        - scheduledTime
        - createdAt
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [CREATED, RUNNING, FINISHED, FAILED]
        scheduledTime:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time

    ScannerJobRun:
      description: Detailed execution metadata for a scanner job run.
      allOf:
        - $ref: '#/components/schemas/ScannerJobRunSummary'
        - type: object
          required:
            - updatedAt
          properties:
            updatedAt:
              type: string
              format: date-time

    ScannerJob:
      description: Scanner job summary returned by list and create operations.
      type: object
      required:
        - id
        - urls
      properties:
        id:
          type: string
          format: uuid
        name:
          oneOf:
            - type: string
            - type: 'null'
        urls:
          type: array
          items:
            type: string
            format: uri
        scheduler:
          oneOf:
            - type: string
            - type: 'null'
        brand:
          oneOf:
            - $ref: '#/components/schemas/ScannerJobBrand'
            - type: 'null'
        documentEvaluationType:
          $ref: '#/components/schemas/ScannerJobDocumentEvaluationType'
        lastRun:
          oneOf:
            - $ref: '#/components/schemas/ScannerJobRunSummary'
            - type: 'null'

    ScannerJobDetail:
      description: Full scanner job configuration, including crawl and archival options.
      allOf:
        - $ref: '#/components/schemas/ScannerJob'
        - type: object
          required:
            - showAllFeedbackInDecisionStore
            - translationEnabled
          properties:
            maxPages:
              oneOf:
                - type: integer
                - type: 'null'
            maxDepth:
              oneOf:
                - type: integer
                - type: 'null'
            maxTrackedPages:
              oneOf:
                - type: integer
                - type: 'null'
            newPagesForSuccessiveScans:
              oneOf:
                - type: integer
                - type: 'null'
            showAllFeedbackInDecisionStore:
              type: boolean
            translationEnabled:
              type: boolean
            useSitemaps:
              oneOf:
                - type: boolean
                - type: 'null'
            archiveMode:
              oneOf:
                - type: string
                  enum: [ON_FOR_ALL, ON_FOR_BRAND_MENTIONED]
                - type: 'null'

    ScannerJobListResponse:
      description: Paginated collection of scanner jobs.
      type: object
      required:
        - scannerJobs
        - page
      properties:
        scannerJobs:
          type: array
          items:
            $ref: '#/components/schemas/ScannerJob'
        page:
          $ref: '#/components/schemas/PageMetadata'

    ScannerJobDetailResponse:
      description: Wrapper containing a single scanner job record.
      type: object
      required:
        - scannerJob
      properties:
        scannerJob:
          $ref: '#/components/schemas/ScannerJobDetail'

    ScannerJobRunsResponse:
      description: Paginated collection of historical runs for a scanner job.
      type: object
      required:
        - scannerRuns
        - page
      properties:
        scannerRuns:
          type: array
          items:
            $ref: '#/components/schemas/ScannerJobRun'
        page:
          $ref: '#/components/schemas/PageMetadata'

    ScannerJobUpdateRequest:
      description: Partial update payload for a scanner job. Include only the fields you want to change.
      type: object
      minProperties: 1
      properties:
        name:
          type: string
        urls:
          type: array
          minItems: 1
          items:
            type: string
            format: uri
        scheduler:
          oneOf:
            - type: string
            - type: 'null'
        documentEvaluationTypeId:
          type: string
          format: uuid
        brandId:
          oneOf:
            - type: string
              format: uuid
            - type: 'null'
        maxPages:
          type: integer
        maxDepth:
          type: integer
        maxTrackedPages:
          type: integer
          minimum: 1
        newPagesForSuccessiveScans:
          type: integer
          minimum: 0
        showAllFeedbackInDecisionStore:
          type: boolean
        translationEnabled:
          type: boolean
        useSitemaps:
          type: boolean
        archiveMode:
          oneOf:
            - type: string
              enum: [ON_FOR_ALL, ON_FOR_BRAND_MENTIONED]
            - type: 'null'

    ScannerJobCreateRequest:
      description: Request body used to create a new scanner job.
      type: object
      required:
        - name
        - documentEvaluationTypeId
        - urls
      properties:
        name:
          type: string
        documentEvaluationTypeId:
          type: string
          format: uuid
        urls:
          type: array
          items:
            type: string
            format: uri
        scheduler:
          type: string
        maxPages:
          type: integer
        maxDepth:
          type: integer
        maxTrackedPages:
          type: integer
          minimum: 1
        newPagesForSuccessiveScans:
          type: integer
          minimum: 0
        brandId:
          oneOf:
            - type: string
              format: uuid
            - type: 'null'
        showAllFeedbackInDecisionStore:
          type: boolean
        translationEnabled:
          type: boolean
        useSitemaps:
          type: boolean
        archiveMode:
          oneOf:
            - type: string
              enum: [ON_FOR_ALL, ON_FOR_BRAND_MENTIONED]
            - type: 'null'

    ScannerJobCreateResponse:
      description: Wrapper returned after a scanner job is created successfully.
      type: object
      required:
        - scannerJob
      properties:
        scannerJob:
          $ref: '#/components/schemas/ScannerJob'

paths:
  /api/v1/brands:
    get:
      summary: List brands
      description: Retrieve brands available to the authenticated tenant. These brand identifiers can be used when creating scanner jobs or filtering report results.
      operationId: listBrands
      tags:
        - Reference Data
      parameters:
        - name: id
          in: query
          description: Filter by a specific brand identifier.
          schema:
            type: string
            format: uuid
        - name: search
          in: query
          description: Case-insensitive search against brand names.
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of records to return.
          schema:
            type: integer
            minimum: 1
        - name: offset
          in: query
          description: Number of records to skip before returning results.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        '200':
          description: Brands returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandListResponse'
              examples:
                default:
                  value:
                    brands:
                      - id: 11111111-1111-1111-1111-111111111111
                        name: Acme
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/policies:
    get:
      summary: List policies
      description: Return policy definitions that may be referenced by review findings or nested under policy groups and document evaluation types.
      operationId: listPolicies
      tags:
        - Reference Data
      parameters:
        - name: id
          in: query
          description: Filter by a specific policy identifier.
          schema:
            type: string
            format: uuid
        - name: policyGroupId
          in: query
          description: Filter to policies that belong to a specific policy group.
          schema:
            type: string
            format: uuid
        - name: search
          in: query
          description: Case-insensitive search against policy names.
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          schema:
            type: integer
            minimum: 1
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sortBy
          in: query
          description: Field used to sort the result set.
          schema:
            type: string
            enum: [name, createdAt, updatedAt]
        - name: sortOrder
          in: query
          description: Sort direction for the selected sort field.
          schema:
            type: string
            enum: [asc, desc]
      responses:
        '200':
          description: Policies returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyListResponse'
              examples:
                default:
                  value:
                    policies:
                      - id: 11111111-1111-1111-1111-111111111111
                        name: No unqualified claims
                        description: Claims must be supported
                        useCase: marketing_review
                        enabled: true
                        riskLevel: high
                        policyGroup:
                          id: 22222222-2222-2222-2222-222222222222
                          name: Claims
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/policy-groups:
    get:
      summary: List policy groups
      description: Return policy groups available to the tenant. Use the `expand=policies` option when clients need the nested policy records in the same response.
      operationId: listPolicyGroups
      tags:
        - Reference Data
      parameters:
        - name: id
          in: query
          schema:
            type: string
            format: uuid
        - name: search
          in: query
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          schema:
            type: integer
            minimum: 1
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sortBy
          in: query
          description: Field used to sort the result set.
          schema:
            type: string
            enum: [name, createdAt]
        - name: sortOrder
          in: query
          description: Sort direction for the selected sort field.
          schema:
            type: string
            enum: [asc, desc]
        - name: expand
          in: query
          description: Expand related resources inline.
          schema:
            type: string
            enum: [policies]
      responses:
        '200':
          description: Policy groups returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PolicyGroupListResponse'
              examples:
                default:
                  value:
                    policyGroups:
                      - id: 22222222-2222-2222-2222-222222222222
                        name: Claims
                        description: Claims rules
                        useCase: marketing_review
                        prePolicy:
                          id: 33333333-3333-3333-3333-333333333333
                          name: Pre-check
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
                expanded:
                  value:
                    policyGroups:
                      - id: 22222222-2222-2222-2222-222222222222
                        name: Claims
                        description: Claims rules
                        useCase: marketing_review
                        prePolicy:
                          id: 33333333-3333-3333-3333-333333333333
                          name: Pre-check
                        policies:
                          - id: 11111111-1111-1111-1111-111111111111
                            name: No unqualified claims
                            description: Claims must be supported
                            useCase: marketing_review
                            enabled: true
                            riskLevel: high
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/document-evaluation-types:
    get:
      summary: List document evaluation types
      description: Return review configurations available to the tenant. These identifiers are required when creating document reviews or scanner jobs.
      operationId: listDocumentEvaluationTypes
      tags:
        - Reference Data
      parameters:
        - name: id
          in: query
          schema:
            type: string
            format: uuid
        - name: search
          in: query
          schema:
            type: string
        - name: useCase
          in: query
          description: Filter evaluation types by business use case.
          schema:
            type: string
            enum: [marketing_review, document_qa]
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          schema:
            type: integer
            minimum: 1
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sortBy
          in: query
          description: Field used to sort the result set.
          schema:
            type: string
            enum: [name, createdAt]
        - name: sortOrder
          in: query
          description: Sort direction for the selected sort field.
          schema:
            type: string
            enum: [asc, desc]
        - name: expand
          in: query
          description: Expand related policy groups inline.
          schema:
            type: string
            enum: [policyGroups]
      responses:
        '200':
          description: Document evaluation types returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentEvaluationTypeListResponse'
              examples:
                default:
                  value:
                    documentEvaluationTypes:
                      - id: 22222222-2222-2222-2222-222222222222
                        name: Marketing Review
                        description: Checks marketing policies
                        useCase: marketing_review
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
                expanded:
                  value:
                    documentEvaluationTypes:
                      - id: 22222222-2222-2222-2222-222222222222
                        name: Marketing Review
                        description: Checks marketing policies
                        useCase: marketing_review
                        policyGroups:
                          - id: 44444444-4444-4444-4444-444444444444
                            name: Claims
                            description: Claims rules
                            useCase: marketing_review
                            prePolicy:
                              id: 33333333-3333-3333-3333-333333333333
                              name: Pre-check
                            policies:
                              - id: 11111111-1111-1111-1111-111111111111
                                name: No unqualified claims
                                description: Claims must be supported
                                useCase: marketing_review
                                enabled: true
                                riskLevel: high
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/scanner-jobs:
    get:
      summary: List scanner jobs
      description: Return the scanner jobs owned by the authenticated tenant, including their most recent run when available.
      operationId: listScannerJobs
      tags:
        - Scanner Jobs
      parameters:
        - name: id
          in: query
          description: Filter by a specific scanner job identifier.
          schema:
            type: string
            format: uuid
        - name: brandId
          in: query
          description: Filter jobs assigned to a specific brand.
          schema:
            type: string
            format: uuid
        - name: search
          in: query
          description: Case-insensitive search against scanner job names.
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          schema:
            type: integer
            minimum: 1
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sortBy
          in: query
          description: Field used to sort the result set.
          schema:
            type: string
            enum: [createdAt, name]
        - name: sortOrder
          in: query
          description: Sort direction for the selected sort field.
          schema:
            type: string
            enum: [asc, desc]
      responses:
        '200':
          description: Scanner jobs returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScannerJobListResponse'
              examples:
                default:
                  value:
                    scannerJobs:
                      - id: 55555555-5555-5555-5555-555555555555
                        name: Acme Site Monitor
                        urls:
                          - https://example.com
                        scheduler: 0 0 * * *
                        brand:
                          id: 11111111-1111-1111-1111-111111111111
                          name: Acme
                        documentEvaluationType:
                          id: 22222222-2222-2222-2222-222222222222
                          name: Marketing Review
                        lastRun:
                          id: 66666666-6666-6666-6666-666666666666
                          status: FINISHED
                          scheduledTime: '2026-05-15T00:00:00.000Z'
                          createdAt: '2026-05-15T00:00:00.000Z'
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
    post:
      summary: Create a content scanner job
      description: Create a new website monitoring job that crawls the provided URLs and evaluates discovered content using the selected document evaluation type. The crawl engine is selected automatically based on the evaluation type's useCase.
      operationId: createScannerJob
      tags:
        - Scanner Jobs
      requestBody:
        required: true
        description: Scanner job configuration, including crawl targets, schedule, and review settings.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScannerJobCreateRequest'
            examples:
              default:
                value:
                  name: Acme Site Monitor
                  documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                  urls:
                    - https://example.com
                  scheduler: 0 0 * * *
                  brandId: 11111111-1111-1111-1111-111111111111
                  maxPages: 10
                  maxDepth: 2
                  maxTrackedPages: 100
                  newPagesForSuccessiveScans: 0
                  showAllFeedbackInDecisionStore: false
                  translationEnabled: false
                  useSitemaps: true
                  archiveMode: null
      responses:
        '201':
          description: Scanner job created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScannerJobCreateResponse'
        '400':
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Related evaluation type or brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/scanner-jobs/{scannerJobId}:
    get:
      summary: Get a scanner job
      description: Retrieve the full configuration and latest run summary for a single scanner job.
      operationId: getScannerJob
      tags:
        - Scanner Jobs
      parameters:
        - name: scannerJobId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Scanner job returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScannerJobDetailResponse'
              examples:
                default:
                  value:
                    scannerJob:
                      id: 55555555-5555-5555-5555-555555555555
                      name: Acme Site Monitor
                      urls:
                        - https://example.com
                      scheduler: 0 0 * * *
                      brand:
                        id: 11111111-1111-1111-1111-111111111111
                        name: Acme
                      documentEvaluationType:
                        id: 22222222-2222-2222-2222-222222222222
                        name: Marketing Review
                      maxPages: 10
                      maxDepth: 2
                      maxTrackedPages: 100
                      newPagesForSuccessiveScans: 0
                      showAllFeedbackInDecisionStore: false
                      translationEnabled: false
                      useSitemaps: true
                      archiveMode: null
                      lastRun:
                        id: 66666666-6666-6666-6666-666666666666
                        status: FINISHED
                        scheduledTime: '2026-05-15T00:00:00.000Z'
                        createdAt: '2026-05-15T00:00:00.000Z'
        '400':
          description: Missing or invalid scanner job id
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Scanner job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
    patch:
      summary: Update a scanner job
      description: Partially update an existing scanner job. Only the fields supplied in the request body are modified.
      operationId: updateScannerJob
      tags:
        - Scanner Jobs
      parameters:
        - name: scannerJobId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        description: Partial scanner job update payload.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScannerJobUpdateRequest'
            examples:
              pauseMonitoring:
                value:
                  scheduler: null
              updateSettings:
                value:
                  scheduler: 0 12 * * *
                  maxPages: 150
                  archiveMode: ON_FOR_ALL
      responses:
        '200':
          description: Scanner job updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScannerJobDetailResponse'
        '400':
          description: Invalid scanner job id or request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Scanner job or related brand/evaluation type not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
    delete:
      summary: Delete a scanner job
      description: Permanently delete a scanner job so it no longer runs or appears in list results.
      operationId: deleteScannerJob
      tags:
        - Scanner Jobs
      parameters:
        - name: scannerJobId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '204':
          description: Scanner job deleted
        '400':
          description: Missing or invalid scanner job id
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Scanner job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/scanner-jobs/{scannerJobId}/runs:
    get:
      summary: List scanner job runs
      description: Return historical executions for a scanner job, ordered by most recent first.
      operationId: listScannerJobRuns
      tags:
        - Scanner Jobs
      parameters:
        - name: scannerJobId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          schema:
            type: integer
            minimum: 1
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        '200':
          description: Scanner job runs returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScannerJobRunsResponse'
              examples:
                default:
                  value:
                    scannerRuns:
                      - id: 66666666-6666-6666-6666-666666666666
                        status: FINISHED
                        scheduledTime: '2026-05-15T00:00:00.000Z'
                        createdAt: '2026-05-15T00:00:00.000Z'
                        updatedAt: '2026-05-15T00:05:00.000Z'
                      - id: 77777777-7777-7777-7777-777777777777
                        status: FAILED
                        scheduledTime: '2026-05-14T00:00:00.000Z'
                        createdAt: '2026-05-14T00:00:00.000Z'
                        updatedAt: '2026-05-14T00:03:00.000Z'
                    page:
                      limit: 25
                      offset: 0
                      count: 2
                      total: 2
        '400':
          description: Missing or invalid scanner job id or query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Scanner job not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/reports:
    get:
      summary: List reports
      description: Return scanner report summaries generated from completed scanner runs. Reports can be filtered by brand or searched by name.
      operationId: listReports
      tags:
        - Reports
      parameters:
        - name: brandId
          in: query
          description: Filter reports for a specific brand.
          schema:
            type: string
            format: uuid
        - name: search
          in: query
          description: Case-insensitive search against report names.
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          schema:
            type: integer
            minimum: 1
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sortBy
          in: query
          description: Field used to sort the result set.
          schema:
            type: string
            enum: [createdAt, name, documentCount]
        - name: sortOrder
          in: query
          description: Sort direction for the selected sort field.
          schema:
            type: string
            enum: [asc, desc]
      responses:
        '200':
          description: Report summaries returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportListResponse'
              examples:
                default:
                  value:
                    reports:
                      - id: 33333333-3333-3333-3333-333333333333
                        name: April Scan
                        createdAt: '2026-05-15T00:00:00.000Z'
                        brand:
                          id: 11111111-1111-1111-1111-111111111111
                          name: Acme
                        documentCount: 42
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/reports/{reportId}:
    get:
      summary: Get a report with scanned pages
      description: Retrieve a report and the scanned pages or captured documents that make up the report payload.
      operationId: getReport
      tags:
        - Reports
      parameters:
        - name: reportId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Report detail returned
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportDetail'
              examples:
                default:
                  value:
                    id: 33333333-3333-3333-3333-333333333333
                    name: April Scan
                    createdAt: '2026-05-15T00:00:00.000Z'
                    brand:
                      id: 11111111-1111-1111-1111-111111111111
                      name: Acme
                    documentCount: 1
                    pages:
                      - documentId: 44444444-4444-4444-4444-444444444444
                        title: Landing Page
                        link: https://example.com/page
                        fileType: WEBPAGE
                        createdAt: '2026-05-15T00:00:00.000Z'
                        lastScannedAt: '2026-05-15T00:00:00.000Z'
        '400':
          description: Missing or invalid report id
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Report not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'

  /api/v1/document-reviews:
    get:
      summary: List document reviews
      description: Return document reviews visible to the authenticated tenant. This endpoint is typically used to poll or reconcile asynchronous reviews in bulk.
      operationId: listDocumentReviews
      tags:
        - Document Reviews
      parameters:
        - name: id
          in: query
          required: false
          description: Filter by a specific review identifier.
          schema:
            type: string
            format: uuid
        - name: documentEvaluationTypeId
          in: query
          required: false
          description: Filter reviews created with a specific document evaluation type.
          schema:
            type: string
            format: uuid
        - name: externalId
          in: query
          required: false
          description: Filter by the client-supplied external document identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Filter reviews by processing status.
          schema:
            $ref: '#/components/schemas/ReviewStatus'
        - name: limit
          in: query
          description: Maximum number of records to return per page.
          required: false
          schema:
            type: integer
            default: 25
        - name: offset
          in: query
          description: Number of records to skip before starting the page.
          required: false
          schema:
            type: integer
            default: 0
        - name: sortBy
          in: query
          description: Field used to sort the result set.
          required: false
          schema:
            type: string
            enum: [createdAt, updatedAt]
            default: createdAt
        - name: sortOrder
          in: query
          description: Sort direction for the selected sort field.
          required: false
          schema:
            type: string
            enum: [asc, desc]
            default: desc
      responses:
        '200':
          description: Document reviews page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DocumentReviewListResponse'
              examples:
                default:
                  value:
                    documentReviews:
                      - id: 88888888-8888-8888-8888-888888888888
                        status: completed
                        documentId: 99999999-9999-9999-9999-999999999999
                        documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                        document:
                          title: MSA draft
                          fileType: TEXT
                          externalId: client-doc-123
                        createdAt: '2026-05-15T00:00:00.000Z'
                        updatedAt: '2026-05-15T00:00:05.000Z'
                    page:
                      limit: 25
                      offset: 0
                      count: 1
                      total: 1
        '400':
          description: Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
        '500':
          description: Failed to list document reviews
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
    post:
      summary: Create a document review
      description: Submit a document for compliance review. Use JSON for plain-text content or multipart form data for file uploads. Synchronous requests return findings inline; asynchronous requests return a queued review that can be polled later.
      operationId: createDocumentReview
      tags:
        - Document Reviews
      requestBody:
        required: true
        description: Review request body supplied as JSON or multipart form data.
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TextReviewRequest'
            examples:
              textSync:
                value:
                  mode: sync
                  documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                  document:
                    type: text
                    title: MSA draft
                    externalId: client-doc-123
                    text: Full review text goes here
                    metadata:
                      sourceSystem: partner-api
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/MultipartFileReviewRequest'
            encoding:
              metadata:
                contentType: text/plain
            examples:
              fileSync:
                summary: Sync file upload review
                value:
                  mode: sync
                  documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                  title: Uploaded MSA draft
                  externalId: client-upload-123
                  metadata: '{"sourceSystem":"partner-api","documentCategory":"msa"}'
                  file: '(binary)'
      responses:
        '200':
          description: Sync review completed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompletedReviewResponse'
              examples:
                default:
                  value:
                    id: 88888888-8888-8888-8888-888888888888
                    status: completed
                    mode: sync
                    documentId: 99999999-9999-9999-9999-999999999999
                    documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                    document:
                      title: MSA draft
                      fileType: TEXT
                      externalId: client-doc-123
                    findings:
                      - kind: policy_feedback
                        text: Guaranteed 20% return
                        comment: This claim appears unqualified and may require substantiation.
                        riskLevel: high
                        feedbackLocation: text
                        location:
                          pageNumber: 1
                        status: flagged
                        approval: null
                        metadata: null
                        formattedOutput: null
                        policy:
                          id: 11111111-1111-1111-1111-111111111111
                          name: No unqualified claims
                        trademark: null
                        details:
                          recommendation: Add supporting disclosure or revise the claim.
        '202':
          description: Async review accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PendingReviewResponse'
              examples:
                default:
                  value:
                    id: 88888888-8888-8888-8888-888888888888
                    status: queued
                    mode: async
                    documentId: 99999999-9999-9999-9999-999999999999
                    documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                    document:
                      title: Uploaded MSA draft
                      fileType: PDF
                      externalId: client-upload-123
                    findings: []
        '400':
          description: Validation or sync-limit error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Document evaluation type not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
        '415':
          description: Unsupported content type
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/v1/document-reviews/{reviewId}:
    get:
      summary: Get document review status or result
      description: Retrieve the latest state of a specific document review. Completed reviews include findings; pending reviews expose queue or processing status.
      operationId: getDocumentReview
      tags:
        - Document Reviews
      parameters:
        - name: reviewId
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Review status or completed result
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/CompletedReviewResponse'
                  - $ref: '#/components/schemas/PendingReviewResponse'
              examples:
                completed:
                  value:
                    id: 88888888-8888-8888-8888-888888888888
                    status: completed
                    mode: sync
                    documentId: 99999999-9999-9999-9999-999999999999
                    documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                    document:
                      title: MSA draft
                      fileType: TEXT
                      externalId: client-doc-123
                    findings: []
                processing:
                  value:
                    id: 88888888-8888-8888-8888-888888888888
                    status: processing
                    mode: async
                    documentId: 99999999-9999-9999-9999-999999999999
                    documentEvaluationTypeId: 22222222-2222-2222-2222-222222222222
                    document:
                      title: Uploaded MSA draft
                      fileType: PDF
                      externalId: client-upload-123
                    findings: []
        '400':
          description: Missing review id
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Review not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
              description: Number of seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RateLimitError'
