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

# Create an Evidence Report

> Validates submitted operational evidence, applies technical rate limiting, checks the authenticated customer's Operational Evidence product entitlement, supports optional idempotent retries, checks the customer's monthly quota, securely retrieves remote image evidence when present, generates a structured operational report, persists the completed report, records usage, and returns the public result.




## OpenAPI

````yaml /openapi/operational-evidence-v1.yaml post /v1/evidence/reports
openapi: 3.1.0
info:
  title: The Wo Operational Evidence API
  version: 1.0.0
  description: >
    Public API contract for transforming operational evidence into structured
    operational reports and exposing customer-scoped usage visibility.
servers:
  - url: https://api.thewo.io
    description: Canonical The Wo production API origin.
security:
  - ApiKeyAuth: []
tags:
  - name: Operational Evidence
    description: Transform submitted operational evidence into structured reports.
  - name: Usage
    description: Read customer-scoped usage and monthly quota information.
paths:
  /v1/evidence/reports:
    post:
      tags:
        - Operational Evidence
      summary: Create an Evidence Report
      description: >
        Validates submitted operational evidence, applies technical rate
        limiting, checks the authenticated customer's Operational Evidence
        product entitlement, supports optional idempotent retries, checks the
        customer's monthly quota, securely retrieves remote image evidence when
        present, generates a structured operational report, persists the
        completed report, records usage, and returns the public result.
      operationId: createEvidenceReport
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          description: >-
            Client-generated identifier for safe retries of the same logical
            Evidence Report creation request. Reusing the same key with a
            different normalized request returns 409.
          schema:
            type: string
            minLength: 1
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEvidenceReportRequest'
            examples:
              textOnly:
                $ref: '#/components/examples/TextOnlyRequest'
              imageOnly:
                $ref: '#/components/examples/ImageOnlyRequest'
              textAndImage:
                $ref: '#/components/examples/TextAndImageRequest'
      responses:
        '201':
          description: Evidence Report created successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateEvidenceReportResponse'
              examples:
                success:
                  $ref: '#/components/examples/SuccessfulReport'
        '400':
          description: >
            The JSON payload does not match the public create Evidence Report
            HTTP contract, or the Idempotency-Key header is invalid.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                invalidPayload:
                  $ref: '#/components/examples/InvalidPayload'
        '401':
          description: >
            The x-api-key header is missing or the provided credential is
            invalid, inactive, or revoked.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                missingApiKey:
                  $ref: '#/components/examples/MissingApiKey'
        '403':
          description: >
            The authenticated customer is not currently entitled to Operational
            Evidence or does not otherwise have valid access to execute the
            billable operation. Inspect error.code to distinguish
            product_not_entitled from quota_access_denied.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                productNotEntitled:
                  $ref: '#/components/examples/ProductNotEntitled'
                quotaAccessDenied:
                  $ref: '#/components/examples/QuotaAccessDenied'
        '409':
          description: >
            The Idempotency-Key was already used for a different normalized
            request, or the same logical request is still being processed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                idempotencyConflict:
                  $ref: '#/components/examples/IdempotencyConflict'
                idempotencyInProgress:
                  $ref: '#/components/examples/IdempotencyInProgress'
        '422':
          description: >
            The HTTP payload passed request validation but the application
            rejected the Evidence Report input, or a submitted remote image
            could not be accepted safely.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                remoteEvidenceImageRejected:
                  $ref: '#/components/examples/RemoteEvidenceImageRejected'
        '429':
          description: >-
            The request exceeded either the configured technical request rate or
            the customer's current commercial operation quota. Inspect
            error.code to distinguish rate_limit_exceeded from quota_exceeded.
          headers:
            Retry-After:
              description: >-
                Number of seconds the client should wait before retrying when
                the response code is rate_limit_exceeded.
              schema:
                type: integer
                minimum: 1
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/RateLimitExceededErrorResponse'
                  - $ref: '#/components/schemas/QuotaExceededErrorResponse'
              examples:
                rateLimitExceeded:
                  $ref: '#/components/examples/RateLimitExceeded'
                quotaExceeded:
                  $ref: '#/components/examples/QuotaExceeded'
        '500':
          description: |
            An unexpected internal error occurred.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                unexpectedError:
                  $ref: '#/components/examples/UnexpectedError'
        '502':
          description: >
            Report generation failed or the provider produced output that could
            not be represented by the public Operational Evidence contract.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                generationFailed:
                  $ref: '#/components/examples/GenerationFailed'
                invalidGeneratedReport:
                  $ref: '#/components/examples/InvalidGeneratedReport'
        '503':
          description: >
            A required service such as API key authentication, rate limiting,
            product entitlement evaluation, idempotency, quota validation,
            secure remote image retrieval, report generation, report
            persistence, usage recording, or idempotent replay restoration is
            temporarily unavailable.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                entitlementCheckUnavailable:
                  $ref: '#/components/examples/EntitlementCheckUnavailable'
                providerUnavailable:
                  $ref: '#/components/examples/ProviderUnavailable'
                rateLimitUnavailable:
                  $ref: '#/components/examples/RateLimitUnavailable'
                remoteEvidenceImageUnavailable:
                  $ref: '#/components/examples/RemoteEvidenceImageUnavailable'
                idempotencyUnavailable:
                  $ref: '#/components/examples/IdempotencyUnavailable'
                idempotencyReplayUnavailable:
                  $ref: '#/components/examples/IdempotencyReplayUnavailable'
      security:
        - ApiKeyAuth: []
components:
  schemas:
    CreateEvidenceReportRequest:
      type: object
      additionalProperties: false
      required:
        - context
        - evidence
      properties:
        context:
          type: string
          description: |
            Operational context used to interpret the submitted evidence.
          enum:
            - property_maintenance
            - delivery_confirmation
            - field_inspection
            - damage_report
            - inventory_check
        language:
          type: string
          minLength: 1
          pattern: .*\S.*
          description: |
            Optional nonblank language guidance for the generated report.
        evidence:
          $ref: '#/components/schemas/EvidenceInput'
    CreateEvidenceReportResponse:
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - result
        - usage
      properties:
        id:
          type: string
          minLength: 1
          description: Evidence Report identifier.
        status:
          type: string
          enum:
            - completed
          description: |
            Public status returned by the current synchronous create operation.
        result:
          $ref: '#/components/schemas/OperationalReportResult'
        usage:
          $ref: '#/components/schemas/EvidenceReportUsage'
    ApiErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
            - requestId
          properties:
            code:
              type: string
              minLength: 1
              description: Stable public error identifier.
            message:
              type: string
              minLength: 1
              description: Human-readable public error message.
            requestId:
              type: string
              minLength: 1
              description: Request correlation identifier.
            details:
              type: object
              description: |
                Optional safe public metadata associated with the error.
              additionalProperties:
                oneOf:
                  - type: string
                  - type: number
                  - type: boolean
                  - type: 'null'
    RateLimitExceededErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
            - requestId
            - details
          properties:
            code:
              type: string
              const: rate_limit_exceeded
            message:
              type: string
              const: Rate limit exceeded. Try again later.
            requestId:
              type: string
              minLength: 1
            details:
              $ref: '#/components/schemas/RateLimitExceededDetails'
    QuotaExceededErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - message
            - requestId
            - details
          properties:
            code:
              type: string
              const: quota_exceeded
            message:
              type: string
              const: Monthly operation quota has been exceeded.
            requestId:
              type: string
              minLength: 1
            details:
              $ref: '#/components/schemas/QuotaExceededDetails'
    EvidenceInput:
      type: object
      additionalProperties: false
      description: >
        Evidence submitted for analysis. At least nonblank text or one image
        must be present.
      properties:
        text:
          type: string
          minLength: 1
          pattern: .*\S.*
          description: Nonblank textual operational evidence.
        images:
          type: array
          description: Image evidence references.
          items:
            $ref: '#/components/schemas/EvidenceImage'
      anyOf:
        - required:
            - text
        - required:
            - images
          properties:
            images:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/EvidenceImage'
    OperationalReportResult:
      type: object
      additionalProperties: false
      required:
        - title
        - description
        - category
        - priority
        - suggestedNextStep
        - tags
        - riskFlags
        - confidence
      properties:
        title:
          type: string
          minLength: 1
          description: Concise operational report title.
        description:
          type: string
          minLength: 1
          description: Structured description derived from the evidence.
        category:
          type: string
          description: Controlled operational category.
          enum:
            - plumbing
            - electrical
            - cleaning
            - security
            - elevator
            - structural
            - appliance
            - other
        priority:
          type: string
          description: Suggested operational urgency.
          enum:
            - low
            - medium
            - high
            - urgent
        suggestedNextStep:
          type:
            - string
            - 'null'
          description: Suggested operational follow-up when available.
        tags:
          type: array
          description: Operational classification or search tags.
          items:
            type: string
        riskFlags:
          type: array
          description: Detected uncertainty or operational risk indicators.
          items:
            type: string
        confidence:
          type: number
          minimum: 0
          maximum: 1
          description: Confidence value between 0 and 1.
    EvidenceReportUsage:
      type: object
      additionalProperties: false
      required:
        - operation
        - units
      properties:
        operation:
          type: string
          enum:
            - evidence_report
          description: Usage operation associated with the report.
        units:
          type: integer
          enum:
            - 1
          description: Units consumed by one successful Evidence Report.
    RateLimitExceededDetails:
      type: object
      additionalProperties: false
      required:
        - limit
        - remaining
        - resetAt
        - retryAfterSeconds
      properties:
        limit:
          type: integer
          minimum: 1
        remaining:
          type: integer
          const: 0
        resetAt:
          type: string
          format: date-time
        retryAfterSeconds:
          type: integer
          minimum: 1
    QuotaExceededDetails:
      type: object
      additionalProperties: false
      required:
        - operation
        - limit
        - used
        - remaining
        - requestedUnits
        - resetAt
      properties:
        operation:
          type: string
          enum:
            - evidence_report
        limit:
          type: integer
          minimum: 0
        used:
          type: integer
          minimum: 0
        remaining:
          type: integer
          minimum: 0
        requestedUnits:
          type: integer
          minimum: 1
        resetAt:
          type: string
          format: date-time
          description: UTC timestamp at which the next quota period begins.
    EvidenceImage:
      type: object
      additionalProperties: false
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          pattern: ^https?://
          minLength: 1
          description: >
            Absolute HTTP or HTTPS URL referencing image evidence. The Wo
            retrieves the remote resource through its secure remote-resource
            boundary before report-provider execution; the original URL is not
            delegated to the provider for an independent fetch.
  examples:
    TextOnlyRequest:
      summary: Property maintenance text evidence
      value:
        context: property_maintenance
        language: en
        evidence:
          text: >-
            Water is collecting under the bathroom sink and the cabinet base is
            wet.
    ImageOnlyRequest:
      summary: Field inspection image evidence
      value:
        context: field_inspection
        language: en
        evidence:
          images:
            - url: https://example.com/evidence/inspection-panel.jpg
    TextAndImageRequest:
      summary: Damage report with text and image evidence
      value:
        context: damage_report
        language: en
        evidence:
          text: A crack appeared beside the entrance door after the impact.
          images:
            - url: https://example.com/evidence/entrance-damage.jpg
    SuccessfulReport:
      summary: Successfully created Evidence Report
      value:
        id: report_01JXYZ123ABC
        status: completed
        result:
          title: Water leak below bathroom sink
          description: >-
            Water accumulation is visible below the bathroom sink and the
            cabinet base appears wet.
          category: plumbing
          priority: high
          suggestedNextStep: >-
            Inspect the sink plumbing and stop the source of the leak before
            further water damage occurs.
          tags:
            - water
            - bathroom
            - sink
          riskFlags:
            - water_damage
          confidence: 0.92
        usage:
          operation: evidence_report
          units: 1
    InvalidPayload:
      summary: Invalid public request payload
      value:
        error:
          code: invalid_request_payload
          message: Request body does not match the create evidence report contract.
          requestId: req_123
    MissingApiKey:
      summary: Missing API key
      value:
        error:
          code: missing_api_key
          message: The x-api-key header is required.
          requestId: req_123
    ProductNotEntitled:
      summary: Operational Evidence product access is not enabled
      value:
        error:
          code: product_not_entitled
          message: The customer is not entitled to create Operational Evidence reports.
          requestId: req_123
    QuotaAccessDenied:
      summary: Billable operation unavailable
      value:
        error:
          code: quota_access_denied
          message: The customer is not allowed to execute this billable operation.
          requestId: req_123
    IdempotencyConflict:
      summary: Idempotency key reused with a different request
      value:
        error:
          code: idempotency_conflict
          message: The idempotency key was already used with a different request.
          requestId: req_123
    IdempotencyInProgress:
      summary: Original idempotent operation is still processing
      value:
        error:
          code: idempotency_in_progress
          message: An operation with this idempotency key is still in progress.
          requestId: req_123
    RemoteEvidenceImageRejected:
      summary: Remote evidence image rejected
      value:
        error:
          code: remote_evidence_image_rejected
          message: One or more remote evidence images could not be accepted safely.
          requestId: req_123
    RateLimitExceeded:
      summary: Technical request rate exceeded
      value:
        error:
          code: rate_limit_exceeded
          message: Rate limit exceeded. Try again later.
          requestId: req_123
          details:
            limit: 60
            remaining: 0
            resetAt: '2030-01-01T00:01:00.000Z'
            retryAfterSeconds: 30
    QuotaExceeded:
      summary: Monthly quota exhausted
      value:
        error:
          code: quota_exceeded
          message: Monthly operation quota has been exceeded.
          requestId: req_123
          details:
            operation: evidence_report
            limit: 500
            used: 500
            remaining: 0
            requestedUnits: 1
            resetAt: '2026-09-01T00:00:00.000Z'
    UnexpectedError:
      summary: Unexpected internal error
      value:
        error:
          code: internal_error
          message: An unexpected error occurred.
          requestId: req_123
    GenerationFailed:
      summary: Operational report generation failed
      value:
        error:
          code: report_generation_failed
          message: Operational report generation failed.
          requestId: req_123
    InvalidGeneratedReport:
      summary: Invalid generated operational report
      value:
        error:
          code: invalid_generated_report
          message: The report provider returned an invalid response.
          requestId: req_123
    EntitlementCheckUnavailable:
      summary: Product entitlement evaluation temporarily unavailable
      value:
        error:
          code: entitlement_check_unavailable
          message: Product entitlement validation is temporarily unavailable.
          requestId: req_123
    ProviderUnavailable:
      summary: Report generation temporarily unavailable
      value:
        error:
          code: report_generation_unavailable
          message: Operational report generation is temporarily unavailable.
          requestId: req_123
    RateLimitUnavailable:
      summary: Rate-limit evaluation temporarily unavailable
      value:
        error:
          code: rate_limit_unavailable
          message: Rate limiting is temporarily unavailable.
          requestId: req_123
    RemoteEvidenceImageUnavailable:
      summary: Remote evidence image temporarily unavailable
      value:
        error:
          code: remote_evidence_image_unavailable
          message: One or more remote evidence images could not be retrieved safely.
          requestId: req_123
    IdempotencyUnavailable:
      summary: Idempotency protection temporarily unavailable
      value:
        error:
          code: idempotency_unavailable
          message: Idempotency protection is temporarily unavailable.
          requestId: req_123
    IdempotencyReplayUnavailable:
      summary: Original idempotent result cannot be restored safely
      value:
        error:
          code: idempotency_replay_unavailable
          message: The original idempotent result could not be restored safely.
          requestId: req_123
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >
        Secret API credential for trusted server-to-server integrations. Never
        expose this value in public frontend or mobile application code.

````