openapi: 3.1.0
info:
  title: AvatarOps API
  version: 1.0.0
  description: >-
    Source-of-truth API contract for AvatarOps foundational resources.
    This contract is additive and implementation-agnostic.
servers:
  - url: https://api.avatarops.ai/v1
    description: Production
  - url: http://localhost:3001/v1
    description: Local development
security:
  - bearerAuth: []
  - apiKeyAuth: []
  - agentTokenAuth: []
tags:
  - name: Organizations
  - name: Workspaces
  - name: Avatars
  - name: AvatarVersions
  - name: Campaigns
  - name: WorkflowRuns
  - name: Assets
  - name: Exports
  - name: Agents
  - name: Approvals
  - name: Planning
  - name: Governance
  - name: Usage
  - name: Billing
  - name: Webhooks
paths:
  /organizations:
    get:
      tags: [Organizations]
      summary: List organizations
      operationId: listOrganizations
      parameters:
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/OrganizationListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Organizations]
      summary: Create organization
      operationId: createOrganization
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrganizationRequest'
      responses:
        '201':
          $ref: '#/components/responses/OrganizationResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /organizations/{organizationId}:
    get:
      tags: [Organizations]
      summary: Get organization
      operationId: getOrganization
      parameters:
        - $ref: '#/components/parameters/OrganizationIdPath'
      responses:
        '200':
          $ref: '#/components/responses/OrganizationResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
    patch:
      tags: [Organizations]
      summary: Update organization
      operationId: updateOrganization
      parameters:
        - $ref: '#/components/parameters/OrganizationIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrganizationRequest'
      responses:
        '200':
          $ref: '#/components/responses/OrganizationResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /workspaces:
    get:
      tags: [Workspaces]
      summary: List workspaces
      operationId: listWorkspaces
      parameters:
        - $ref: '#/components/parameters/OrganizationIdQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/WorkspaceListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Workspaces]
      summary: Create workspace
      operationId: createWorkspace
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWorkspaceRequest'
      responses:
        '201':
          $ref: '#/components/responses/WorkspaceResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /workspaces/{workspaceId}:
    get:
      tags: [Workspaces]
      summary: Get workspace
      operationId: getWorkspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WorkspaceResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
    patch:
      tags: [Workspaces]
      summary: Update workspace
      operationId: updateWorkspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWorkspaceRequest'
      responses:
        '200':
          $ref: '#/components/responses/WorkspaceResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /avatars:
    get:
      tags: [Avatars]
      summary: List avatars
      operationId: listAvatars
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/AvatarListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Avatars]
      summary: Create avatar
      operationId: createAvatar
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAvatarRequest'
      responses:
        '201':
          $ref: '#/components/responses/AvatarResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /avatars/{avatarId}:
    get:
      tags: [Avatars]
      summary: Get avatar
      operationId: getAvatar
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AvatarResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
    patch:
      tags: [Avatars]
      summary: Update avatar
      operationId: updateAvatar
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateAvatarRequest'
      responses:
        '200':
          $ref: '#/components/responses/AvatarResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /avatars/{avatarId}/archive:
    post:
      tags: [Avatars]
      summary: Archive avatar
      operationId: archiveAvatar
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AvatarResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /avatars/{avatarId}/versions:
    get:
      tags: [AvatarVersions]
      summary: List avatar versions
      operationId: listAvatarVersions
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/AvatarVersionListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
    post:
      tags: [AvatarVersions]
      summary: Start avatar version generation
      operationId: createAvatarVersion
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAvatarVersionRequest'
      responses:
        '202':
          $ref: '#/components/responses/AsyncWorkflowResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /avatars/{avatarId}/versions/{versionId}:
    get:
      tags: [AvatarVersions]
      summary: Get avatar version
      operationId: getAvatarVersion
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
        - $ref: '#/components/parameters/VersionIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AvatarVersionResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /avatars/{avatarId}/versions/{versionId}/approve:
    post:
      tags: [AvatarVersions]
      summary: Approve avatar version
      operationId: approveAvatarVersion
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
        - $ref: '#/components/parameters/VersionIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AvatarVersionResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /avatars/{avatarId}/versions/{versionId}/reject:
    post:
      tags: [AvatarVersions]
      summary: Reject avatar version
      operationId: rejectAvatarVersion
      parameters:
        - $ref: '#/components/parameters/AvatarIdPath'
        - $ref: '#/components/parameters/VersionIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RejectAvatarVersionRequest'
      responses:
        '200':
          $ref: '#/components/responses/AvatarVersionResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /campaigns:
    get:
      tags: [Campaigns]
      summary: List campaigns
      operationId: listCampaigns
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/CampaignListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /campaigns/{campaignId}:
    get:
      tags: [Campaigns]
      summary: Get campaign
      operationId: getCampaign
      parameters:
        - $ref: '#/components/parameters/CampaignIdPath'
      responses:
        '200':
          $ref: '#/components/responses/CampaignResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /campaigns/{campaignId}/generate:
    post:
      tags: [Campaigns]
      summary: Start campaign generation workflow
      operationId: generateCampaign
      parameters:
        - $ref: '#/components/parameters/CampaignIdPath'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GenerateCampaignRequest'
      responses:
        '202':
          $ref: '#/components/responses/AsyncWorkflowResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /workflow-runs:
    get:
      tags: [WorkflowRuns]
      summary: List workflow runs
      operationId: listWorkflowRuns
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/AvatarIdQuery'
        - $ref: '#/components/parameters/WorkflowTypeQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/CreatedAfterQuery'
        - $ref: '#/components/parameters/CreatedBeforeQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/WorkflowRunListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /workflow-runs/{runId}:
    get:
      tags: [WorkflowRuns]
      summary: Get workflow run
      operationId: getWorkflowRun
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WorkflowRunResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /workflow-runs/{runId}/steps:
    get:
      tags: [WorkflowRuns]
      summary: List workflow steps
      operationId: listWorkflowRunSteps
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WorkflowStepListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /workflow-runs/{runId}/events:
    get:
      tags: [WorkflowRuns]
      summary: List workflow events
      operationId: listWorkflowRunEvents
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
      responses:
        '200':
          $ref: '#/components/responses/WorkflowEventListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /workflow-runs/{runId}/signal:
    post:
      tags: [WorkflowRuns]
      summary: Send signal to workflow run
      operationId: signalWorkflowRun
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignalWorkflowRequest'
      responses:
        '202':
          $ref: '#/components/responses/AsyncWorkflowResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /workflow-runs/{runId}/steps/{stepId}/retry:
    post:
      tags: [WorkflowRuns]
      summary: Retry workflow step
      operationId: retryWorkflowRunStep
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
        - $ref: '#/components/parameters/StepIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowStepControlRequest'
      responses:
        '202':
          $ref: '#/components/responses/WorkflowStepControlResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/ValidationError'

  /workflow-runs/{runId}/steps/{stepId}/approve:
    post:
      tags: [WorkflowRuns]
      summary: Approve workflow step
      operationId: approveWorkflowRunStep
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
        - $ref: '#/components/parameters/StepIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowStepControlRequest'
      responses:
        '202':
          $ref: '#/components/responses/WorkflowStepControlResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/ValidationError'

  /workflow-runs/{runId}/steps/{stepId}/reject:
    post:
      tags: [WorkflowRuns]
      summary: Reject workflow step
      operationId: rejectWorkflowRunStep
      parameters:
        - $ref: '#/components/parameters/RunIdPath'
        - $ref: '#/components/parameters/StepIdPath'
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowStepControlRequest'
      responses:
        '202':
          $ref: '#/components/responses/WorkflowStepControlResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/ValidationError'

  /assets:
    get:
      tags: [Assets]
      summary: List immutable assets
      operationId: listAssets
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/AvatarIdQuery'
        - $ref: '#/components/parameters/RunIdQuery'
        - $ref: '#/components/parameters/AssetTypeQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/AssetListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /assets/{assetId}:
    get:
      tags: [Assets]
      summary: Get immutable asset metadata
      operationId: getAsset
      parameters:
        - $ref: '#/components/parameters/AssetIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AssetResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /assets/presign-upload:
    post:
      tags: [Assets]
      summary: Create presigned upload URL
      operationId: presignAssetUpload
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PresignUploadRequest'
      responses:
        '200':
          $ref: '#/components/responses/PresignUploadResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /assets/{assetId}/lineage:
    get:
      tags: [Assets]
      summary: Get asset lineage graph for immutable derivatives
      operationId: getAssetLineage
      parameters:
        - $ref: '#/components/parameters/AssetIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AssetLineageResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /assets/{assetId}/scores:
    get:
      tags: [Assets]
      summary: Get quality and moderation scores
      operationId: getAssetScores
      parameters:
        - $ref: '#/components/parameters/AssetIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AssetScoresResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /assets/{assetId}/tags:
    post:
      tags: [Assets]
      summary: Add tags to an asset
      operationId: addAssetTags
      parameters:
        - $ref: '#/components/parameters/AssetIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AddAssetTagsRequest'
      responses:
        '200':
          $ref: '#/components/responses/AssetResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /export-presets:
    get:
      tags: [Exports]
      summary: List export presets for a workspace
      operationId: listExportPresets
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/ExportPresetListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Exports]
      summary: Create export preset
      operationId: createExportPreset
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateExportPresetRequest'
      responses:
        '201':
          $ref: '#/components/responses/ExportPresetResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /exports:
    get:
      tags: [Exports]
      summary: List export requests
      operationId: listExports
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/ExportListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Exports]
      summary: Start export workflow
      operationId: createExport
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateExportRequest'
      responses:
        '202':
          $ref: '#/components/responses/AsyncWorkflowResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /exports/{exportId}:
    get:
      tags: [Exports]
      summary: Get export request
      operationId: getExport
      parameters:
        - $ref: '#/components/parameters/ExportIdPath'
      responses:
        '200':
          $ref: '#/components/responses/ExportResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /agents:
    get:
      tags: [Agents]
      summary: List agent principals
      operationId: listAgents
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/AgentListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Agents]
      summary: Create agent principal
      operationId: createAgent
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentRequest'
      responses:
        '201':
          $ref: '#/components/responses/AgentResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /agents/{agentId}:
    get:
      tags: [Agents]
      summary: Get agent principal
      operationId: getAgent
      parameters:
        - $ref: '#/components/parameters/AgentIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AgentResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /agents/{agentId}/tokens:
    post:
      tags: [Agents]
      summary: Create agent token
      operationId: createAgentToken
      parameters:
        - $ref: '#/components/parameters/AgentIdPath'
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAgentTokenRequest'
      responses:
        '201':
          $ref: '#/components/responses/AgentTokenResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/IdempotencyConflict'

  /agents/{agentId}/tokens/{tokenId}:
    delete:
      tags: [Agents]
      summary: Revoke agent token
      operationId: revokeAgentToken
      parameters:
        - $ref: '#/components/parameters/AgentIdPath'
        - $ref: '#/components/parameters/TokenIdPath'
      responses:
        '204':
          description: Token revoked.
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /approvals:
    get:
      tags: [Approvals]
      summary: List approval requests
      operationId: listApprovals
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/ApprovalListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /approvals/{approvalId}:
    get:
      tags: [Approvals]
      summary: Get approval request
      operationId: getApproval
      parameters:
        - $ref: '#/components/parameters/ApprovalIdPath'
      responses:
        '200':
          $ref: '#/components/responses/ApprovalResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /approvals/{approvalId}/decision:
    post:
      tags: [Approvals]
      summary: Submit approval decision
      operationId: submitApprovalDecision
      parameters:
        - $ref: '#/components/parameters/ApprovalIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApprovalDecisionRequest'
      responses:
        '200':
          $ref: '#/components/responses/ApprovalDecisionResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /planning/preview:
    post:
      tags: [Planning]
      summary: Generate a structured planning preview
      operationId: previewPlanning
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanningPreviewRequest'
      responses:
        '200':
          $ref: '#/components/responses/PlanningPreviewResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /spend-limits:
    get:
      tags: [Governance]
      summary: List spend limits by governance scope
      operationId: listSpendLimits
      parameters:
        - $ref: '#/components/parameters/OrganizationIdQuery'
        - $ref: '#/components/parameters/WorkspaceIdOptionalQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/AgentPrincipalIdQuery'
      responses:
        '200':
          $ref: '#/components/responses/SpendLimitListResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Governance]
      summary: Create spend limit
      operationId: createSpendLimit
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSpendLimitRequest'
      responses:
        '201':
          $ref: '#/components/responses/SpendLimitResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /spend-limits/{spendLimitId}:
    patch:
      tags: [Governance]
      summary: Update spend limit
      operationId: updateSpendLimit
      parameters:
        - $ref: '#/components/parameters/SpendLimitIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateSpendLimitRequest'
      responses:
        '200':
          $ref: '#/components/responses/SpendLimitResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /policy-packs:
    get:
      tags: [Governance]
      summary: List policy packs by scope
      operationId: listPolicyPacks
      parameters:
        - $ref: '#/components/parameters/OrganizationIdQuery'
        - $ref: '#/components/parameters/WorkspaceIdOptionalQuery'
        - in: query
          name: status
          schema:
            type: string
            enum: [active, archived]
      responses:
        '200':
          $ref: '#/components/responses/PolicyPackListResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Governance]
      summary: Create policy pack
      operationId: createPolicyPack
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePolicyPackRequest'
      responses:
        '201':
          $ref: '#/components/responses/PolicyPackResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /policy-packs/{policyPackId}:
    patch:
      tags: [Governance]
      summary: Update policy pack
      operationId: updatePolicyPack
      parameters:
        - $ref: '#/components/parameters/PolicyPackIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdatePolicyPackRequest'
      responses:
        '200':
          $ref: '#/components/responses/PolicyPackResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /policy-packs/{policyPackId}/bindings:
    get:
      tags: [Governance]
      summary: List bindings for a policy pack
      operationId: listPolicyBindings
      parameters:
        - $ref: '#/components/parameters/PolicyPackIdPath'
        - in: query
          name: bindingScope
          schema:
            type: string
            enum: [organization, workspace, campaign, agent]
      responses:
        '200':
          $ref: '#/components/responses/PolicyBindingListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /policy-packs/{policyPackId}/bind:
    post:
      tags: [Governance]
      summary: Bind policy pack to a scope
      operationId: bindPolicyPack
      parameters:
        - $ref: '#/components/parameters/PolicyPackIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePolicyBindingRequest'
      responses:
        '201':
          $ref: '#/components/responses/PolicyBindingResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /policy/effective:
    get:
      tags: [Governance]
      summary: Resolve effective policy for a context
      operationId: getEffectivePolicy
      parameters:
        - $ref: '#/components/parameters/OrganizationIdQuery'
        - $ref: '#/components/parameters/WorkspaceIdOptionalQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/AgentPrincipalIdQuery'
      responses:
        '200':
          $ref: '#/components/responses/EffectivePolicyResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /audit-logs:
    get:
      tags: [Governance]
      summary: List audit logs
      operationId: listAuditLogs
      parameters:
        - in: query
          name: workspaceId
          schema:
            $ref: '#/components/schemas/Id'
        - $ref: '#/components/parameters/OrganizationIdQuery'
        - $ref: '#/components/parameters/ActorTypeQuery'
        - $ref: '#/components/parameters/ActionQuery'
        - $ref: '#/components/parameters/ResourceTypeQuery'
        - $ref: '#/components/parameters/CreatedAfterQuery'
        - $ref: '#/components/parameters/CreatedBeforeQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/AuditLogListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /audit-logs/{auditLogId}:
    get:
      tags: [Governance]
      summary: Get audit log
      operationId: getAuditLog
      parameters:
        - $ref: '#/components/parameters/AuditLogIdPath'
      responses:
        '200':
          $ref: '#/components/responses/AuditLogResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /usage-events:
    get:
      tags: [Usage]
      summary: List usage events
      operationId: listUsageEvents
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/AvatarIdQuery'
        - $ref: '#/components/parameters/RunIdQuery'
        - $ref: '#/components/parameters/ProviderQuery'
        - $ref: '#/components/parameters/UsageTypeQuery'
        - $ref: '#/components/parameters/CreatedAfterQuery'
        - $ref: '#/components/parameters/CreatedBeforeQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/UsageEventListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /billing-events:
    get:
      tags: [Billing]
      summary: List billing events
      operationId: listBillingEvents
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/CampaignIdQuery'
        - $ref: '#/components/parameters/AvatarIdQuery'
        - $ref: '#/components/parameters/ProviderQuery'
        - $ref: '#/components/parameters/UsageTypeQuery'
        - $ref: '#/components/parameters/CreatedAfterQuery'
        - $ref: '#/components/parameters/CreatedBeforeQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/BillingEventListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /spend-summary:
    get:
      tags: [Billing]
      summary: Get workspace spend summary
      operationId: getSpendSummary
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/BillingPeriodQuery'
      responses:
        '200':
          $ref: '#/components/responses/SpendSummaryResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /webhooks:
    get:
      tags: [Webhooks]
      summary: List webhooks
      operationId: listWebhooks
      parameters:
        - $ref: '#/components/parameters/WorkspaceIdQuery'
        - $ref: '#/components/parameters/StatusQuery'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/WebhookListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
    post:
      tags: [Webhooks]
      summary: Create webhook endpoint
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookRequest'
      responses:
        '201':
          $ref: '#/components/responses/WebhookResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'

  /webhooks/{webhookId}:
    patch:
      tags: [Webhooks]
      summary: Update webhook endpoint
      operationId: updateWebhook
      parameters:
        - $ref: '#/components/parameters/WebhookIdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateWebhookRequest'
      responses:
        '200':
          $ref: '#/components/responses/WebhookResponse'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

  /webhooks/{webhookId}/deliveries:
    get:
      tags: [Webhooks]
      summary: List webhook deliveries
      operationId: listWebhookDeliveries
      parameters:
        - $ref: '#/components/parameters/WebhookIdPath'
        - $ref: '#/components/parameters/LimitQuery'
        - $ref: '#/components/parameters/CursorQuery'
      responses:
        '200':
          $ref: '#/components/responses/WebhookDeliveryListResponse'
        '401':
          $ref: '#/components/responses/AuthenticationRequired'
        '403':
          $ref: '#/components/responses/PermissionDenied'
        '404':
          $ref: '#/components/responses/ResourceNotFound'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
    agentTokenAuth:
      type: apiKey
      in: header
      name: X-Agent-Token

  parameters:
    OrganizationIdPath:
      in: path
      name: organizationId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    WorkspaceIdPath:
      in: path
      name: workspaceId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    AvatarIdPath:
      in: path
      name: avatarId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    VersionIdPath:
      in: path
      name: versionId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    CampaignIdPath:
      in: path
      name: campaignId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    RunIdPath:
      in: path
      name: runId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    StepIdPath:
      in: path
      name: stepId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    AssetIdPath:
      in: path
      name: assetId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    ExportIdPath:
      in: path
      name: exportId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    AgentIdPath:
      in: path
      name: agentId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    TokenIdPath:
      in: path
      name: tokenId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    ApprovalIdPath:
      in: path
      name: approvalId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    WebhookIdPath:
      in: path
      name: webhookId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    AuditLogIdPath:
      in: path
      name: auditLogId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    SpendLimitIdPath:
      in: path
      name: spendLimitId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    PolicyPackIdPath:
      in: path
      name: policyPackId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    OrganizationIdQuery:
      in: query
      name: organizationId
      schema:
        $ref: '#/components/schemas/Id'
    WorkspaceIdOptionalQuery:
      in: query
      name: workspaceId
      schema:
        $ref: '#/components/schemas/Id'
    WorkspaceIdQuery:
      in: query
      name: workspaceId
      required: true
      schema:
        $ref: '#/components/schemas/Id'
    CampaignIdQuery:
      in: query
      name: campaignId
      schema:
        $ref: '#/components/schemas/Id'
    AvatarIdQuery:
      in: query
      name: avatarId
      schema:
        $ref: '#/components/schemas/Id'
    AgentPrincipalIdQuery:
      in: query
      name: agentPrincipalId
      schema:
        $ref: '#/components/schemas/Id'
    RunIdQuery:
      in: query
      name: workflowRunId
      schema:
        $ref: '#/components/schemas/Id'
    WorkflowTypeQuery:
      in: query
      name: workflowType
      schema:
        type: string
    StatusQuery:
      in: query
      name: status
      schema:
        type: string
    ActorTypeQuery:
      in: query
      name: actorType
      schema:
        type: string
        enum: [user, agent, system]
    ActionQuery:
      in: query
      name: action
      schema:
        type: string
    ResourceTypeQuery:
      in: query
      name: resourceType
      schema:
        type: string
    AssetTypeQuery:
      in: query
      name: assetType
      schema:
        type: string
    ProviderQuery:
      in: query
      name: provider
      schema:
        type: string
    UsageTypeQuery:
      in: query
      name: usageType
      schema:
        type: string
    CreatedAfterQuery:
      in: query
      name: createdAfter
      schema:
        type: string
        format: date-time
    CreatedBeforeQuery:
      in: query
      name: createdBefore
      schema:
        type: string
        format: date-time
    BillingPeriodQuery:
      in: query
      name: period
      schema:
        type: string
        example: '2026-03'
    LimitQuery:
      in: query
      name: limit
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
    CursorQuery:
      in: query
      name: cursor
      schema:
        type: string
    IdempotencyKeyHeader:
      in: header
      name: Idempotency-Key
      required: true
      schema:
        type: string

  responses:
    ValidationError:
      description: Request validation failed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    AuthenticationRequired:
      description: Authentication credentials are missing or invalid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    PermissionDenied:
      description: Caller lacks permission for the requested scope or resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    ResourceNotFound:
      description: Requested resource was not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    IdempotencyConflict:
      description: Idempotency key was reused with a conflicting request payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    WorkflowAlreadyRunning:
      description: Similar workflow is already in progress.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'

    OrganizationResponse:
      description: Organization payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/OrganizationSingleResponse'
    OrganizationListResponse:
      description: Organization list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/OrganizationListResponse'

    WorkspaceResponse:
      description: Workspace payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkspaceSingleResponse'
    WorkspaceListResponse:
      description: Workspace list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkspaceListResponse'

    AvatarResponse:
      description: Avatar payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AvatarSingleResponse'
    AvatarListResponse:
      description: Avatar list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AvatarListResponse'

    AvatarVersionResponse:
      description: Avatar version payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AvatarVersionSingleResponse'
    AvatarVersionListResponse:
      description: Avatar version list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AvatarVersionListResponse'

    CampaignResponse:
      description: Campaign payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CampaignSingleResponse'
    CampaignListResponse:
      description: Campaign list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/CampaignListResponse'

    WorkflowRunResponse:
      description: Workflow run payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkflowRunSingleResponse'
    WorkflowRunListResponse:
      description: Workflow run list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkflowRunListResponse'
    WorkflowStepListResponse:
      description: Workflow step list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkflowStepListResponse'
    WorkflowEventListResponse:
      description: Workflow event list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkflowEventListResponse'
    WorkflowStepControlResponse:
      description: Workflow step control payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WorkflowStepControlSingleResponse'

    AssetResponse:
      description: Asset payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AssetSingleResponse'
    AssetListResponse:
      description: Asset list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AssetListResponse'
    AssetLineageResponse:
      description: Asset lineage payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AssetLineageResponse'
    AssetScoresResponse:
      description: Asset score payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AssetScoresResponse'
    PresignUploadResponse:
      description: Presigned upload payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PresignUploadResponse'

    ExportResponse:
      description: Export payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExportSingleResponse'
    ExportListResponse:
      description: Export list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExportListResponse'
    ExportPresetResponse:
      description: Export preset payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExportPresetSingleResponse'
    ExportPresetListResponse:
      description: Export preset list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExportPresetListResponse'

    AgentResponse:
      description: Agent payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AgentSingleResponse'
    AgentListResponse:
      description: Agent list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AgentListResponse'
    AgentTokenResponse:
      description: Agent token creation payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AgentTokenSingleResponse'

    ApprovalResponse:
      description: Approval payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApprovalSingleResponse'
    ApprovalListResponse:
      description: Approval list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApprovalListResponse'
    ApprovalDecisionResponse:
      description: Approval decision payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApprovalDecisionSingleResponse'

    PlanningPreviewResponse:
      description: Planner preview payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PlanningPreviewSingleResponse'

    SpendLimitResponse:
      description: Spend limit payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SpendLimitSingleResponse'
    SpendLimitListResponse:
      description: Spend limit list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SpendLimitListResponse'
    PolicyPackResponse:
      description: Policy pack payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PolicyPackSingleResponse'
    PolicyPackListResponse:
      description: Policy pack list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PolicyPackListResponse'
    PolicyBindingResponse:
      description: Policy binding payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PolicyBindingSingleResponse'
    PolicyBindingListResponse:
      description: Policy binding list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PolicyBindingListResponse'
    EffectivePolicyResponse:
      description: Effective policy payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EffectivePolicySingleResponse'

    AuditLogResponse:
      description: Audit log payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AuditLogSingleResponse'
    AuditLogListResponse:
      description: Audit log list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AuditLogListResponse'

    UsageEventListResponse:
      description: Usage event list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UsageEventListResponse'
    BillingEventListResponse:
      description: Billing event list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/BillingEventListResponse'
    SpendSummaryResponse:
      description: Spend summary payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/SpendSummarySingleResponse'

    WebhookResponse:
      description: Webhook payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WebhookSingleResponse'
    WebhookListResponse:
      description: Webhook list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WebhookListResponse'
    WebhookDeliveryListResponse:
      description: Webhook delivery list payload.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WebhookDeliveryListResponse'

    AsyncWorkflowResponse:
      description: Accepted asynchronous operation with workflow linkage.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AsyncWorkflowSingleResponse'

  schemas:
    Id:
      type: string
      minLength: 1
    Timestamp:
      type: string
      format: date-time

    PageInfo:
      type: object
      required: [next_cursor, has_more]
      properties:
        next_cursor:
          type: string
          nullable: true
        has_more:
          type: boolean

    ErrorCode:
      type: string
      enum:
        - authentication_required
        - permission_denied
        - resource_not_found
        - validation_error
        - idempotency_conflict
        - budget_limit_exceeded
        - policy_violation
        - approval_required
        - workflow_already_running
        - provider_unavailable
        - rate_limited
        - moderation_blocked
        - asset_not_ready

    ErrorEnvelope:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message, request_id, details]
          properties:
            code:
              $ref: '#/components/schemas/ErrorCode'
            message:
              type: string
            request_id:
              type: string
            details:
              type: object
              additionalProperties: true

    Organization:
      type: object
      required: [id, slug, name, status, created_at, updated_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        slug: { type: string }
        name: { type: string }
        status: { type: string }
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    Workspace:
      type: object
      required: [id, organization_id, slug, name, status, created_at, updated_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        organization_id: { $ref: '#/components/schemas/Id' }
        slug: { type: string }
        name: { type: string }
        description: { type: string, nullable: true }
        status: { type: string }
        region: { type: string, nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    Avatar:
      type: object
      required:
        - id
        - workspace_id
        - slug
        - name
        - avatar_type
        - lifecycle_state
        - created_at
        - updated_at
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        slug: { type: string }
        name: { type: string }
        avatar_type: { type: string }
        description: { type: string, nullable: true }
        lifecycle_state: { type: string }
        current_version_id: { $ref: '#/components/schemas/Id', nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    AvatarVersion:
      type: object
      required: [id, avatar_id, version_number, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        avatar_id: { $ref: '#/components/schemas/Id' }
        version_number: { type: integer }
        status: { type: string }
        approved_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    Campaign:
      type: object
      required: [id, workspace_id, slug, name, status, created_at, updated_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        slug: { type: string }
        name: { type: string }
        objective: { type: string, nullable: true }
        status: { type: string }
        avatar_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    WorkflowRun:
      type: object
      required: [id, workspace_id, workflow_type, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id', nullable: true }
        avatar_id: { $ref: '#/components/schemas/Id', nullable: true }
        workflow_type: { type: string }
        status: { type: string }
        started_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        ended_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    WorkflowStep:
      type: object
      required: [id, workflow_run_id, step_key, status, attempt_count]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workflow_run_id: { $ref: '#/components/schemas/Id' }
        step_key: { type: string }
        status: { type: string }
        attempt_count: { type: integer }
        started_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        ended_at: { $ref: '#/components/schemas/Timestamp', nullable: true }

    WorkflowEvent:
      type: object
      required: [id, workflow_run_id, event_type, payload_json, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workflow_run_id: { $ref: '#/components/schemas/Id' }
        event_type: { type: string }
        payload_json:
          type: object
          additionalProperties: true
        created_at: { $ref: '#/components/schemas/Timestamp' }

    Asset:
      type: object
      required:
        - id
        - workspace_id
        - asset_type
        - storage_bucket
        - storage_key
        - created_at
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id', nullable: true }
        avatar_id: { $ref: '#/components/schemas/Id', nullable: true }
        workflow_run_id: { $ref: '#/components/schemas/Id', nullable: true }
        asset_type: { type: string }
        storage_bucket: { type: string }
        storage_key: { type: string }
        mime_type: { type: string, nullable: true }
        width: { type: integer, nullable: true }
        height: { type: integer, nullable: true }
        duration_ms: { type: integer, nullable: true }
        provider: { type: string, nullable: true }
        provider_model: { type: string, nullable: true }
        tags:
          type: array
          items: { type: string }
        transcripts:
          type: array
          items:
            type: object
            properties:
              id: { $ref: '#/components/schemas/Id' }
              asset_id: { $ref: '#/components/schemas/Id' }
              transcript_text: { type: string }
              locale: { type: string, nullable: true }
              created_at: { $ref: '#/components/schemas/Timestamp' }
        captions:
          type: array
          items:
            type: object
            properties:
              id: { $ref: '#/components/schemas/Id' }
              asset_id: { $ref: '#/components/schemas/Id' }
              caption_format: { type: string }
              content_text: { type: string }
              locale: { type: string, nullable: true }
              created_at: { $ref: '#/components/schemas/Timestamp' }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    AssetLineage:
      type: object
      required: [child_asset_id, relation_type]
      properties:
        child_asset_id: { $ref: '#/components/schemas/Id' }
        parent_asset_id: { $ref: '#/components/schemas/Id', nullable: true }
        relation_type: { type: string }
        workflow_run_id: { $ref: '#/components/schemas/Id', nullable: true }

    AssetScore:
      type: object
      required: [score_type]
      properties:
        score_type: { type: string }
        score: { type: number, nullable: true }
        passed: { type: boolean, nullable: true }

    Export:
      type: object
      required: [id, workspace_id, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id', nullable: true }
        preset_id: { $ref: '#/components/schemas/Id', nullable: true }
        requested_by: { $ref: '#/components/schemas/Id', nullable: true }
        status: { type: string }
        workflow_run_id: { $ref: '#/components/schemas/Id', nullable: true }
        export_bundle_id: { $ref: '#/components/schemas/Id', nullable: true }
        bundle_status: { type: string, nullable: true }
        bundle:
          allOf:
            - $ref: '#/components/schemas/ExportBundle'
          nullable: true
        bundle_items:
          type: array
          items:
            $ref: '#/components/schemas/ExportBundleItem'
        created_at: { $ref: '#/components/schemas/Timestamp' }

    ExportPreset:
      type: object
      required: [id, name, preset_key, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id', nullable: true }
        name: { type: string }
        preset_key: { type: string }
        settings_json:
          type: object
          additionalProperties: true
        created_at: { $ref: '#/components/schemas/Timestamp' }

    ExportBundle:
      type: object
      required: [id, export_request_id, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        export_request_id: { $ref: '#/components/schemas/Id' }
        bundle_asset_id: { $ref: '#/components/schemas/Id', nullable: true }
        manifest_asset_id: { $ref: '#/components/schemas/Id', nullable: true }
        status: { type: string }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    ExportBundleItem:
      type: object
      required: [id, export_bundle_id, asset_id, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        export_bundle_id: { $ref: '#/components/schemas/Id' }
        asset_id: { $ref: '#/components/schemas/Id' }
        role: { type: string, nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    AgentPrincipal:
      type: object
      required: [id, workspace_id, name, principal_type, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        name: { type: string }
        description: { type: string, nullable: true }
        principal_type: { type: string }
        status: { type: string }
        last_used_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        tokens:
          type: array
          items:
            $ref: '#/components/schemas/AgentTokenMetadata'
        created_at: { $ref: '#/components/schemas/Timestamp' }

    AgentTokenMetadata:
      type: object
      required: [id, agent_principal_id, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        agent_principal_id: { $ref: '#/components/schemas/Id' }
        status:
          type: string
          enum: [active, revoked, expired]
        expires_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        last_used_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    AgentToken:
      type: object
      required: [id, agent_id, token, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        agent_id: { $ref: '#/components/schemas/Id' }
        token:
          type: string
          description: Returned only at token creation time.
        status:
          type: string
          enum: [active, revoked, expired]
        expires_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        last_used_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    ApprovalRequest:
      type: object
      required: [id, workspace_id, resource_type, resource_id, requested_by, status, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        resource_type: { type: string }
        resource_id: { $ref: '#/components/schemas/Id' }
        requested_by: { $ref: '#/components/schemas/Id', nullable: true }
        status:
          type: string
          enum: [pending, approved, rejected, expired]
        reason: { type: string, nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    ApprovalDecision:
      type: object
      required: [approval_id, decision, created_at]
      properties:
        approval_id: { $ref: '#/components/schemas/Id' }
        decision:
          type: string
          enum: [approved, rejected]
        notes: { type: string, nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    PlanningPreview:
      type: object
      required: [plan_type, mode, final_mode_fallback, workspace_id, explanation, plan]
      properties:
        plan_type:
          type: string
          enum: [avatar, campaign]
        mode:
          type: string
          enum: [draft, final]
        final_mode_fallback:
          type: boolean
        workspace_id:
          $ref: '#/components/schemas/Id'
        avatar_id:
          $ref: '#/components/schemas/Id'
          nullable: true
        campaign_id:
          $ref: '#/components/schemas/Id'
          nullable: true
        explanation:
          type: string
        plan:
          type: object
          additionalProperties: true

    PolicyRuleSet:
      type: object
      additionalProperties: false
      properties:
        allowed_providers:
          type: array
          items: { type: string }
        denied_providers:
          type: array
          items: { type: string }
        max_image_resolution:
          type: object
          required: [width, height]
          properties:
            width: { type: integer, minimum: 1 }
            height: { type: integer, minimum: 1 }
        max_video_duration_ms:
          type: integer
          minimum: 1
        allow_draft_generation:
          type: boolean
        allow_final_generation:
          type: boolean
        moderation_threshold:
          type: number

    SpendLimit:
      type: object
      required: [id, limit_cents, enforcement_mode, created_at, updated_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        organization_id: { $ref: '#/components/schemas/Id', nullable: true }
        workspace_id: { $ref: '#/components/schemas/Id', nullable: true }
        campaign_id: { $ref: '#/components/schemas/Id', nullable: true }
        agent_principal_id: { $ref: '#/components/schemas/Id', nullable: true }
        limit_cents: { type: integer, minimum: 1 }
        enforcement_mode:
          type: string
          enum: [hard, soft]
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    PolicyPack:
      type: object
      required: [id, name, version, status, rules_json, created_at, updated_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        organization_id: { $ref: '#/components/schemas/Id', nullable: true }
        workspace_id: { $ref: '#/components/schemas/Id', nullable: true }
        name: { type: string }
        version: { type: string }
        status:
          type: string
          enum: [active, archived]
        rules_json:
          $ref: '#/components/schemas/PolicyRuleSet'
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    PolicyBinding:
      type: object
      required: [id, policy_pack_id, binding_scope, binding_id, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        policy_pack_id: { $ref: '#/components/schemas/Id' }
        binding_scope:
          type: string
          enum: [organization, workspace, campaign, agent]
        binding_id: { $ref: '#/components/schemas/Id' }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    EffectivePolicy:
      type: object
      required: [context, rules, applied_policy_packs]
      properties:
        context:
          type: object
          additionalProperties: true
        rules:
          $ref: '#/components/schemas/PolicyRuleSet'
        applied_policy_packs:
          type: array
          items:
            type: object
            required: [policy_pack_id, name, version, scope]
            properties:
              policy_pack_id: { $ref: '#/components/schemas/Id' }
              name: { type: string }
              version: { type: string }
              scope:
                type: string
                enum: [organization, workspace, campaign, agent]

    AuditLog:
      type: object
      required:
        - id
        - actor_type
        - action
        - result
        - details_json
        - created_at
      properties:
        id: { $ref: '#/components/schemas/Id' }
        organization_id: { $ref: '#/components/schemas/Id', nullable: true }
        workspace_id: { $ref: '#/components/schemas/Id', nullable: true }
        actor_type:
          type: string
          enum: [user, agent, system]
        actor_id: { type: string, nullable: true }
        action: { type: string }
        resource_type: { type: string, nullable: true }
        resource_id: { type: string, nullable: true }
        request_id: { type: string, nullable: true }
        result:
          type: string
          enum: [success, failure]
        details_json:
          type: object
          additionalProperties: true
        created_at: { $ref: '#/components/schemas/Timestamp' }

    UsageEvent:
      type: object
      required: [id, workspace_id, usage_type, quantity, unit, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id', nullable: true }
        avatar_id: { $ref: '#/components/schemas/Id', nullable: true }
        workflow_run_id: { $ref: '#/components/schemas/Id', nullable: true }
        usage_type: { type: string }
        quantity: { type: number }
        unit: { type: string }
        estimated_cost_cents: { type: integer, nullable: true }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    BillingEvent:
      type: object
      required: [id, billing_code, amount_cents, billing_period, created_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        organization_id: { $ref: '#/components/schemas/Id', nullable: true }
        workspace_id: { $ref: '#/components/schemas/Id', nullable: true }
        usage_event_id: { $ref: '#/components/schemas/Id', nullable: true }
        billing_code: { type: string }
        amount_cents: { type: integer }
        billing_period: { type: string }
        created_at: { $ref: '#/components/schemas/Timestamp' }

    SpendSummary:
      type: object
      required: [workspace_id, period, total_spend_cents]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        period: { type: string }
        total_spend_cents: { type: integer }
        budget_limit_cents: { type: integer, nullable: true }
        threshold_ratio: { type: number, nullable: true }

    Webhook:
      type: object
      required: [id, workspace_id, url, status, subscribed_event_types, created_at, updated_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        url: { type: string, format: uri }
        status: { type: string }
        subscribed_event_types:
          type: array
          items: { type: string }
        created_at: { $ref: '#/components/schemas/Timestamp' }
        updated_at: { $ref: '#/components/schemas/Timestamp' }

    WebhookDelivery:
      type: object
      required: [id, delivery_id, webhook_id, event_type, status, attempt_count, attempted_at]
      properties:
        id: { $ref: '#/components/schemas/Id' }
        delivery_id: { $ref: '#/components/schemas/Id' }
        webhook_id: { $ref: '#/components/schemas/Id' }
        event_type: { type: string }
        status: { type: string }
        attempt_count: { type: integer }
        last_attempt_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        response_status: { type: integer, nullable: true }
        response_body_truncated: { type: string, nullable: true }
        error_message: { type: string, nullable: true }
        next_retry_at: { $ref: '#/components/schemas/Timestamp', nullable: true }
        attempted_at: { $ref: '#/components/schemas/Timestamp' }

    WorkflowReference:
      type: object
      required: [workflow_run_id, status]
      properties:
        workflow_run_id: { $ref: '#/components/schemas/Id' }
        status:
          type: string
          enum: [queued, running, waiting_for_approval, blocked, completed, failed, canceled]

    AsyncWorkflowOperation:
      type: object
      required: [resource_id, workflow]
      properties:
        resource_id: { $ref: '#/components/schemas/Id' }
        workflow:
          $ref: '#/components/schemas/WorkflowReference'

    OrganizationSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Organization'

    WorkspaceSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Workspace'

    AvatarSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Avatar'

    AvatarVersionSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/AvatarVersion'

    CampaignSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Campaign'

    WorkflowRunSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/WorkflowRun'

    AssetSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Asset'

    ExportSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Export'

    ExportPresetSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/ExportPreset'

    AgentSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/AgentPrincipal'

    AgentTokenSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/AgentToken'

    ApprovalSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/ApprovalRequest'

    ApprovalDecisionSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/ApprovalDecision'

    PlanningPreviewSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/PlanningPreview'

    SpendLimitSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/SpendLimit'

    SpendLimitListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/SpendLimit'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    PolicyPackSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/PolicyPack'

    PolicyPackListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/PolicyPack'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    PolicyBindingSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/PolicyBinding'

    PolicyBindingListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/PolicyBinding'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    EffectivePolicySingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/EffectivePolicy'

    AuditLogSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/AuditLog'

    SpendSummarySingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/SpendSummary'

    WebhookSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/Webhook'

    AsyncWorkflowSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          $ref: '#/components/schemas/AsyncWorkflowOperation'

    WorkflowStepListResponse:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowStep'

    WorkflowEventListResponse:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowEvent'

    WorkflowStepControlRequest:
      type: object
      properties:
        notes:
          type: string
          maxLength: 2000

    WorkflowStepControlSingleResponse:
      type: object
      required: [data]
      properties:
        data:
          type: object
          required: [resource_id, workflow, step]
          properties:
            resource_id:
              $ref: '#/components/schemas/Id'
            workflow:
              $ref: '#/components/schemas/WorkflowReference'
            step:
              type: object
              required: [id, step_key, status, attempt_count]
              properties:
                id:
                  $ref: '#/components/schemas/Id'
                step_key:
                  type: string
                status:
                  type: string
                  enum: [pending, running, completed, failed, skipped, blocked]
                attempt_count:
                  type: integer

    AssetLineageResponse:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/AssetLineage'

    AssetScoresResponse:
      type: object
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/AssetScore'

    PresignUploadResponse:
      type: object
      required: [data]
      properties:
        data:
          type: object
          required: [upload_url, storage_bucket, storage_key]
          properties:
            upload_url:
              type: string
              format: uri
            storage_bucket:
              type: string
            storage_key:
              type: string

    OrganizationListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Organization'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    WorkspaceListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Workspace'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    AvatarListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Avatar'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    AvatarVersionListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/AvatarVersion'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    CampaignListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Campaign'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    WorkflowRunListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WorkflowRun'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    AssetListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Asset'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    ExportListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Export'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    ExportPresetListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ExportPreset'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    AgentListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/AgentPrincipal'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    ApprovalListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ApprovalRequest'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    AuditLogListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/AuditLog'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    UsageEventListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/UsageEvent'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    BillingEventListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/BillingEvent'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    WebhookListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Webhook'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    WebhookDeliveryListResponse:
      type: object
      required: [items, page_info]
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/WebhookDelivery'
        page_info:
          $ref: '#/components/schemas/PageInfo'

    CreateOrganizationRequest:
      type: object
      required: [name, slug]
      properties:
        name: { type: string }
        slug: { type: string }
        default_region: { type: string }

    UpdateOrganizationRequest:
      type: object
      properties:
        name: { type: string }
        status: { type: string }

    CreateWorkspaceRequest:
      type: object
      required: [organization_id, name, slug]
      properties:
        organization_id: { $ref: '#/components/schemas/Id' }
        name: { type: string }
        slug: { type: string }
        description: { type: string }
        region: { type: string }

    UpdateWorkspaceRequest:
      type: object
      properties:
        name: { type: string }
        description: { type: string }
        status: { type: string }
        region: { type: string }

    CreateAvatarRequest:
      type: object
      required: [workspace_id, name, avatar_type]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        name: { type: string }
        slug: { type: string }
        avatar_type:
          type: string
          enum: [human, animal, mascot, fantasy, object]
        description: { type: string }

    UpdateAvatarRequest:
      type: object
      properties:
        name: { type: string }
        description: { type: string }
        primary_voice_profile_id: { $ref: '#/components/schemas/Id' }

    CreateAvatarVersionRequest:
      type: object
      properties:
        generation_mode:
          type: string
          enum: [canonical, refine]
        brief: { type: string }
        style_hints:
          type: array
          items: { type: string }
        reference_asset_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }

    RejectAvatarVersionRequest:
      type: object
      properties:
        notes: { type: string }

    CreateCampaignRequest:
      type: object
      required: [workspace_id, name]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        name: { type: string }
        slug: { type: string }
        objective: { type: string }
        brief_markdown: { type: string }
        avatar_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }
        budget_limit_cents: { type: integer }

    UpdateCampaignRequest:
      type: object
      properties:
        name: { type: string }
        objective: { type: string }
        brief_markdown: { type: string }
        budget_limit_cents: { type: integer }

    GenerateCampaignRequest:
      type: object
      properties:
        mode:
          type: string
          enum: [draft, final]
        export_preset_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }

    SignalWorkflowRequest:
      type: object
      required: [signal_name]
      properties:
        signal_name:
          type: string
          enum: [approve, reject, resume, cancel]
        payload:
          type: object
          additionalProperties: true

    PresignUploadRequest:
      type: object
      required: [workspace_id, file_name, content_type]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        file_name: { type: string }
        content_type: { type: string }

    AddAssetTagsRequest:
      type: object
      required: [tags]
      properties:
        tags:
          type: array
          items: { type: string }

    CreateExportRequest:
      type: object
      required: [workspace_id]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id' }
        asset_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }
        preset_id: { $ref: '#/components/schemas/Id' }

    CreateExportPresetRequest:
      type: object
      required: [workspace_id, name, preset_key]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        name: { type: string }
        preset_key: { type: string }
        aspect_ratio: { type: string }
        target_width: { type: integer }
        target_height: { type: integer }
        file_format: { type: string }
        caption_policy: { type: string }
        settings_json:
          type: object
          additionalProperties: true

    CreateAgentRequest:
      type: object
      required: [workspace_id, name, principal_type]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        name: { type: string }
        description: { type: string }
        principal_type:
          type: string
          enum: [service, internal_agent, external_agent, automation]

    CreateAgentTokenRequest:
      type: object
      properties:
        expires_at:
          type: string
          format: date-time

    ApprovalDecisionRequest:
      type: object
      required: [decision]
      properties:
        decision:
          type: string
          enum: [approve, reject]
        notes:
          type: string

    PlanningPreviewRequest:
      type: object
      required: [workspace_id, plan_type, prompt]
      additionalProperties: false
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        plan_type:
          type: string
          enum: [avatar, campaign]
        mode:
          type: string
          enum: [draft, final]
          default: draft
        prompt:
          type: string
          minLength: 1
        avatar_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id' }
        selected_avatar_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }
        channels:
          type: array
          items: { type: string }
        style_hints:
          type: array
          items: { type: string }
        reference_asset_ids:
          type: array
          items: { $ref: '#/components/schemas/Id' }

    CreateSpendLimitRequest:
      type: object
      required: [limit_cents]
      properties:
        organization_id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        campaign_id: { $ref: '#/components/schemas/Id' }
        agent_principal_id: { $ref: '#/components/schemas/Id' }
        limit_cents: { type: integer, minimum: 1 }
        enforcement_mode:
          type: string
          enum: [hard, soft]

    UpdateSpendLimitRequest:
      type: object
      properties:
        limit_cents: { type: integer, minimum: 1 }
        enforcement_mode:
          type: string
          enum: [hard, soft]
      minProperties: 1

    CreatePolicyPackRequest:
      type: object
      required: [name]
      properties:
        organization_id: { $ref: '#/components/schemas/Id' }
        workspace_id: { $ref: '#/components/schemas/Id' }
        name: { type: string, minLength: 1 }
        version: { type: string, minLength: 1 }
        status:
          type: string
          enum: [active, archived]
        rules:
          $ref: '#/components/schemas/PolicyRuleSet'

    UpdatePolicyPackRequest:
      type: object
      properties:
        name: { type: string, minLength: 1 }
        version: { type: string, minLength: 1 }
        status:
          type: string
          enum: [active, archived]
        rules:
          $ref: '#/components/schemas/PolicyRuleSet'
      minProperties: 1

    CreatePolicyBindingRequest:
      type: object
      required: [binding_scope, binding_id]
      properties:
        binding_scope:
          type: string
          enum: [organization, workspace, campaign, agent]
        binding_id: { $ref: '#/components/schemas/Id' }

    CreateWebhookRequest:
      type: object
      required: [workspace_id, url]
      properties:
        workspace_id: { $ref: '#/components/schemas/Id' }
        url: { type: string, format: uri }
        status: { type: string, enum: [active, disabled] }
        subscribed_event_types:
          type: array
          items: { type: string }

    UpdateWebhookRequest:
      type: object
      properties:
        url: { type: string, format: uri }
        status: { type: string }
        subscribed_event_types:
          type: array
          items: { type: string }
