openapi: 3.0.3
info:
  title: NativeAds Headless API
  version: 1.0.0
  description: 'The headless REST API for programmatic creative generation. Authenticate
    with a per-user API key (`Authorization: Bearer nak_...`). This reference lists
    only the endpoints an API key may call; generation endpoints are asynchronous
    (submit returns an id, then poll).'
  license:
    name: Commercial
    url: https://www.nativeads.ai/
servers:
- url: https://api.nativeads.ai/v1
  description: NativeAds API Server
- url: https://dev-api.nativeads.ai/v1
  description: NativeAds Development API Server
- url: https://staging-api.nativeads.ai/v1
  description: NativeAds Staging API Server
security:
- BearerAuth: []
paths:
  /assets/initiate-upload:
    post:
      summary: Initiate file upload
      description: Get presigned URLs for secure direct-to-storage uploads
      operationId: initiateUpload
      tags:
      - Assets
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InitiateUploadRequest'
      responses:
        '201':
          description: Upload URLs generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InitiateUploadResponse'
        '400':
          description: Invalid request data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /assets/confirm-upload:
    post:
      summary: Confirm successful upload
      description: Marks upload as complete and triggers asset processing
      operationId: confirmUpload
      tags:
      - Assets
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ConfirmUploadRequest'
      responses:
        '200':
          description: Upload confirmed and processing started
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Asset'
        '400':
          description: Invalid upload data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Upload not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /assets/cancel-upload/{uploadId}:
    post:
      summary: Cancel an in-progress upload
      description: Cancels an upload and cleans up any temporary resources
      operationId: cancelUpload
      tags:
      - Assets
      parameters:
      - name: uploadId
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: Unique identifier of the upload to cancel
      responses:
        '200':
          description: Upload cancelled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelUploadResponse'
        '404':
          description: Upload not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /assets/{assetId}:
    get:
      summary: Get asset details
      operationId: getAsset
      tags:
      - Assets
      parameters:
      - name: assetId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Asset details retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Asset'
        '404':
          description: Asset not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/assets:
    get:
      summary: List brand assets
      description: Retrieve assets with filtering and pagination
      operationId: listBrandAssets
      tags:
      - Assets
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: type
        in: query
        schema:
          type: string
          enum:
          - image
          - video
          - document
      - name: status
        in: query
        schema:
          type: string
          enum:
          - processing
          - complete
          - failed
      - name: tags
        in: query
        schema:
          type: array
          items:
            type: string
      - name: campaignId
        in: query
        schema:
          type: string
          format: uuid
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: limit
        in: query
        schema:
          type: integer
          default: 20
          maximum: 100
      - name: sort
        in: query
        schema:
          type: string
          enum:
          - createdAt
          - -createdAt
          - fileName
          - -fileName
          default: -createdAt
      responses:
        '200':
          description: Assets retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CategorizedAssetList'
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands:
    post:
      summary: Create a new brand
      operationId: createBrand
      tags:
      - Brands
      requestBody:
        description: Details of the brand to be created
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBrandRequest'
      responses:
        '201':
          description: Brand successfully created
          headers:
            Location:
              schema:
                type: string
              description: URL of the created resource
            ETag:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Brand'
        '400':
          description: Invalid input data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden - No permissions for advertiser ID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                noPermissions:
                  value:
                    requestId: 123e4567-e89b-12d3-a456-426614174000
                    error:
                      code: FORBIDDEN
                      message: No permissions for Walmart advertiser ID
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          headers:
            Retry-After:
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: Service Unavailable - Cannot validate advertiser ID
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                walmartUnavailable:
                  value:
                    requestId: 123e4567-e89b-12d3-a456-426614174002
                    error:
                      code: SERVICE_UNAVAILABLE
                      message: Unable to validate Walmart advertiser ID at this time.
                        Walmart API is unreachable. Please try again later.
    get:
      summary: Retrieve a list of brands
      operationId: listBrands
      tags:
      - Brands
      parameters:
      - name: all_organizations
        in: query
        description: Set to 'true' to retrieve brands from all organizations. This
          is an admin-only parameter. Requests from non-admin users with this parameter
          will result in a 403 Forbidden error.
        required: false
        schema:
          type: boolean
          default: false
      - name: page
        in: query
        schema:
          type: integer
          minimum: 1
          default: 1
      - name: limit
        in: query
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 20
      - name: sort
        in: query
        schema:
          type: string
          enum:
          - name
          - -name
          - createdAt
          - -createdAt
          default: -createdAt
      - name: industry
        in: query
        schema:
          type: string
      responses:
        '200':
          description: List of brands retrieved successfully
          headers:
            Cache-Control:
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Brand'
                  pagination:
                    type: object
                    required:
                    - total
                    - pages
                    - currentPage
                    - limit
                    properties:
                      total:
                        type: integer
                      pages:
                        type: integer
                      currentPage:
                        type: integer
                      limit:
                        type: integer
                  links:
                    type: object
                    properties:
                      self:
                        type: string
                        format: uri
                      next:
                        type: string
                        format: uri
                      prev:
                        type: string
                        format: uri
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}:
    parameters:
    - name: brandId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Unique identifier of the brand
    get:
      summary: Retrieve a specific brand
      operationId: getBrandById
      tags:
      - Brands
      responses:
        '200':
          description: Brand details retrieved successfully
          headers:
            ETag:
              schema:
                type: string
            Cache-Control:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Brand'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      summary: Update a specific brand
      operationId: updateBrand
      tags:
      - Brands
      parameters:
      - name: If-Match
        in: header
        required: true
        schema:
          type: string
        description: ETag from previous get/update
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateBrandRequest'
      responses:
        '200':
          description: Brand successfully updated
          headers:
            ETag:
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Brand'
        '400':
          description: Invalid request data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Conflict - Cannot change advertiser ID (brand has submitted
            creatives)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                hasSubmittedCreatives:
                  value:
                    requestId: 123e4567-e89b-12d3-a456-426614174003
                    error:
                      code: CONFLICT
                      message: Cannot change advertiser ID because this brand has
                        3 creative(s) that have been submitted to Walmart. Creatives
                        must be deleted before changing the advertiser ID.
                      details:
                        blockingCreativeCount: 3
                        blockingStatuses:
                        - walmart_draft
                        - approved
        '412':
          description: Precondition failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/dna:
    parameters:
    - name: brandId
      in: path
      required: true
      schema:
        type: string
        format: uuid
    get:
      summary: Get Brand DNA status and data
      description: 'Returns the current Brand DNA extraction status and the merged
        Brand DNA

        data for a brand. If no PDFs have been uploaded, status will be ''none''.

        '
      operationId: getBrandDna
      tags:
      - Brands
      responses:
        '200':
          description: Brand DNA status and data
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    $ref: '#/components/schemas/BrandDnaResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/brand-dna/versions:
    get:
      summary: List Brand DNA versions for a brand
      description: Returns all versions for the brand, newest first. Each item carries
        the preview slice but not the full DNA payload.
      operationId: listBrandDnaVersions
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: List retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListBrandDnaVersionsResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      summary: Create a new Brand DNA version
      description: 'Create a new version with one or more source assets/URLs. Returns
        the version

        in pending state; the orchestrator picks up the workflow trigger row and runs

        per-source extractors plus the merger asynchronously.

        '
      operationId: createBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateBrandDnaVersionRequest'
      responses:
        '200':
          description: Version created and queued for extraction
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandDnaVersionSummaryResponse'
        '400':
          description: Bad Request - invalid body or NO_SOURCES
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden - ASSET_NOT_OWNED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/brand-dna/active:
    get:
      summary: Get the currently active Brand DNA version
      description: 'Returns the active version detail. When the active version is
        mid-rerun

        (status=pending or extracting), responds 200 with `dna: null`. Returns 404

        when no version has ever been activated for the brand.

        '
      operationId: getActiveBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Active version retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandDnaVersionDetailResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found or no active version (VERSION_NOT_FOUND)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/brand-dna/versions/{versionId}:
    get:
      summary: Get a specific Brand DNA version
      description: Returns the full version detail including sources and (when ready)
        the canonical DNA payload.
      operationId: getBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: versionId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Version retrieved
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandDnaVersionDetailResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERSION_NOT_FOUND or BRAND_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    put:
      summary: Update a Brand DNA version (rename and/or edit DNA payload)
      description: 'Optimistic-locked update via updatedAt. Setting `dna` overwrites
        the canonical

        S3 payload and recomputes the preview slice; `name` updates metadata only.

        At least one of `name` or `dna` must be provided. Confidence score and

        missing fields are immutable from this endpoint.

        '
      operationId: updateBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: versionId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateBrandDnaVersionRequest'
      responses:
        '200':
          description: Version updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandDnaVersionSummaryResponse'
        '400':
          description: Bad Request - invalid body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERSION_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: STALE_UPDATE (concurrency conflict) or INVALID_STATUS_FOR_ACTION
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      summary: Delete a Brand DNA version
      description: 'Hard-deletes a non-active version, including its sources (CASCADE)
        and S3

        artifacts. Deleting the active version is forbidden; activate another version
        first.

        '
      operationId: deleteBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: versionId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '204':
          description: Version deleted
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERSION_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: ACTIVE_VERSION_DELETE_FORBIDDEN
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/brand-dna/versions/{versionId}/activate:
    post:
      summary: Activate a Brand DNA version
      description: 'Marks the version active and mirrors its s3_key, version_number,
        and status to

        Brands.brand_dna_s3_key/brand_dna_version/brand_dna_status so downstream

        modal consumers pick up the new payload. Idempotent on an already-active version.

        '
      operationId: activateBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: versionId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: Version activated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandDnaVersionSummaryResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERSION_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: INVALID_STATUS_FOR_ACTION (only ready versions can activate)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/brand-dna/versions/{versionId}/cancel:
    post:
      summary: Cancel an in-flight Brand DNA extraction
      description: 'Signals workflow cancellation and deletes the version row. Only
        valid

        while the version is pending or extracting. Best-effort cleans S3 partials.

        '
      operationId: cancelBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: versionId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '204':
          description: Version cancelled and removed
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERSION_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: INVALID_STATUS_FOR_ACTION (cannot cancel ready or failed)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/brand-dna/versions/{versionId}/rerun:
    post:
      summary: Re-run extraction for a Brand DNA version
      description: 'Replaces the version''s source set with the supplied assetIds
        and urls,

        resets status to pending, and queues a fresh extraction. The version

        retains its versionNumber and is_active flag. Returns 202 Accepted.

        '
      operationId: rerunBrandDnaVersion
      tags:
      - Brand DNA Versions
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: versionId
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RerunBrandDnaVersionRequest'
      responses:
        '202':
          description: Re-run accepted; poll the version detail endpoint until status=ready
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrandDnaVersionSummaryResponse'
        '400':
          description: Bad Request - NO_SOURCES or invalid body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden - ASSET_NOT_OWNED
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERSION_NOT_FOUND
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: INVALID_STATUS_FOR_ACTION (cannot rerun while pending or extracting)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/scene-forges:
    post:
      summary: Create scene forge request
      description: 'Generate a scene with products, optional environment, and blending
        prompt.

        This is an asynchronous operation that creates 4 initial variations.

        Returns 202 Accepted. Poll the GET endpoint to check generation status.

        '
      operationId: createSceneForge
      tags:
      - Scene Forges
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        description: Brand context for the scene forge
        schema:
          type: string
          format: uuid
        example: 223e4567-e89b-12d3-a456-426614174000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SceneForgeInput'
            example:
              blendingPrompt: Products displayed on a marble countertop with natural
                lighting
              aspectRatio: '16:9'
              productAssetIds:
              - 550e8400-e29b-41d4-a716-446655440000
              - 6ba7b810-9dad-11d1-80b4-00c04fd430c8
              environmentAssetId: 7c9e6679-7425-40de-944b-e07fc1f90ae7
      responses:
        '202':
          description: Scene forge request accepted for asynchronous processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SceneForge'
        '400':
          description: Bad Request - Invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand or referenced assets not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: Unprocessable Entity - Validation failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests - Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      summary: List scene forges for brand
      description: 'Retrieve a paginated list of scene forges for the specified brand.

        Results can be filtered by status and sorted by creation or update time.

        '
      operationId: listSceneForges
      tags:
      - Scene Forges
      security:
      - BearerAuth: []
      parameters:
      - name: partner
        in: query
        required: false
        description: Partner list filter. Omit for the default bucket only; "all"
          returns every partner; otherwise a single partner slug.
        schema:
          $ref: '#/components/schemas/PartnerFilter'
      - name: brandId
        in: path
        required: true
        description: Brand identifier
        schema:
          type: string
          format: uuid
        example: 223e4567-e89b-12d3-a456-426614174000
      - name: page
        in: query
        required: false
        description: Page number (1-indexed)
        schema:
          type: integer
          minimum: 1
          default: 1
        example: 1
      - name: limit
        in: query
        required: false
        description: Number of items per page
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 20
        example: 20
      - name: sortBy
        in: query
        required: false
        description: Field to sort by
        schema:
          type: string
          enum:
          - createdAt
          - updatedAt
          default: createdAt
        example: createdAt
      - name: sortOrder
        in: query
        required: false
        description: Sort direction
        schema:
          type: string
          enum:
          - asc
          - desc
          default: desc
        example: desc
      - name: status
        in: query
        required: false
        description: Filter by generation status
        schema:
          $ref: '#/components/schemas/GenerationStatus'
        example: completed
      responses:
        '200':
          description: Scene forges retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SceneForgePaginatedResponse'
        '400':
          description: Bad Request - Invalid query parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests - Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /scene-forges/{id}:
    get:
      summary: Get scene forge by ID
      description: 'Retrieve scene forge details including all generated variations.

        Use this endpoint to poll for completion status after creating a scene forge.

        '
      operationId: getSceneForge
      tags:
      - Scene Forges
      security:
      - BearerAuth: []
      parameters:
      - name: id
        in: path
        required: true
        description: Scene forge identifier
        schema:
          type: string
          format: uuid
        example: 323e4567-e89b-12d3-a456-426614174000
      responses:
        '200':
          description: Scene forge retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SceneForge'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Scene forge not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests - Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/scene-forge-prompt-enhancements:
    post:
      summary: Create prompt enhancement request
      description: 'Request AI enhancement of a prompt for Scene Forge generation.

        This is an asynchronous operation that returns 202 Accepted.

        Poll the GET endpoint to check enhancement status and retrieve results.

        '
      operationId: createPromptEnhancement
      tags:
      - Scene Forge Prompt Enhancements
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        description: Brand context for the enhancement
        schema:
          type: string
          format: uuid
        example: 223e4567-e89b-12d3-a456-426614174000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PromptEnhancementInput'
            example:
              originalPrompt: A modern kitchen with stainless steel appliances
              productAssetIds:
              - 550e8400-e29b-41d4-a716-446655440000
              environmentAssetId: 7c9e6679-7425-40de-944b-e07fc1f90ae7
      responses:
        '202':
          description: Prompt enhancement request accepted for asynchronous processing
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptEnhancement'
        '400':
          description: Bad Request - Invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand or referenced assets not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests - Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/scene-forge-prompt-enhancements/{id}:
    get:
      summary: Get prompt enhancement by ID
      description: 'Retrieve prompt enhancement details and status. Use this endpoint
        to poll

        for completion status after creating a prompt enhancement request.

        Returns both originalPrompt and optimizedPrompt to support frontend Undo functionality.

        '
      operationId: getPromptEnhancement
      tags:
      - Scene Forge Prompt Enhancements
      security:
      - BearerAuth: []
      parameters:
      - name: brandId
        in: path
        required: true
        description: Brand context
        schema:
          type: string
          format: uuid
        example: 223e4567-e89b-12d3-a456-426614174000
      - name: id
        in: path
        required: true
        description: Prompt enhancement identifier
        schema:
          type: string
          format: uuid
        example: 123e4567-e89b-12d3-a456-426614174000
      responses:
        '200':
          description: Prompt enhancement retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PromptEnhancement'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Prompt enhancement not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Too Many Requests - Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/generate-video:
    parameters:
    - name: brandId
      in: path
      required: true
      description: The unique identifier of the brand.
      schema:
        type: string
        format: uuid
    post:
      tags:
      - VideoGeneration
      summary: Submit Video Generation Job
      description: Creates a new Video Generation Group and triggers the asynchronous
        generation of videos variations. It generates a video for every combination
        of the provided prompts and dimensions, using the specified source asset.
      operationId: generateVideo
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/VideoGenerationRequest'
            example:
              startImageAssetId: 123e4567-e89b-12d3-a456-426614174000
              userPrompts:
              - Product on a beach at sunset, dramatic lighting
              - Product floating in space among nebulae
              dimension:
                width: 1024
                height: 1024
              enableAudio: false
      responses:
        '202':
          description: Video generation job accepted. The response includes the group
            ID and initial details for all variation jobs (once for each prompt) which
            are now pending. Poll GET /generated-videos-groups/{generatedVideosGroupId}
            for status updates.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedGeneratedVideosGroupList'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/generated-videos-groups:
    get:
      tags:
      - VideoGeneration
      summary: List Generated Video Groups
      description: Retrieves a paginated list of all generated videos groups created
        by the user/brand, suitable for the gallery view. Each group includes its
        source asset info, parameters, and the generated video variations with their
        current status.
      operationId: listGeneratedVideosGroups
      parameters:
      - name: partner
        in: query
        required: false
        description: Partner list filter. Omit for the default bucket only; "all"
          returns every partner; otherwise a single partner slug.
        schema:
          $ref: '#/components/schemas/PartnerFilter'
      - name: brandId
        in: path
        required: true
        description: The unique identifier of the brand.
        schema:
          type: string
          format: uuid
      - name: page
        in: query
        description: Page number for pagination.
        schema:
          type: integer
          default: 1
          minimum: 1
      - name: limit
        in: query
        description: Number of items per page.
        schema:
          type: integer
          default: 20
          minimum: 1
          maximum: 100
      - name: sortBy
        in: query
        description: Field to sort by.
        schema:
          type: string
          enum:
          - createdAt
          default: createdAt
      - name: sortOrder
        in: query
        description: Sort order.
        schema:
          type: string
          enum:
          - asc
          - desc
          default: desc
      responses:
        '200':
          description: A paginated list of generated videos groups.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedGeneratedVideosGroupList'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /generated-videos-groups/{generatedVideosGroupId}:
    parameters:
    - name: generatedVideosGroupId
      in: path
      required: true
      description: The unique identifier of the generated videos group.
      schema:
        type: string
        format: uuid
    get:
      tags:
      - VideoGeneration
      summary: Get Generated Videos Group Details
      description: Retrieves the details of a specific generated videos group, including
        the status of all its generated variations. Poll this endpoint after submitting
        a video generation job to track progress.
      operationId: getGeneretedVideosGroup
      responses:
        '200':
          description: Generated videos group details retrieved successfully.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GeneratedVideosGroup'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Generated videos group not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/image-to-video-prompt-enhancements:
    parameters:
    - name: brandId
      in: path
      required: true
      description: The unique identifier of the brand.
      schema:
        type: string
        format: uuid
    post:
      tags:
      - Image-to-Video Prompt Enhancements
      summary: Create an image-to-video prompt enhancement preview
      description: 'Creates a prompt enhancement preview request for image-to-video
        generation.

        The enhancement workflow will refine the provided prompt using AI, taking
        into

        account the start frame image, aspect ratio, and target video model, and return

        an optimized version suitable for video generation.

        '
      operationId: createImageToVideoPromptEnhancement
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateImageToVideoPromptEnhancementRequest'
            example:
              startFrameAssetId: 550e8400-e29b-41d4-a716-446655440000
              endFrameAssetId: 660e8400-e29b-41d4-a716-446655440001
              originalPrompt: The product slowly rotates on a marble countertop with
                soft natural lighting
              aspectRatio: '16:9'
              model: veo-3.1
      responses:
        '202':
          description: Prompt enhancement request accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageToVideoPromptEnhancementResponse'
        '400':
          description: Bad Request - Invalid input
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Brand or asset not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /brands/{brandId}/image-to-video-prompt-enhancements/{id}:
    parameters:
    - name: brandId
      in: path
      required: true
      description: The unique identifier of the brand.
      schema:
        type: string
        format: uuid
    - name: id
      in: path
      required: true
      description: The prompt enhancement ID.
      schema:
        type: string
        format: uuid
    get:
      tags:
      - Image-to-Video Prompt Enhancements
      summary: Get image-to-video prompt enhancement status and results
      description: 'Retrieves the status and results of a prompt enhancement request.

        Poll this endpoint until status is ''completed'' or ''failed''.

        '
      operationId: getImageToVideoPromptEnhancement
      responses:
        '200':
          description: Prompt enhancement details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ImageToVideoPromptEnhancementResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Prompt enhancement not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /organizations/current/feature-usage:
    get:
      summary: Get feature usage status
      description: 'Retrieve usage status for all managed features. Returns current
        usage counts,

        limits, remaining quota, and reset timing for the current organization.


        Features are grouped by source (plan or override) and include cap information

        for each cap type (e.g., generation, training).

        '
      operationId: getFeatureUsage
      tags:
      - Organizations
      responses:
        '200':
          description: Successfully retrieved feature usage
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeatureUsageResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token for authentication.
  schemas:
    Asset:
      type: object
      required:
      - id
      - brandId
      - url
      - status
      - createdAt
      - updatedAt
      properties:
        id:
          type: string
          format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
          example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
        status:
          type: string
          enum:
          - uploading
          - uploaded
          - processing
          - complete
          - failed
          - canceled
        url:
          type: string
        thumbnailUrl:
          type: string
        metadata:
          $ref: '#/components/schemas/AssetMetadata'
        tags:
          type: array
          items:
            type: string
        autoGeneratedTags:
          type: array
          items:
            type: string
        usedInCampaigns:
          type: array
          items:
            type: string
            format: uuid
        assetQualityTags:
          type: array
          items:
            $ref: '#/components/schemas/AssetQualityTag'
        qualityAssessment:
          allOf:
          - $ref: '#/components/schemas/AssetQualityAssessment'
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        version:
          type: integer
          default: 0
    AssetMetadata:
      type: object
      required:
      - fileName
      - fileType
      - fileSize
      - type
      - dimension
      - duration
      - description
      properties:
        fileName:
          type: string
          example: logo-dark.png
        fileType:
          type: string
          example: image/jpeg
        fileSize:
          type: integer
        type:
          type: string
          enum:
          - image
          - logo
          - video
          - document
        dimension:
          allOf:
          - $ref: '#/components/schemas/Dimension'
          nullable: true
        duration:
          type: string
        description:
          type: string
    InitiateUploadRequest:
      type: object
      required:
      - files
      - brandId
      properties:
        brandId:
          type: string
          format: uuid
        categoryId:
          type: string
          format: uuid
        files:
          type: array
          items:
            type: object
            required:
            - fileName
            - fileType
            - fileSize
            - dimension
            properties:
              fileName:
                type: string
                maxLength: 1000
              fileType:
                type: string
                enum:
                - image/jpeg
                - image/png
                - image/svg+xml
                - image/tiff
                - video/mp4
                - video/quicktime
                - application/pdf
              fileSize:
                type: integer
                maximum: 524288000
              isLogo:
                type: boolean
                description: Indicates if the file is a logo
                nullable: true
              dimension:
                $ref: '#/components/schemas/Dimension'
    InitiateUploadResponse:
      type: object
      properties:
        uploads:
          type: array
          items:
            type: object
            required:
            - uploadId
            - assetId
            - uploadUrl
            - expires
            properties:
              uploadId:
                type: string
                format: uuid
              assetId:
                type: string
                format: uuid
              uploadUrl:
                type: string
                format: uri
              expires:
                type: string
                format: date-time
    CancelUploadResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          example: Upload cancelled successfully
      required:
      - success
      - message
    AssetCategory:
      type: object
      required:
      - id
      - brandId
      - name
      - createdAt
      - updatedAt
      properties:
        id:
          type: string
          format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
        name:
          type: string
          maxLength: 100
          example: Logo Assets
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    CreateCategoryRequest:
      type: object
      required:
      - brandId
      - name
      properties:
        brandId:
          type: string
          format: uuid
        name:
          type: string
          maxLength: 100
    UpdateCategoryRequest:
      type: object
      required:
      - name
      properties:
        name:
          type: string
          maxLength: 100
    CategorizedAssetList:
      type: object
      required:
      - categories
      properties:
        categories:
          type: array
          items:
            type: object
            required:
            - id
            - name
            - assets
            properties:
              id:
                type: string
                description: Category identifier - UUID string for user-created categories,
                  or predefined strings like 'general' for default categories
                example: general
              name:
                type: string
              assets:
                type: array
                items:
                  $ref: '#/components/schemas/Asset'
    ConfirmUploadRequest:
      type: object
      required:
      - uploadId
      properties:
        uploadId:
          type: string
          format: uuid
        categoryId:
          type: string
          format: uuid
          description: Optional category ID to assign the asset to
    BrandDnaPreview:
      type: object
      required:
      - colorHexes
      - typographyShort
      - toneShort
      - topValues
      - sourceCounts
      description: Denormalized list-view slice computed from the canonical DNA payload
      properties:
        colorHexes:
          type: array
          items:
            type: string
          maxItems: 5
          description: First 5 color hex values from the canonical palette
          example:
          - '#1a8a3a'
          - '#fff8e7'
          - '#3a3a3a'
          - '#c00000'
          - '#a3c293'
        typographyShort:
          type: string
          description: Short typography descriptor (truncated)
          example: Bold sans-serif headlines paired with serif body copy
        toneShort:
          type: string
          description: Short voice/tone descriptor (truncated)
          example: Warm, family-oriented, confident
        topValues:
          type: array
          items:
            type: string
          maxItems: 3
          description: Top 3 brand values
          example:
          - Quality
          - Family
          - Tradition
        sourceCounts:
          type: object
          required:
          - pdf
          - image
          - video
          - url
          description: Count of source rows per type for the version
          properties:
            pdf:
              type: integer
              minimum: 0
            image:
              type: integer
              minimum: 0
            video:
              type: integer
              minimum: 0
            url:
              type: integer
              minimum: 0
    BrandDnaSource:
      type: object
      required:
      - id
      - type
      - status
      description: One source (asset or URL) feeding a Brand DNA version
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        type:
          type: string
          enum:
          - pdf
          - image
          - video
          - url
          description: Source category
        label:
          type: string
          nullable: true
          description: Optional human-readable label set at create time
        assetId:
          type: string
          format: uuid
          nullable: true
          description: Asset ID for asset-backed sources (mutually exclusive with
            url)
        url:
          type: string
          nullable: true
          description: URL for url sources (mutually exclusive with assetId)
        pageCount:
          type: integer
          nullable: true
          description: Page count for PDF sources, populated after extraction
        status:
          type: string
          enum:
          - queued
          - processing
          - done
          - failed
          description: Per-source processing state
        progressNote:
          type: string
          nullable: true
          description: Free-form progress hint set by extractors
        errorReason:
          type: string
          nullable: true
          description: Failure detail when status=failed
    BrandDnaVersionSummary:
      type: object
      required:
      - versionId
      - versionNumber
      - isActive
      - status
      - createdAt
      - updatedAt
      description: Compact representation of a Brand DNA version, suitable for list
        views
      properties:
        versionId:
          type: string
          format: uuid
          readOnly: true
        versionNumber:
          type: integer
          minimum: 1
          readOnly: true
        name:
          type: string
          nullable: true
          maxLength: 200
        isActive:
          type: boolean
        status:
          type: string
          enum:
          - pending
          - extracting
          - ready
          - failed
          description: Lifecycle state of the version
        confidenceScore:
          type: integer
          nullable: true
          minimum: 1
          maximum: 10
          description: Merger-reported 1 to 10 confidence; null while pending or extracting
        missingFields:
          type: array
          nullable: true
          items:
            type: string
          description: Snake_case field names the merger could not resolve
        preview:
          allOf:
          - $ref: '#/components/schemas/BrandDnaPreview'
          nullable: true
          description: Null while pending or extracting, populated when status=ready
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
    BrandDnaVersionDetail:
      allOf:
      - $ref: '#/components/schemas/BrandDnaVersionSummary'
      - type: object
        required:
        - sources
        properties:
          sources:
            type: array
            items:
              $ref: '#/components/schemas/BrandDnaSource'
          dna:
            type: object
            nullable: true
            description: 'Canonical Brand DNA payload (snake_case passthrough from
              the merger).

              Null while pending or extracting; null on the active version while

              an in-place rerun is underway.

              '
            additionalProperties: true
    CreateBrandDnaVersionRequest:
      type: object
      description: Create a new Brand DNA version. At least one of assetIds or urls
        must be non-empty.
      properties:
        name:
          type: string
          maxLength: 200
          description: Optional human-readable label
        assetIds:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 20
          description: Asset IDs to feed into per-source extractors (PDF, image, or
            video)
        urls:
          type: array
          items:
            type: string
            format: uri
          maxItems: 20
          description: Website URLs to feed into the web extractor
    UpdateBrandDnaVersionRequest:
      type: object
      required:
      - updatedAt
      description: 'Update version metadata or DNA payload. Optimistic lock via updatedAt.

        Omit dna for rename-only updates.

        '
      properties:
        name:
          type: string
          maxLength: 200
        dna:
          type: object
          additionalProperties: true
          description: Full canonical Brand DNA payload (snake_case). Overwrites the
            existing s3_key blob.
        updatedAt:
          type: string
          format: date-time
          description: Concurrency token; the previously-returned updatedAt for this
            version
    RerunBrandDnaVersionRequest:
      type: object
      description: 'Reset a version''s status to pending and queue a fresh extraction.

        Replaces the existing source set with the supplied sources.

        '
      properties:
        assetIds:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 20
        urls:
          type: array
          items:
            type: string
            format: uri
          maxItems: 20
    ListBrandDnaVersionsResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/BrandDnaVersionSummary'
    BrandDnaVersionDetailResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/BrandDnaVersionDetail'
    BrandDnaVersionSummaryResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/BrandDnaVersionSummary'
    Brand:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          example: 123e4567-e89b-12d3-a456-426614174000
        name:
          type: string
          minLength: 1
          maxLength: 100
          example: Acme Corporation
        industry:
          type: string
          minLength: 1
          maxLength: 50
          example: Technology
        description:
          type: string
          minLength: 10
          maxLength: 280
          example: Leading provider of innovative cloud solutions
        mission:
          type: string
          maxLength: 1000
          example: To accelerate the world's transition to sustainable technology
        values:
          type: array
          items:
            type: string
            maxLength: 50
          maxItems: 10
          example:
          - Innovation
          - Sustainability
          - Customer Focus
        tone:
          type: array
          items:
            type: string
            enum:
            - Professional
            - Casual
            - Friendly
            - Authoritative
            - Playful
            - Innovative
            - Traditional
            - Luxurious
          maxItems: 5
          example:
          - Professional
          - Innovative
        voice:
          type: array
          items:
            type: string
            maxLength: 50
          maxItems: 5
          example:
          - Clear
          - Confident
          - Expert
        logoAsset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
          readOnly: true
          description: The detailed logo asset object, or null if no logo is associated.
        organizationId:
          type: string
          format: uuid
          readOnly: true
          nullable: true
          description: identifier of the brand organization
          example: 123e4567-e89b-12d3-a456-426614174000
        organizationName:
          type: string
          nullable: true
          description: name of the brand organization
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
        brandDnaStatus:
          type: string
          readOnly: true
          enum:
          - none
          - pending
          - extracting
          - ready
          - failed
          description: Current Brand DNA extraction status
          default: none
          example: none
      required:
      - id
      - name
      - industry
      - description
      - mission
      - values
      - tone
      - voice
      - createdAt
      - updatedAt
    IntegrationType:
      type: string
      description: The integration variant under a partner.
      enum:
      - display
      - sponsored_video
      - default
      x-enum-varnames:
      - INTEGRATION_DISPLAY
      - INTEGRATION_SPONSORED_VIDEO
      - INTEGRATION_DEFAULT
    BrandPartnerIntegration:
      type: object
      required:
      - integration_type
      - enabled
      properties:
        id:
          type: string
          format: uuid
          nullable: true
          description: brand_integrations row id, or null when this integration is
            not set for the brand.
        integration_type:
          $ref: '#/components/schemas/IntegrationType'
        enabled:
          type: boolean
          description: Whether this integration is connected (i.e. an advertiser_id
            is set).
        advertiser_id:
          type: string
          nullable: true
          description: The partner advertiser ID, or null when not set.
    BrandPartnerGroup:
      type: object
      required:
      - slug
      - integrations
      properties:
        slug:
          allOf:
          - $ref: '#/components/schemas/Partner'
          description: Partner slug (the group key). Localized labels live in the
            frontend.
        integrations:
          type: array
          items:
            $ref: '#/components/schemas/BrandPartnerIntegration'
    BrandPartnersResponse:
      type: object
      required:
      - partners
      properties:
        partners:
          type: array
          items:
            $ref: '#/components/schemas/BrandPartnerGroup'
    SetBrandPartnerIntegration:
      type: object
      required:
      - slug
      - integration_type
      properties:
        slug:
          $ref: '#/components/schemas/Partner'
        integration_type:
          $ref: '#/components/schemas/IntegrationType'
        advertiser_id:
          type: string
          nullable: true
          description: 'Numeric advertiser ID (max 10 digits). Null or empty clears
            (disconnects) the integration.

            '
          pattern: ^[0-9]{1,10}$
          example: '16416669'
    SetBrandPartnersRequest:
      type: object
      required:
      - integrations
      properties:
        integrations:
          type: array
          description: 'The full desired set of partner integrations for the brand.
            Integrations present with a

            non-empty advertiser_id are upserted; integrations omitted (or with null/empty
            advertiser_id)

            are cleared.

            '
          items:
            $ref: '#/components/schemas/SetBrandPartnerIntegration'
    Campaign:
      type: object
      required:
      - brandId
      - name
      - audience
      - subject
      - objectives
      - guidelines
      - selectedAssetIds
      properties:
        campaignId:
          type: string
          format: uuid
          readOnly: true
        brandId:
          type: string
          format: uuid
        name:
          type: string
          minLength: 3
          maxLength: 100
        subject:
          type: string
          minLength: 5
          maxLength: 200
        objectives:
          type: array
          items:
            type: string
            enum:
            - reach
            - conversion
          minItems: 1
        audience:
          type: string
          maxLength: 500
        partner:
          $ref: '#/components/schemas/Partner'
        guidelines:
          $ref: '#/components/schemas/CampaignGuidelines'
        selectedAssetIds:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
        assets:
          type: array
          readOnly: true
          items:
            $ref: '#/components/schemas/CampaignAsset'
        processingStatus:
          type: object
          readOnly: true
          properties:
            assetsProcessing:
              $ref: '#/components/schemas/ProcessingStatus'
            modelTraining:
              $ref: '#/components/schemas/ProcessingStatus'
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
    CampaignGuidelines:
      type: object
      required:
      - tone
      - creativeBrief
      properties:
        tone:
          type: string
          maxLength: 200
        dos:
          type: array
          items:
            type: string
            maxLength: 100
        donts:
          type: array
          items:
            type: string
            maxLength: 100
        creativeBrief:
          type: string
          maxLength: 1000
    CampaignAsset:
      type: object
      required:
      - assetId
      - type
      - url
      - status
      properties:
        assetId:
          type: string
          format: uuid
        type:
          type: string
        url:
          type: string
        status:
          type: string
    ProcessingStatus:
      type: object
      required:
      - status
      - progress
      - completedAt
      properties:
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
        progress:
          type: integer
          minimum: 0
          maximum: 100
        completedAt:
          type: string
          format: date-time
          nullable: true
    Theme:
      type: object
      required:
      - id
      - campaignId
      - content
      - status
      - createdAt
      - updatedAt
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        campaignId:
          type: string
          format: uuid
          readOnly: true
        content:
          type: string
        status:
          type: string
          enum:
          - pending
          - approved
          - rejected
          readOnly: true
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
    CreateThemeRequest:
      type: object
      required:
      - content
      properties:
        content:
          type: string
    CreateThemeAndGenerateRequest:
      type: object
      required:
      - content
      - campaignId
      - settings
      properties:
        content:
          type: string
        campaignId:
          type: string
          format: uuid
        settings:
          type: object
          required:
          - dimensions
          properties:
            dimensions:
              type: array
              items:
                type: object
                required:
                - width
                - height
                properties:
                  width:
                    type: integer
                  height:
                    type: integer
              minItems: 1
              maxItems: 25
        partner:
          $ref: '#/components/schemas/Partner'
    UpdateCampaignRequest:
      type: object
      required:
      - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 200
    CreativeGeneration:
      type: object
      required:
      - campaignId
      - themeId
      properties:
        campaignId:
          type: string
          format: uuid
        themeId:
          type: string
          format: uuid
        partner:
          $ref: '#/components/schemas/Partner'
        settings:
          type: object
          required:
          - dimensions
          properties:
            dimensions:
              type: array
              items:
                type: object
                required:
                - width
                - height
                properties:
                  width:
                    type: integer
                    default: 1024
                  height:
                    type: integer
                    default: 1024
              minItems: 1
              maxItems: 25
    EditCreativeRequest:
      type: object
      required:
      - editPrompt
      - themeId
      - creativeVariationId
      properties:
        editPrompt:
          type: string
        themeId:
          type: string
          format: uuid
        creativeVariationId:
          type: string
          format: uuid
        dimensions:
          type: array
          items:
            type: object
            required:
            - width
            - height
            properties:
              width:
                type: integer
              height:
                type: integer
          minItems: 1
          maxItems: 20
    CreativeVariation:
      type: object
      required:
      - creativeVariationId
      - imageUrl
      - thumbnailUrl
      - status
      - width
      - height
      - liked
      - disliked
      - generatedAt
      properties:
        creativeVariationId:
          type: string
          format: uuid
        assetId:
          type: string
          format: uuid
          nullable: true
          description: The ID of the generated asset once the image is successfully
            created and stored. Null if generation is still pending or failed.
          example: 987e6543-e21b-12d3-a456-426614174999
        imageUrl:
          type: string
        thumbnailUrl:
          type: string
        generationType:
          type: string
          enum:
          - original
          - edit
          - resize
          - identify_replace
        parentVariationId:
          type: string
          format: uuid
        width:
          type: integer
        height:
          type: integer
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
        liked:
          type: boolean
        disliked:
          type: boolean
        generatedAt:
          type: string
          format: date-time
        error:
          type: object
          nullable: true
          description: Error classification populated when the variation failed.
          required:
          - code
          - message
          properties:
            code:
              type: string
            message:
              type: string
              nullable: true
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking partner hardspec-compatibility and ML moderation
            warnings

            (NAT-1677). Empty/absent when the output matches the partner''s image
            specs,

            has no partner, or the partner has no image specs. DISTINCT from hard
            errors

            (see `error`) — a real policy violation / failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    CreativeDetails:
      type: object
      required:
      - themeId
      - prompt
      - createdAt
      properties:
        themeId:
          type: string
          format: uuid
        prompt:
          type: string
        variations:
          type: array
          items:
            $ref: '#/components/schemas/CreativeVariation'
        createdAt:
          type: string
          format: date-time
    CreativeStatus:
      type: object
      required:
      - creativeVariationId
      - status
      - progress
      - imageUrl
      - lastUpdated
      - errorDetails
      properties:
        creativeVariationId:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
        progress:
          type: integer
          minimum: 0
          maximum: 100
        errorDetails:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
            message:
              type: string
        imageUrl:
          type: string
        thumbnailUrl:
          type: string
        lastUpdated:
          type: string
          format: date-time
    CampaignSummary:
      type: object
      required:
      - campaignId
      - name
      - createdAt
      - updatedAt
      properties:
        campaignId:
          type: string
          format: uuid
        name:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    BrandCreativesGroupedByCampaign:
      type: object
      required:
      - campaign
      - creatives
      properties:
        campaign:
          $ref: '#/components/schemas/CampaignSummary'
        creatives:
          type: array
          items:
            $ref: '#/components/schemas/CreativeDetails'
    Point:
      type: object
      required:
      - x
      - y
      properties:
        x:
          type: integer
          description: X-coordinate (pixel value from top-left).
        y:
          type: integer
          description: Y-coordinate (pixel value from top-left).
      example:
        x: 150
        y: 200
    BoundingBox:
      type: object
      required:
      - x1
      - y1
      - x2
      - y2
      properties:
        x1:
          type: integer
          description: X-coordinate of the top-left corner.
        y1:
          type: integer
          description: Y-coordinate of the top-left corner.
        x2:
          type: integer
          description: X-coordinate of the bottom-right corner.
        y2:
          type: integer
          description: Y-coordinate of the bottom-right corner.
      example:
        x1: 100
        y1: 150
        x2: 250
        y2: 300
    BrushStroke:
      type: object
      required:
      - points
      - radius
      - positive
      properties:
        points:
          type: array
          items:
            $ref: '#/components/schemas/Point'
          minItems: 1
          description: An ordered sequence of points representing the path of the
            brush stroke.
        radius:
          type: integer
          description: The radius of the brush in pixels (e.g., 8-24px).
          example: 12
          minimum: 1
        positive:
          type: boolean
          description: Whether the brush adds to the mask (`true`) or subtracts from
            it (`false`).
          example: true
    MaskInput:
      type: object
      properties:
        originalMaskId:
          type: string
          format: uuid
          nullable: true
          description: (Optional) The ID of the existing mask that this new mask is
            based on. Useful when editing or refining an existing mask.
          example: 223e4567-e89b-12d3-a456-426614174111
        points:
          type: array
          items:
            $ref: '#/components/schemas/Point'
          description: Optional array of points indicating the object to mask.
        boxes:
          type: array
          items:
            $ref: '#/components/schemas/BoundingBox'
          description: Optional array of bounding boxes indicating the object(s) to
            mask.
        brushStrokes:
          type: array
          items:
            $ref: '#/components/schemas/BrushStroke'
          minItems: 1
          description: Optional array of brush strokes to define or refine the mask.
      description: 'Input parameters for creating or updating a mask definition.

        At least one of `points`, `boxes`, or `brushStrokes` must be provided with
        at least one element in the array.

        '
    Canvas:
      type: object
      description: Canvas transformation configuration including resize, crop, padding,
        and rotation.
      required:
      - resize
      properties:
        resize:
          $ref: '#/components/schemas/CanvasResize'
        crop:
          allOf:
          - $ref: '#/components/schemas/CanvasCrop'
          nullable: true
          description: Optional crop parameters. Defaults to all zeros if not provided.
        padding:
          allOf:
          - $ref: '#/components/schemas/CanvasPadding'
          nullable: true
          description: Optional padding parameters. Defaults to all zeros if not provided.
        rotate:
          type: integer
          format: int32
          minimum: 0
          maximum: 360
          default: 0
          nullable: true
          description: Optional rotation angle in degrees (0-360). Defaults to 0.
          example: 0
    CanvasCrop:
      type: object
      description: Crop parameters - pixels to remove from each edge.
      properties:
        left:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Pixels to crop from left edge.
          example: 0
        right:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Pixels to crop from right edge.
          example: 0
        up:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Pixels to crop from top edge.
          example: 0
        down:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Pixels to crop from bottom edge.
          example: 0
    CanvasPadding:
      type: object
      description: Padding parameters - pixels to add to each edge.
      properties:
        left:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Padding pixels on left edge.
          example: 50
        right:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Padding pixels on right edge.
          example: 50
        up:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Padding pixels on top edge.
          example: 50
        down:
          type: integer
          format: int32
          minimum: 0
          default: 0
          description: Padding pixels on bottom edge.
          example: 50
    CanvasResize:
      type: object
      description: Resize dimensions for the canvas.
      required:
      - new_width
      - new_height
      properties:
        new_width:
          type: integer
          format: int32
          minimum: 100
          maximum: 4096
          description: Target width in pixels (100-4096).
          example: 1024
        new_height:
          type: integer
          format: int32
          minimum: 100
          maximum: 4096
          description: Target height in pixels (100-4096).
          example: 1024
    ReimaginePrompt:
      type: object
      description: Prompt object containing text and style for generation. Style is
        optional when prompt was pre-enhanced (promptIsEnhanced=true).
      required:
      - text
      properties:
        text:
          type: string
          description: The text prompt describing the desired context/environment.
          minLength: 1
          maxLength: 2500
          example: Product on a marble countertop with soft natural lighting
        style:
          allOf:
          - $ref: '#/components/schemas/ReimagineStyle'
          nullable: true
          description: Style for generation. Null when prompt was pre-enhanced.
    ReimagineStyle:
      type: string
      description: Visual style preset for the reimagination generation.
      enum:
      - photorealistic
      - painting
      - photograph
      - sketch
      - pastel painting
      - charcoal drawing
      - isometric 3D
      - close-up
      example: photorealistic
    ReimaginationInput:
      type: object
      description: Input for creating a new reimagination.
      required:
      - sourceAssetId
      - maskId
      - promptIsEnhanced
      - prompt
      - canvas
      properties:
        sourceAssetId:
          type: string
          format: uuid
          description: ID of the source image asset to reimagine.
          example: 550e8400-e29b-41d4-a716-446655440000
        maskId:
          type: string
          format: uuid
          description: ID of the confirmed mask (REQUIRED for canvas reimagination).
          example: 550e8400-e29b-41d4-a716-446655440001
        promptIsEnhanced:
          type: boolean
          description: 'Whether the prompt is pre-enhanced.

            - true: prompt.text contains the final prompt, use negativePrompt if provided

            - false: prompt.text + prompt.style sent to Modal for internal enhancement

            '
          example: false
        prompt:
          $ref: '#/components/schemas/CreateReimaginationPrompt'
        canvas:
          $ref: '#/components/schemas/Canvas'
        partner:
          $ref: '#/components/schemas/Partner'
    Mask:
      type: object
      required:
      - maskId
      - sourceAssetId
      - sourceAssetUrl
      - status
      - createdAt
      - updatedAt
      properties:
        maskId:
          type: string
          format: uuid
          description: Unique identifier for the mask.
        sourceAssetId:
          type: string
          format: uuid
          description: The ID of the source asset this mask is associated with.
        sourceAssetUrl:
          type: string
          format: url
          description: URL to the source asset image.
          example: https://cdn.example.com/assets/asset-123e4567.jpg
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          - confirmed
          description: Current status of the mask generation.
        maskUrl:
          type: string
          format: url
          nullable: true
          description: URL to the generated mask image (PNG format). Only present
            when status is 'completed' or 'confirmed'. Null otherwise.
          example: https://cdn.example.com/masks/mask-abcdef01-2345-6789-abcd-ef0123456789.png
        maskInputParameters:
          allOf:
          - $ref: '#/components/schemas/MaskInput'
          nullable: true
          description: 'The input parameters (points, boxes, strokes, originalMaskId)
            used to create or update this mask.

            Populated only if the `include=inputParameters` query parameter was provided
            in the request. Otherwise omitted or null.

            '
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update (e.g., when status changed).
        completedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when mask generation completed successfully.
        failedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when mask generation failed.
        confirmedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the mask was confirmed by the user via the confirm
            endpoint.
        errorCode:
          type: string
          nullable: true
          readOnly: true
          description: Error code when status is 'failed'. One of UserRequestError,
            ModelProviderError, NativeAdsSystemError.
          example: UserRequestError
        errorMessage:
          type: string
          nullable: true
          readOnly: true
          description: Error message when status is 'failed'. User-facing for UserRequestError/ModelProviderError;
            internal-only for NativeAdsSystemError.
          example: Source image could not be loaded. It may be missing, corrupted,
            or in an unsupported format.
    GeneratedImage:
      type: object
      required:
      - generatedImageId
      - status
      - prompt
      - width
      - height
      - liked
      - disliked
      - createdAt
      - updatedAt
      properties:
        generatedImageId:
          type: string
          format: uuid
          description: Unique identifier for this specific generated image variation.
        assetId:
          type: string
          format: uuid
          nullable: true
          description: The ID of the generated asset once the image is successfully
            created and stored. Null if generation is still pending or failed.
          example: 987e6543-e21b-12d3-a456-426614174999
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current status of this image generation.
        prompt:
          type: string
          description: The specific prompt used to generate this image.
        width:
          type: integer
          description: Width of the generated image in pixels.
        height:
          type: integer
          description: Height of the generated image in pixels.
        canvasKey:
          type: string
          description: Canvas key identifier for this variation.
          example: 1024x1024_c0-0-0-0_p0-0-0-0_r0
        imageUrl:
          type: string
          format: url
          nullable: true
          description: URL to the full-resolution generated image. Available when
            status is 'completed'.
          example: https://cdn.example.com/gen/genimg-1111-2222-3333-4444.jpg
        thumbnailUrl:
          type: string
          format: url
          nullable: true
          description: URL to a thumbnail version of the generated image. Available
            when status is 'completed'.
          example: https://cdn.example.com/gen/genimg-1111-2222-3333-4444-thumb.jpg
        liked:
          type: boolean
          default: false
          description: Indicates if the user has marked this image as liked.
        disliked:
          type: boolean
          default: false
          description: Indicates if the user has marked this image as disliked.
        createdAt:
          type: string
          format: date-time
          description: Timestamp when this variation job was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update (status change, like/dislike).
        generatedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the image generation completed successfully.
        failedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the image generation failed.
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking partner hardspec-compatibility and ML moderation
            warnings

            (NAT-1677). Empty/absent when the output matches the partner''s image
            specs,

            has no partner, or the partner has no image specs. DISTINCT from hard
            errors

            (see `error`) — a real policy violation / failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    ReimaginationGroup:
      type: object
      description: A reimagination group containing variations generated from a single
        prompt and canvas.
      required:
      - reimaginationGroupId
      - sourceAsset
      - maskId
      - prompt
      - canvas
      - status
      - variations
      - createdAt
      - updatedAt
      properties:
        reimaginationGroupId:
          type: string
          format: uuid
          description: Unique identifier for the reimagination group.
        sourceAsset:
          $ref: '#/components/schemas/AssetSummary'
        maskId:
          type: string
          format: uuid
          description: ID of the mask used for this reimagination.
        prompt:
          $ref: '#/components/schemas/ReimaginePrompt'
          description: The prompt object used for this generation group.
        canvas:
          $ref: '#/components/schemas/Canvas'
          description: The canvas configuration used for this generation group.
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current status of the reimagination group.
        variations:
          type: array
          items:
            $ref: '#/components/schemas/GeneratedImage'
          description: List of generated image variations.
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
          description: Error details if status is failed.
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        completedAt:
          type: string
          format: date-time
          nullable: true
    PaginatedReimaginationGroupList:
      type: object
      required:
      - data
      - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/ReimaginationGroup'
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    CreateReimaginationPrompt:
      type: object
      description: 'Prompt structure with conditional fields based on promptIsEnhanced.

        - When promptIsEnhanced=false: text and style are required

        - When promptIsEnhanced=true: text is required, negativePrompt is optional

        '
      required:
      - text
      properties:
        text:
          type: string
          minLength: 1
          maxLength: 2500
          description: The prompt text (original or refined).
          example: A product photographed on a clean marble countertop
        style:
          $ref: '#/components/schemas/ReimagineStyle'
          description: Required when promptIsEnhanced=false.
        negativePrompt:
          type: string
          nullable: true
          description: Optional, used when promptIsEnhanced=true, defaults to empty
            string.
          example: blurry, low quality, distorted
    CreateReimaginationPromptEnhancementRequest:
      type: object
      description: Request to create a reimagination prompt enhancement preview.
      required:
      - sourceAssetId
      - maskId
      - prompt
      - canvas
      properties:
        sourceAssetId:
          type: string
          format: uuid
          description: ID of the source image asset.
          example: 550e8400-e29b-41d4-a716-446655440000
        maskId:
          type: string
          format: uuid
          description: ID of the confirmed mask.
          example: 550e8400-e29b-41d4-a716-446655440001
        prompt:
          $ref: '#/components/schemas/ReimaginationPromptInput'
        canvas:
          $ref: '#/components/schemas/ReimaginationCanvas'
        partner:
          $ref: '#/components/schemas/Partner'
        useBrandDna:
          type: boolean
          nullable: true
          description: Whether to apply Brand DNA to prompt enhancement (defaults
            to true if omitted).
          example: true
    ReimaginationCanvas:
      type: object
      description: Canvas transformation parameters for reimagination prompt enhancement.
      required:
      - resize
      - crop
      - padding
      - rotate
      properties:
        resize:
          $ref: '#/components/schemas/ReimaginationCanvasResize'
        crop:
          $ref: '#/components/schemas/ReimaginationCanvasOffset'
        padding:
          $ref: '#/components/schemas/ReimaginationCanvasOffset'
        rotate:
          type: integer
          minimum: 0
          maximum: 360
          description: Rotation angle in degrees.
          example: 0
    ReimaginationCanvasOffset:
      type: object
      description: Offset values for crop or padding.
      required:
      - left
      - right
      - up
      - down
      properties:
        left:
          type: integer
          minimum: 0
          description: Left offset in pixels.
          example: 0
        right:
          type: integer
          minimum: 0
          description: Right offset in pixels.
          example: 0
        up:
          type: integer
          minimum: 0
          description: Up/top offset in pixels.
          example: 0
        down:
          type: integer
          minimum: 0
          description: Down/bottom offset in pixels.
          example: 0
    ReimaginationCanvasResize:
      type: object
      description: Resize dimensions for the canvas.
      required:
      - newWidth
      - newHeight
      properties:
        newWidth:
          type: integer
          minimum: 32
          description: New width after resize.
          example: 1024
        newHeight:
          type: integer
          minimum: 32
          description: New height after resize.
          example: 1024
    ReimaginationPromptEnhancementResponse:
      type: object
      description: Response for a reimagination prompt enhancement request.
      required:
      - promptEnhancementId
      - brandId
      - sourceAssetId
      - maskId
      - originalPrompt
      - status
      - useBrandDna
      - createdAt
      - updatedAt
      properties:
        promptEnhancementId:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the prompt enhancement.
          example: 123e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
          readOnly: true
          description: ID of the brand.
          example: 223e4567-e89b-12d3-a456-426614174000
        sourceAssetId:
          type: string
          format: uuid
          readOnly: true
          description: ID of the source image asset.
          example: 550e8400-e29b-41d4-a716-446655440000
        maskId:
          type: string
          format: uuid
          readOnly: true
          description: ID of the mask.
          example: 550e8400-e29b-41d4-a716-446655440001
        partner:
          $ref: '#/components/schemas/Partner'
        useBrandDna:
          type: boolean
          readOnly: true
          description: Whether Brand DNA was applied to this prompt enhancement.
          example: true
        originalPrompt:
          allOf:
          - $ref: '#/components/schemas/ReimaginationPromptInput'
          readOnly: true
          description: The original prompt submitted for enhancement.
        refinedPrompt:
          type: string
          nullable: true
          readOnly: true
          description: The AI-enhanced prompt (available when status is 'completed').
          example: A premium skincare product elegantly displayed on polished marble...
        negativePrompt:
          type: string
          nullable: true
          readOnly: true
          description: The negative prompt for generation (available when status is
            'completed').
          example: blurry, low quality, distorted
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current status of the enhancement.
          example: pending
        errorCode:
          type: string
          nullable: true
          readOnly: true
          description: Error code if status is 'failed'.
          example: ENHANCEMENT_FAILED
        errorMessage:
          type: string
          nullable: true
          readOnly: true
          description: Error message if status is 'failed'.
          example: Failed to enhance prompt due to content policy violation
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp.
          example: '2024-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          readOnly: true
          description: Last update timestamp.
          example: '2024-01-01T00:00:00Z'
        completedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Completion timestamp (if completed).
          example: '2024-01-01T00:00:30Z'
        failedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Failure timestamp (if failed).
          example: '2024-01-01T00:00:30Z'
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking ML moderation content warnings (NAT-1677). Empty/absent
            when

            the enhanced prompt raises no content flags. DISTINCT from hard errors

            (see `errorCode`/`errorMessage`) — a real failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    ReimaginationPromptInput:
      type: object
      description: Prompt input with text and style (for enhancement preview).
      required:
      - text
      - style
      properties:
        text:
          type: string
          minLength: 1
          maxLength: 2500
          description: The prompt text to enhance.
          example: A product photographed on a clean marble countertop
        style:
          $ref: '#/components/schemas/ReimagineStyle'
    AdaptationInput:
      type: object
      required:
      - sourceAssetId
      - title
      - dimensions
      properties:
        title:
          type: string
          description: Title of the creative adaptation.
        description:
          type: string
          description: Description of the creative adaptation.
          nullable: true
        sourceAssetId:
          type: string
          format: uuid
          description: The ID of the original source *video* asset. Needs to be a
            video.
          example: 123e4567-e89b-12d3-a456-426614174000
        logoAssetId:
          type: string
          format: uuid
          description: The ID of the *logo* asset.
          example: 223e4567-e89b-12d3-a456-426614174001
        dimensions:
          type: array
          items:
            $ref: '#/components/schemas/Dimension'
          minItems: 1
          description: One or more target dimensions (width, height) for the generated
            variations. A variation will be generated for each dimension.
        partner:
          $ref: '#/components/schemas/Partner'
    AdaptationGeneratedVariation:
      type: object
      required:
      - generatedVariationId
      - status
      - width
      - height
      - liked
      - disliked
      - createdAt
      - updatedAt
      properties:
        generatedVariationId:
          type: string
          format: uuid
          description: Unique identifier for this specific generated variation.
        assetId:
          type: string
          format: uuid
          nullable: true
          description: The ID of the generated asset once the image is successfully
            created and stored. Null if generation is still pending or failed.
          example: 987e6543-e21b-12d3-a456-426614174999
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current status of this variation generation.
        width:
          type: integer
          description: Width of the generated variation in pixels.
        height:
          type: integer
          description: Height of the generated variation in pixels.
        variationUrl:
          type: string
          format: url
          nullable: true
          description: URL to the full-resolution generated variation. Available when
            status is 'completed'.
          example: https://cdn.example.com/gen/genimg-1111-2222-3333-4444.jpg
        thumbnailUrl:
          type: string
          format: url
          nullable: true
          description: URL to a thumbnail version of the generated variation. Available
            when status is 'completed'.
          example: https://cdn.example.com/gen/genimg-1111-2222-3333-4444-thumb.jpg
        liked:
          type: boolean
          default: false
          description: Indicates if the user has marked this variation as liked.
        disliked:
          type: boolean
          default: false
          description: Indicates if the user has marked this variation as disliked.
        createdAt:
          type: string
          format: date-time
          description: Timestamp when this variation job was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update (status change, like/dislike).
        generatedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the variation generation completed successfully.
        failedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the variation generation failed.
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
          description: 'Classified error from this variation''s generation attempt.

            Populated when status is ''failed''; null otherwise.

            error.error.code is one of {UserRequestError, ModelProviderError, NativeAdsSystemError}.

            '
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking partner hardspec-compatibility and ML moderation
            warnings

            (NAT-1677). Empty/absent when the output matches the partner''s image
            specs,

            has no partner, or the partner has no image specs. DISTINCT from hard
            errors

            (see `error`) — a real policy violation / failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    CreativeAdaptation:
      type: object
      required:
      - creativeAdaptationId
      - title
      - brandId
      - sourceAsset
      - status
      - createdAt
      - updatedAt
      - dimensions
      - variations
      properties:
        creativeAdaptationId:
          type: string
          format: uuid
          description: Unique identifier for this creative adaptation request group.
        title:
          type: string
          description: Title of the creative adaptation.
        description:
          type: string
          description: Description of the creative adaptation.
          nullable: true
        brandId:
          type: string
          format: uuid
          description: The ID of the brand associated with this creative adaptation.
        sourceAsset:
          $ref: '#/components/schemas/AssetSummary'
        logoAsset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Overall status of the creative adaptation, derived from its
            variations.
        createdAt:
          type: string
          format: date-time
          description: Timestamp when the creative adaptation was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update to the group or its variations.
        completedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the creative adaptation was completed
        failedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the creative adaptation failed
        dimensions:
          type: array
          items:
            $ref: '#/components/schemas/Dimension'
          description: The dimensions used for this creative adaptation.
        variations:
          type: array
          items:
            $ref: '#/components/schemas/AdaptationGeneratedVariation'
          description: List of all generated variations within this creative adaptation
            (one per dimension).
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
    PaginatedCreativeAdapatationList:
      type: object
      required:
      - data
      - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/CreativeAdaptation'
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    VideoModel:
      type: string
      enum:
      - veo-3.1
      - veo-3.1-fast
      - kling-v3-pro
      - kling-v3-omni-pro
      - grok-imagine-video
      - seedance-1.5-pro
      - seedance-2.0-pro
      - pixverse-v6
      - optimized
      description: 'The AI model to use for video generation.

        Frontend controls which models are visible to users.

        - veo-3.1: Google Veo 3.1 (higher quality, slower)

        - veo-3.1-fast: Google Veo 3.1 Fast (faster generation)

        - kling-v3-pro: Kling V3 Pro

        - kling-v3-omni-pro: Kling V3 Omni (O3) Pro

        - grok-imagine-video: Grok Imagine Video

        - seedance-1.5-pro: Seedance 1.5 Pro

        - seedance-2.0-pro: Seedance 2.0 Pro

        - pixverse-v6: PixVerse V6 (start-frame only, 15s, 1080p)

        - optimized: ClipForge multi-clip long-video pipeline (6–30s).

        '
    VideoGenerationRequest:
      type: object
      required:
      - startImageAssetId
      - userPrompts
      - dimension
      properties:
        startImageAssetId:
          type: string
          format: uuid
          description: The ID of the original source asset of the image that will
            be used as the video start frame.
          example: 123e4567-e89b-12d3-a456-426614174000
        endImageAssetId:
          type: string
          format: uuid
          description: The ID of the asset to use as the video end frame. Optional.
            Not supported by all models.
          example: 123e4567-e89b-12d3-a456-426614174000
        intermediateImageAssetIds:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          maxItems: 5
          description: 'Ordered intermediate frame assets for the optimized model.
            Optional (omit for none). Order is temporal. Per-duration min/max enforced
            server-side. Rejected for non-optimized models.

            '
        userPrompts:
          type: array
          items:
            type: string
            maxLength: 1000
            minLength: 1
          minItems: 1
          description: One or more text prompts describing the desired context/environment.
          example:
          - Product on a marble countertop
          - Product in a forest clearing
        dimension:
          $ref: '#/components/schemas/Dimension'
        enableAudio:
          type: boolean
          default: false
          description: Whether to generate audio for the video. Defaults to false.
        model:
          allOf:
          - $ref: '#/components/schemas/VideoModel'
          default: veo-3.1
          description: The AI model to use for video generation. Defaults to `veo-3.1`.
        duration:
          type: integer
          minimum: 1
          description: Desired video duration in seconds. Optional; when omitted the
            backend falls back to a per-model default. Backend currently does not
            enforce a per-model allow-list.
          example: 8
        promptIsEnhanced:
          type: boolean
          description: Whether the prompt was enhanced via the prompt enhancement
            preview flow.
          default: false
        useBrandDna:
          type: boolean
          default: false
          description: Whether to apply Brand DNA to inline prompt enhancement during
            video generation. Defaults to false.
        partner:
          $ref: '#/components/schemas/Partner'
    GeneratedVideo:
      type: object
      required:
      - generatedVideoId
      - status
      - prompt
      - width
      - height
      - duration
      - enableAudio
      - model
      - createdAt
      - updatedAt
      properties:
        generatedVideoId:
          type: string
          format: uuid
          description: Unique identifier for this specific generated video variation.
        assetId:
          type: string
          format: uuid
          nullable: true
          description: The ID of the generated asset once the video is successfully
            created and stored. Null if generation is still pending or failed.
          example: 987e6543-e21b-12d3-a456-426614174999
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current status of this video generation.
        prompt:
          type: string
          description: The specific prompt used to generate this video.
        width:
          type: integer
          description: Width of the generated video in pixels.
        height:
          type: integer
          description: Height of the generated video in pixels.
        videoUrl:
          type: string
          format: url
          nullable: true
          description: URL to the full-resolution generated video. Available when
            status is 'completed'.
          example: https://cdn.example.com/gen/genimg-1111-2222-3333-4444.jpg
        previewUrl:
          type: string
          format: url
          nullable: true
          description: URL to the start image (source asset) used as a preview thumbnail
            for the generated video. Available when status is 'completed'.
          example: https://cdn.example.com/assets/start-image-1111-2222.png
        enableAudio:
          type: boolean
          default: false
          description: Whether audio was enabled for this generated video.
        model:
          $ref: '#/components/schemas/VideoModel'
        duration:
          type: integer
          description: Duration of the video in seconds.
        createdAt:
          type: string
          format: date-time
          description: Timestamp when this variation job was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update (status change).
        generatedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the video generation completed successfully.
        failedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when the video generation failed.
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
    GeneratedVideosGroup:
      type: object
      required:
      - generatedVideosGroupId
      - sourceAsset
      - status
      - createdAt
      - updatedAt
      - prompt
      - dimension
      - enableAudio
      - useBrandDna
      - model
      - duration
      - variations
      - intermediateFrameAssets
      properties:
        generatedVideosGroupId:
          type: string
          format: uuid
          description: Unique identifier for this generated videos request group.
        sourceAsset:
          $ref: '#/components/schemas/AssetSummary'
        endFrameAsset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
          description: The end frame image asset, if one was used for this video group.
        intermediateFrameAssets:
          type: array
          items:
            $ref: '#/components/schemas/AssetSummary'
          description: Ordered intermediate frame assets used for this group (optimized
            model). Empty if none.
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Overall status of the generated videos group, derived from
            its variations.
        createdAt:
          type: string
          format: date-time
          description: Timestamp when the generated videos group was created.
        updatedAt:
          type: string
          format: date-time
          description: Timestamp of the last update to the group or its variations.
        completedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when this group was completed.
        failedAt:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when this group failed.
        prompt:
          type: string
          description: The prompt used for this generation group.
        dimension:
          $ref: '#/components/schemas/Dimension'
        enableAudio:
          type: boolean
          default: false
          description: Whether audio generation was enabled for this group.
        useBrandDna:
          type: boolean
          description: Whether Brand DNA was applied to inline prompt enhancement
            for this video group.
        model:
          $ref: '#/components/schemas/VideoModel'
        duration:
          type: integer
          minimum: 1
          description: Video duration in seconds for this generation group.
        variations:
          type: array
          items:
            $ref: '#/components/schemas/GeneratedVideo'
          description: List of all generated videos variations within this group (one
            per prompt).
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
    PaginatedGeneratedVideosGroupList:
      type: object
      required:
      - data
      - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/GeneratedVideosGroup'
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    CreateImageToVideoPromptEnhancementRequest:
      type: object
      description: Request to create an image-to-video prompt enhancement preview.
      required:
      - startFrameAssetId
      - originalPrompt
      - aspectRatio
      - model
      properties:
        startFrameAssetId:
          type: string
          format: uuid
          description: ID of the start frame image asset.
          example: 550e8400-e29b-41d4-a716-446655440000
        endFrameAssetId:
          type: string
          format: uuid
          description: ID of the end frame image asset. Optional.
          example: 550e8400-e29b-41d4-a716-446655440000
        intermediateFrameAssetIds:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          maxItems: 5
          description: 'Ordered intermediate frame assets for optimized-model enhancement.
            Optional. Fed to the enhancer alongside start/end. Rejected for non-optimized
            models. (No per-duration min/max enforced here — preview is exploratory;
            see generation rules.)

            '
        originalPrompt:
          type: string
          minLength: 1
          maxLength: 2500
          description: The text prompt to enhance for video generation.
          example: The product slowly rotates on a marble countertop with soft natural
            lighting
        aspectRatio:
          type: string
          enum:
          - '16:9'
          - '9:16'
          description: The target aspect ratio for the video.
          example: '16:9'
        model:
          allOf:
          - $ref: '#/components/schemas/VideoModel'
          description: The target video generation model.
        duration:
          type: integer
          minimum: 1
          description: Target video duration (s). Lets the enhancer detect the long-video
            (>8s) ClipForge case.
        enableAudio:
          type: boolean
          default: false
          description: Whether audio is enabled -- controls audio guidance in prompt
            enhancement. Defaults to false.
        useBrandDna:
          type: boolean
          default: false
          description: Whether to apply Brand DNA to prompt enhancement. Defaults
            to false. FE sends explicitly based on Brand DNA toggle state.
    ImageToVideoPromptEnhancementResponse:
      type: object
      description: Response for an image-to-video prompt enhancement request.
      required:
      - promptEnhancementId
      - brandId
      - startFrameAssetId
      - intermediateFrameAssetIds
      - originalPrompt
      - aspectRatio
      - model
      - status
      - enableAudio
      - useBrandDna
      - createdAt
      - updatedAt
      properties:
        promptEnhancementId:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the prompt enhancement.
          example: 123e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
          readOnly: true
          description: ID of the brand.
          example: 223e4567-e89b-12d3-a456-426614174000
        startFrameAssetId:
          type: string
          format: uuid
          readOnly: true
          description: ID of the start frame image asset.
          example: 550e8400-e29b-41d4-a716-446655440000
        endFrameAssetId:
          type: string
          format: uuid
          nullable: true
          readOnly: true
          description: ID of the end frame image asset, if provided.
        intermediateFrameAssetIds:
          type: array
          items:
            type: string
            format: uuid
          readOnly: true
          description: Ordered intermediate frame assets used for this enhancement
            (optimized model). Empty array if none.
        originalPrompt:
          type: string
          readOnly: true
          description: The original prompt submitted for enhancement.
          example: The product slowly rotates on a marble countertop with soft natural
            lighting
        aspectRatio:
          type: string
          readOnly: true
          description: The target aspect ratio for the video.
          example: '16:9'
        model:
          type: string
          readOnly: true
          description: The target video generation model.
          example: veo-3.1
        duration:
          type: integer
          minimum: 1
          nullable: true
          readOnly: true
          description: Target video duration (s), if provided.
        enhancedPrompt:
          type: string
          nullable: true
          readOnly: true
          description: The AI-enhanced prompt (available when status is 'completed').
          example: A premium skincare product elegantly rotates on a polished Calacatta
            marble countertop, bathed in warm diffused golden-hour light filtering
            through sheer curtains, with subtle reflections dancing across the marble
            surface...
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current status of the enhancement.
          example: pending
        errorCode:
          type: string
          nullable: true
          readOnly: true
          description: Error code if status is 'failed'.
          example: ENHANCEMENT_FAILED
        errorMessage:
          type: string
          nullable: true
          readOnly: true
          description: Error message if status is 'failed'.
          example: Failed to enhance prompt due to content policy violation
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp.
          example: '2024-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          readOnly: true
          description: Last update timestamp.
          example: '2024-01-01T00:00:00Z'
        completedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Completion timestamp (if completed).
          example: '2024-01-01T00:00:30Z'
        failedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Failure timestamp (if failed).
          example: '2024-01-01T00:00:30Z'
        enableAudio:
          type: boolean
          readOnly: true
          description: Whether audio guidance was included in this prompt enhancement.
        useBrandDna:
          type: boolean
          readOnly: true
          description: Whether Brand DNA was applied to this prompt enhancement.
    CreateCountryRequest:
      type: object
      required:
      - country_code
      properties:
        country_code:
          type: string
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 country code.
          example: CA
    CreateCountryResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/Organization'
    BillingPeriod:
      type: object
      properties:
        start:
          type: string
          format: date-time
          description: Start of current billing period
          example: '2025-12-01T00:00:00Z'
        end:
          type: string
          format: date-time
          description: End of current billing period
          example: '2025-12-31T23:59:59Z'
      required:
      - start
      - end
      description: Current billing period information
    PoolUsageInfo:
      type: object
      properties:
        usage:
          type: integer
          minimum: 0
          description: Current usage count
          example: 23
        cap:
          type: integer
          minimum: 0
          description: Maximum allowed uses (0 means unlimited)
          example: 1000
        remaining:
          type: integer
          minimum: 0
          description: Remaining uses (cap - usage)
          example: 977
        unlimited:
          type: boolean
          description: True if cap is 0 (no limit)
          example: false
      required:
      - usage
      - cap
      - remaining
      - unlimited
    ThresholdAlert:
      type: object
      properties:
        pool:
          type: string
          description: Pool that crossed the threshold (images or videos)
          example: images
        threshold:
          type: string
          description: Threshold level crossed (10_percent or zero)
          example: 10_percent
      required:
      - pool
      - threshold
    FeatureUsageData:
      type: object
      properties:
        pools:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/PoolUsageInfo'
          description: Map of pool keys (images, videos) to their usage information
        threshold_alert:
          $ref: '#/components/schemas/ThresholdAlert'
          nullable: true
        billing_period:
          $ref: '#/components/schemas/BillingPeriod'
        plan_slug:
          type: string
          example: pro
      required:
      - pools
      - billing_period
      - plan_slug
      description: Pool-based usage data with billing period
    FeatureUsageResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/FeatureUsageData'
      required:
      - status
      - data
      description: Response containing feature usage information
    Organization:
      type: object
      properties:
        id:
          type: string
          format: uuid
          example: b5f5d8f8-2c7b-4e2c-a5b4-4c2a8a6b95b7
        name:
          type: string
          example: Acme Corp
        clerkOrgId:
          type: string
          example: org_2kN9bA2eXqZzAbCd
        region:
          type: string
          description: 'Pricing region for billing. Derived from country_code on the

            server; preserved here for audit. Phase 3 introduced

            country_code as the primary pricing key.

            '
          enum:
          - us_ca
          - eu
          - latam
          example: us_ca
        country_code:
          type: string
          pattern: ^[A-Z]{2}$
          description: 'ISO 3166-1 alpha-2 country code. Drives Stripe price ID lookup

            via the server-side CountryToRegion map.

            '
          example: US
          nullable: true
        parent_organization_id:
          type: string
          format: uuid
          description: 'Parent organization grouping country-level orgs under one

            advertiser. Set by the server on signup or add-country.

            '
          example: 9b3d6a91-7b3c-4f1c-9c3a-5b4a9c2f3e1a
          nullable: true
        billing_via_organization_id:
          type: string
          format: uuid
          nullable: true
          description: 'When set, this org piggy-backs on the linked org''s

            subscription and has no Stripe customer or sub of its own.

            Set/cleared by ops via Slack bot (/bundle, /unbundle,

            /reanchor).

            '
          example: null
        partner:
          type: string
          nullable: true
          example: walmart
        createdAt:
          type: string
          format: date-time
          example: '2025-08-14T09:00:00Z'
        updatedAt:
          type: string
          format: date-time
          example: '2025-08-14T09:10:00Z'
      required:
      - id
      - name
      - clerkOrgId
      - region
      - createdAt
      - updatedAt
    CreateOrganizationRequest:
      type: object
      required:
      - companyName
      - country_code
      properties:
        companyName:
          type: string
          description: Name of the organization (becomes the parent_organization name).
          example: Acme Inc.
        country_code:
          type: string
          pattern: ^[A-Z]{2}$
          description: 'ISO 3166-1 alpha-2 country code. Required. Server derives
            the

            pricing region from this via the CountryToRegion map; the

            Organization.region field is set as a derived audit value.

            '
          example: US
        partner:
          $ref: '#/components/schemas/PartnerEnum'
    UpdateOrganizationRequest:
      type: object
      description: 'Updates a mutable subset of organization fields. All fields are

        optional; only fields present in the payload are applied. Billing

        Phase 3 added country_code mutability with a piggy-back guard.

        '
      properties:
        partner:
          $ref: '#/components/schemas/PartnerEnum'
        country_code:
          type: string
          pattern: ^[A-Z]{2}$
          description: 'ISO 3166-1 alpha-2 country code. Server re-derives the pricing

            region. Rejected with 409 when the org is piggy-backing on

            another org''s subscription (unbundle first). Note that the

            subscription.region snapshot may lag until the next checkout

            or webhook event.

            '
          example: CA
      additionalProperties: false
    PartnerEnum:
      type: string
      nullable: true
      description: The partner associated with the organization.
      enum:
      - Walmart Connect
      - ''
    UsageLimitExceededError:
      type: object
      properties:
        requestId:
          type: string
          format: uuid
          description: Request ID for tracking
        error:
          type: object
          properties:
            code:
              type: string
              example: USAGE_LIMIT_EXCEEDED
              description: Error code
            message:
              type: string
              example: You have reached your monthly limit for reimagine generation.
              description: Human-readable error message
            details:
              type: object
              properties:
                feature:
                  type: string
                  description: Feature key that exceeded limit
                  example: reimagine
                capType:
                  type: string
                  description: Cap type that exceeded limit (e.g., generation, training)
                  example: generation
                limit:
                  type: integer
                  description: Maximum allowed uses
                  example: 50
                used:
                  type: integer
                  description: Current usage count
                  example: 50
                resetsAt:
                  type: string
                  format: date-time
                  nullable: true
                  description: When usage resets
                  example: '2025-12-31T23:59:59Z'
              required:
              - feature
              - capType
              - limit
              - used
              - resetsAt
          required:
          - code
          - message
          - details
      required:
      - error
      description: Error response when usage limit is exceeded
    PlanInfo:
      type: object
      properties:
        slug:
          type: string
          example: pro
        name:
          type: string
          example: Pro
        price:
          type: number
          format: double
          example: 1995
        currency:
          type: string
          example: usd
        image_cap:
          type: integer
          description: 0 means unlimited
          example: 0
        video_cap:
          type: integer
          example: 500
        seat_limit:
          type: integer
          example: 3
        includes_fine_tuning:
          type: boolean
        includes_brand_dna:
          type: boolean
    BillingPlansResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/PlanInfo'
    CreateCheckoutRequest:
      type: object
      required:
      - plan_slug
      - region
      - success_url
      - cancel_url
      properties:
        plan_slug:
          type: string
          enum:
          - starter
          - pro
          - unlimited
        region:
          type: string
          enum:
          - us_ca
          - eu
          - latam
        promo_code:
          type: string
          nullable: true
        auto_recharge:
          type: boolean
          default: false
        success_url:
          type: string
        cancel_url:
          type: string
    CreateCheckoutResponse:
      type: object
      properties:
        status:
          type: string
        data:
          $ref: '#/components/schemas/CheckoutData'
    CheckoutData:
      type: object
      properties:
        checkout_url:
          type: string
        session_id:
          type: string
    DirectSubscribeRequest:
      type: object
      required:
      - plan_slug
      - region
      - promo_code
      properties:
        plan_slug:
          type: string
        region:
          type: string
        promo_code:
          type: string
    SubscriptionData:
      type: object
      properties:
        id:
          type: string
          format: uuid
        plan_slug:
          type: string
        plan_name:
          type: string
        subscription_status:
          type: string
          enum:
          - active
          - past_due
          - canceled
          - trialing
          - incomplete
        region:
          type: string
          description: 'Historical pricing region snapshot from the time the

            subscription was created. Not updated when the org''s

            country_code changes; see organizations.country_code for the

            current pricing key.

            '
        country_code:
          type: string
          pattern: ^[A-Z]{2}$
          nullable: true
          description: 'Country of the org this subscription resolves to. For

            piggy-back orgs, this is the paying country.

            '
          example: US
        parent_organization_id:
          type: string
          format: uuid
          nullable: true
          description: Parent organization grouping country orgs.
        billing_via_organization_id:
          type: string
          format: uuid
          nullable: true
          description: 'Non-null only when this subscription is being read from a

            piggy-back org''s context, indicating the paying org. The

            response data itself comes from the paying org''s

            subscription.

            '
        custom_price_cents:
          type: integer
          nullable: true
          description: 'Enterprise override price set via ops Slack bot

            (/setprice, /bundle). When set, plan changes are blocked;

            see can_change_plan.

            '
          example: 700000
        can_change_plan:
          type: boolean
          description: 'False for piggy-back orgs, paying subs with piggy-backers,

            or subs with custom_price_cents set. Frontend hides the

            Upgrade button when false.

            '
        can_cancel:
          type: boolean
          description: 'False for piggy-back orgs (they have no own sub to cancel).

            Frontend hides the Cancel button when false.

            '
        can_manage_payment:
          type: boolean
          description: 'False for piggy-back orgs (they have no Stripe customer of

            their own). Frontend hides Customer Portal and Edit Payment

            Method when false.

            '
        auto_recharge:
          type: boolean
        cancel_at_period_end:
          type: boolean
        billing_period_start:
          type: string
          format: date-time
          nullable: true
        billing_period_end:
          type: string
          format: date-time
          nullable: true
        image_usage:
          type: integer
        image_cap:
          type: integer
          description: Resolved cap (override or plan default). 0 = unlimited.
        video_usage:
          type: integer
        video_cap:
          type: integer
        lockout_mode:
          type: string
          enum:
          - none
          - read_only
          - full_lockout
        hide_billing:
          type: boolean
          description: True when no Stripe subscription is attached (org on manual
            invoicing or internal). Frontend should hide Manage Billing, Renew, Cancel,
            Resume, and Auto-recharge controls.
    SubscriptionResponse:
      type: object
      properties:
        status:
          type: string
        data:
          nullable: true
          allOf:
          - $ref: '#/components/schemas/SubscriptionData'
    UpgradeRequest:
      type: object
      required:
      - plan_slug
      properties:
        plan_slug:
          type: string
          enum:
          - pro
          - unlimited
        success_url:
          type: string
        cancel_url:
          type: string
    ValidatePromoRequest:
      type: object
      required:
      - code
      properties:
        code:
          type: string
          example: SUMMER20
    ValidatePromoData:
      type: object
      properties:
        valid:
          type: boolean
        type:
          type: string
          enum:
          - discount
          - bogo
        discount_percent:
          type: integer
          nullable: true
        allowed_plans:
          type: array
          items:
            type: string
        requires_payment_method:
          type: boolean
          nullable: true
        error_reason:
          type: string
          nullable: true
    ValidatePromoResponse:
      type: object
      properties:
        status:
          type: string
        data:
          $ref: '#/components/schemas/ValidatePromoData'
    PortalSessionData:
      type: object
      properties:
        portal_url:
          type: string
    PortalSessionResponse:
      type: object
      properties:
        status:
          type: string
        data:
          $ref: '#/components/schemas/PortalSessionData'
    AutoRechargeRequest:
      type: object
      required:
      - enabled
      properties:
        enabled:
          type: boolean
    SyncResultData:
      type: object
      properties:
        total:
          type: integer
        updated:
          type: integer
        errors:
          type: integer
    SyncResultResponse:
      type: object
      properties:
        status:
          type: string
        data:
          $ref: '#/components/schemas/SyncResultData'
    Country:
      type: object
      required:
      - code
      - name
      properties:
        code:
          type: string
          pattern: ^[A-Z]{2}$
          example: US
        name:
          type: string
          example: United States
    BillingCountriesResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/Country'
    Dimension:
      type: object
      required:
      - width
      - height
      properties:
        width:
          type: integer
          description: Width of the image in pixels.
          example: 1024
        height:
          type: integer
          description: Height of the image in pixels.
          example: 1024
    Error:
      description: Standard error response
      type: object
      required:
      - error
      - requestId
      properties:
        error:
          $ref: '#/components/schemas/ErrorError'
        requestId:
          type: string
          format: uuid
          description: Unique identifier for the request, useful for tracing.
    AssetSummary:
      type: object
      required:
      - assetId
      - assetType
      - previewUrl
      - assetUrl
      properties:
        assetId:
          type: string
          format: uuid
          description: The ID of the asset.
        assetType:
          type: string
          enum:
          - image
          - logo
          - video
          - document
          - environment
        previewUrl:
          type: string
          format: url
          nullable: true
          description: URL to the preview of the asset.
          example: https://cdn.example.com/assets/asset-123e4567-thumb.jpg
        assetUrl:
          type: string
          format: url
          nullable: true
          description: URL to the asset.
          example: https://cdn.example.com/assets/asset-123e4567-img.jpg
    PaginationInfo:
      type: object
      required:
      - currentPage
      - totalPages
      - totalItems
      - itemsPerPage
      properties:
        currentPage:
          type: integer
        totalPages:
          type: integer
        totalItems:
          type: integer
        itemsPerPage:
          type: integer
    Partner:
      type: string
      description: Partner (retail-media network) slug. `default` means no partner.
      enum:
      - default
      - walmart
      - chewy
      x-enum-varnames:
      - PARTNER_DEFAULT
      - PARTNER_WALMART
      - PARTNER_CHEWY
      example: default
    ContentType:
      type: string
      description: Content-type (ad placement family) slug. Image content types only
        (NAT-1677).
      enum:
      - meta_image
      - meta_carousel
      - meta_collection
      - sponsored_brand_logo
      - offsite_display
      x-enum-varnames:
      - CONTENT_TYPE_META_IMAGE
      - CONTENT_TYPE_META_CAROUSEL
      - CONTENT_TYPE_META_COLLECTION
      - CONTENT_TYPE_SPONSORED_BRAND_LOGO
      - CONTENT_TYPE_OFFSITE_DISPLAY
      example: meta_image
    WarningSeverity:
      type: string
      description: 'Severity of a non-blocking generation warning. `error` is the
        legacy Walmart

        hardspec validation default; `warning` is the softer partner-compatibility
        signal.

        '
      enum:
      - warning
      - error
      x-enum-varnames:
      - WARNING_SEVERITY_WARNING
      - WARNING_SEVERITY_ERROR
      example: warning
    GenerationWarning:
      type: object
      required:
      - code
      - message
      - severity
      properties:
        code:
          type: string
          description: 'Machine-readable warning code. Reserved codes (NAT-1677):

            HARDSPEC_DIMENSIONS, HARDSPEC_ASPECT_MISMATCH, HARDSPEC_FORMAT,

            HARDSPEC_FILE_SIZE, HARDSPEC_TEXT_LIMIT, plus the ML moderation content

            code CONTENT_MODERATION (keywords/tone/promo-copy; placeholder

            MODERATION_CONTENT_FLAGGED noted in the API model, exact slug TBD with
            FE).

            '
          example: HARDSPEC_ASPECT_MISMATCH
        message:
          type: string
          description: Human-readable warning message.
          example: not compatible with chewy, use creative with chewy template to
            fix, or resize.
        severity:
          $ref: '#/components/schemas/WarningSeverity'
        layerId:
          type: string
          nullable: true
          description: 'Optional. For a per-layer compose warning, the template layer''s
            existing

            required `id` (template_document schema.json:77). Null/omitted for doc-level

            warnings and for raw image-generation warnings (no layer concept). Validation

            results are NEVER stored inside the document JSON.

            '
        field:
          type: string
          nullable: true
          description: Optional. The offending field on the layer (e.g. "text"). Omitted
            for doc-level warnings.
    ResizeOffsets:
      type: object
      required:
      - left
      - right
      - top
      - bottom
      properties:
        left:
          type: integer
          description: Left offset in pixels (negative = crop inward, positive = extend
            outward)
          example: 0
        right:
          type: integer
          description: Right offset in pixels (negative = crop inward, positive =
            extend outward)
          example: 100
        top:
          type: integer
          description: Top offset in pixels (negative = crop inward, positive = extend
            outward)
          example: 0
        bottom:
          type: integer
          description: Bottom offset in pixels (negative = crop inward, positive =
            extend outward)
          example: 0
      additionalProperties: false
    GenerativeResizeRequest:
      type: object
      required:
      - source_type
      - group_id
      - source_variation_id
      - offsets
      - resize
      properties:
        source_type:
          type: string
          enum:
          - creative_variation
          - reimagination
          - adaptation
          - scene_forge
          description: Type of source variation to resize (determines which output
            table to use and where to fetch the asset_id from)
          example: creative_variation
        group_id:
          type: string
          format: uuid
          description: ID of the group where the resized image will be added (themeId
            for creative_variation, reimaginationGroupId for reimagination, creativeAdaptationId
            for adaptation, sceneForgeId for scene_forge)
          example: 123e4567-e89b-12d3-a456-426614174001
        source_variation_id:
          type: string
          format: uuid
          description: ID of the specific variation/image to resize (must be completed
            status). The asset_id will be fetched from this variation.
          example: 123e4567-e89b-12d3-a456-426614174002
        offsets:
          $ref: '#/components/schemas/ResizeOffsets'
          description: Pixel offsets for generative fill guidance (where to extend)
        prompt:
          type: string
          nullable: true
          description: Optional prompt for generative fill when extending the image
          example: Continue the background seamlessly
        resize:
          $ref: '#/components/schemas/Dimension'
          description: 'Target output dimensions (REQUIRED). The output will be exactly
            these dimensions.

            Offsets guide the generative fill but do not determine output size.

            '
          example:
            width: 1200
            height: 800
      additionalProperties: false
    GenerativeResizeResponse:
      type: object
      required:
      - workflow_id
      - status
      - placeholder_id
      properties:
        workflow_id:
          type: string
          format: uuid
          description: ID of the created workflow for tracking progress
          example: 123e4567-e89b-12d3-a456-426614174003
        status:
          type: string
          enum:
          - pending
          description: Initial status of the workflow (always 'pending' on creation)
          example: pending
        placeholder_id:
          type: string
          format: uuid
          description: ID of the placeholder record created immediately (will be updated
            when workflow completes). Frontend should poll existing list endpoints
            to see when this placeholder is updated with the actual image.
          example: 123e4567-e89b-12d3-a456-426614174004
      additionalProperties: false
    IdentifyReplaceRequest:
      type: object
      required:
      - source_type
      - group_id
      - source_variation_id
      - mask_id
      properties:
        source_type:
          type: string
          enum:
          - creative_variation
          - reimagination
          - adaptation
          - scene_forge
          description: Type of source variation (determines which output table to
            use and where to fetch the asset_id from)
          example: creative_variation
        group_id:
          type: string
          format: uuid
          description: ID of the group where the output will be added (themeId for
            creative_variation, reimaginationGroupId for reimagination, creativeAdaptationId
            for adaptation, sceneForgeId for scene_forge)
          example: 123e4567-e89b-12d3-a456-426614174001
        source_variation_id:
          type: string
          format: uuid
          description: ID of the source variation/image to process (must have completed
            status)
          example: 123e4567-e89b-12d3-a456-426614174002
        mask_id:
          type: string
          format: uuid
          description: ID of the confirmed mask defining the region to identify and
            replace
          example: 123e4567-e89b-12d3-a456-426614174005
        removal_prompt:
          type: string
          nullable: true
          description: Optional prompt describing what to identify and remove from
            the image. Both prompts are fully optional.
          example: remove the old car
        insertion_prompt:
          type: string
          nullable: true
          description: Optional prompt describing what to insert or replace with.
            Both prompts are fully optional.
          example: insert a modern electric vehicle
      additionalProperties: false
    IdentifyReplaceResponse:
      type: object
      required:
      - workflow_id
      - status
      - placeholder_id
      properties:
        workflow_id:
          type: string
          format: uuid
          description: ID of the created workflow for tracking progress. Frontend
            can use this for debugging but should poll existing list endpoints to
            see when the placeholder is updated.
          example: 123e4567-e89b-12d3-a456-426614174003
        status:
          type: string
          enum:
          - pending
          description: Initial status of the workflow (always 'pending' on creation).
            Placeholder record is created immediately with this status.
          example: pending
        placeholder_id:
          type: string
          format: uuid
          description: ID of the placeholder record created immediately (will be updated
            when workflow completes). Frontend should poll existing list endpoints
            (creatives, reimaginations, or adaptations) to see when this placeholder
            transitions to 'completed' with the actual replaced image.
          example: 123e4567-e89b-12d3-a456-426614174004
      additionalProperties: false
    OutputLanguage:
      type: string
      default: en
      description: 'Language the LLM writes user-facing prompt-enhancement output
        in.

        Codes match the frontend locale set.

        '
      enum:
      - en
      - zh-CN
      - ja
      - de
      - fr
      - it
      - es-ES
      - pt-PT
      x-enum-varnames:
      - OUTPUT_LANGUAGE_EN
      - OUTPUT_LANGUAGE_ZH_CN
      - OUTPUT_LANGUAGE_JA
      - OUTPUT_LANGUAGE_DE
      - OUTPUT_LANGUAGE_FR
      - OUTPUT_LANGUAGE_IT
      - OUTPUT_LANGUAGE_ES_ES
      - OUTPUT_LANGUAGE_PT_PT
    UserPreferences:
      type: object
      description: The authenticated user's preferences.
      required:
      - language
      properties:
        language:
          $ref: '#/components/schemas/OutputLanguage'
      additionalProperties: false
    UpdateUserPreferencesRequest:
      type: object
      description: Mutable subset of user preferences.
      required:
      - language
      properties:
        language:
          $ref: '#/components/schemas/OutputLanguage'
      additionalProperties: false
    CreateApiKeyRequest:
      type: object
      description: Parameters for minting a new API key.
      properties:
        name:
          type: string
          description: Human-readable label for the key.
          example: ci-integration
        expiresAt:
          type: string
          format: date-time
          nullable: true
          description: 'Optional expiry. Omit or null = never expires (revoke is the
            kill

            switch). If set it must be in the future.

            '
          example: '2027-07-06T00:00:00Z'
      additionalProperties: false
    ApiKeyMetadata:
      type: object
      description: Non-secret view of an API key. Never carries the secret or hash.
      required:
      - id
      - keyId
      - ownerUserId
      - createdAt
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
          description: Key row id.
          example: 123e4567-e89b-12d3-a456-426614174000
        keyId:
          type: string
          readOnly: true
          description: Non-secret key handle (the lookup id embedded in the token).
          example: 9f86d081884c7d659a2feaa0c55ad015
        name:
          type: string
          description: Human-readable label.
          example: ci-integration
        ownerUserId:
          type: string
          format: uuid
          readOnly: true
          description: The user who owns the key (the key acts as this user).
          example: 123e4567-e89b-12d3-a456-426614174000
        expiresAt:
          type: string
          format: date-time
          nullable: true
          description: Expiry, or null if the key never expires.
        lastUsedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Last successful use, or null if never used.
        revokedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Revocation time, or null if active.
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp.
          example: '2026-07-06T00:00:00Z'
    CreateApiKeyResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: object
          required:
          - token
          - key
          properties:
            token:
              type: string
              description: 'The plaintext API key token (nak_<env>_<keyId>.<secret>).
                Shown

                ONCE and never retrievable again — store it now.

                '
              example: nak_production_9f86d081884c7d659a2feaa0c55ad015.s3cr3t...
            key:
              $ref: '#/components/schemas/ApiKeyMetadata'
            tokenTTL:
              type: string
              description: Advisory note that the token is shown once.
              example: shown once; not retrievable again
          additionalProperties: false
    ListApiKeysResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/ApiKeyMetadata'
    RevokeApiKeyResponse:
      type: object
      required:
      - status
      properties:
        status:
          type: string
          example: success
        data:
          nullable: true
          description: Always null on success.
    GenerativeResizeTarget:
      type: object
      required:
      - width
      - height
      description: 'Target dimensions for a single generated size. Width and height
        are each in [64, 4096].

        Combined area MUST also satisfy width * height <= 4,194,304 (4 megapixels).
        This

        cross-field constraint is not expressible in OpenAPI 3.0 and is enforced server-side
        —

        requests violating it receive 422. Examples: 2048×2048 ✓, 3200×800 ✓, 4096×1024
        ✓,

        4096×1025 ✗ (4MP overshoot). Clients SHOULD mirror this check before submission;
        the

        backend check is authoritative.

        '
      x-constraint: width * height <= 4194304
      properties:
        width:
          type: integer
          minimum: 64
          maximum: 4096
          description: Target width in pixels.
          example: 1024
        height:
          type: integer
          minimum: 64
          maximum: 4096
          description: Target height in pixels.
          example: 1024
    CreateGenerativeResizeGroupRequest:
      type: object
      required:
      - source_asset_id
      - sizes
      description: 'Create a new generative-resize group. Each size has a 4 MP cap
        (width * height <=

        4,194,304); a submission may include 1 to 15 sizes.

        '
      properties:
        source_asset_id:
          type: string
          format: uuid
          description: ID of the source asset to resize.
          example: 550e8400-e29b-41d4-a716-446655440000
        prompt:
          type: string
          maxLength: 1000
          nullable: true
          description: Optional prompt to guide generative fill during resizing.
          example: Clean studio background with soft lighting
        sizes:
          type: array
          minItems: 1
          maxItems: 15
          description: List of target dimensions to generate. Each size produces 3
            variants.
          items:
            $ref: '#/components/schemas/GenerativeResizeTarget'
        partner:
          $ref: '#/components/schemas/Partner'
    GenerativeResizeVariant:
      type: object
      required:
      - id
      - status
      - liked
      - disliked
      - created_at
      description: A single generated variant within a generative resize size.
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for this variant.
          example: 123e4567-e89b-12d3-a456-426614174000
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Current generation status of this variant.
          example: pending
        asset:
          allOf:
          - $ref: '#/components/schemas/Asset'
          nullable: true
          description: The generated asset. Null until generation completes successfully.
        seed:
          type: integer
          nullable: true
          description: Random seed used for this generation (available after completion).
          example: 42
        outpainting_strategy:
          type: string
          nullable: true
          description: Strategy used for outpainting (e.g. "adaptive_hybrid").
          example: adaptive_hybrid
        outpainting_steps:
          type: integer
          nullable: true
          description: Number of diffusion steps used during outpainting.
          example: 30
        liked:
          type: boolean
          default: false
          description: Whether the user has liked this variant.
        disliked:
          type: boolean
          default: false
          description: Whether the user has disliked this variant.
        error_code:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.code`.
          example: GENERATION_FAILED
        error_message:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.message`.
          example: Generation failed due to an internal error.
        error:
          allOf:
          - $ref: '#/components/schemas/GenerativeResizeError'
          nullable: true
          description: Canonical error object; populated when the variant failed.
        created_at:
          type: string
          format: date-time
          description: Timestamp when this variant was created.
          example: '2024-01-01T00:00:00Z'
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when generation completed successfully.
          example: '2024-01-01T00:01:00Z'
        failed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when generation failed.
          example: null
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking partner hardspec-compatibility and ML moderation
            warnings

            (NAT-1677). Empty/absent when the output matches the partner''s image
            specs,

            has no partner, or the partner has no image specs. DISTINCT from hard
            errors

            (see `error`) — a real policy violation / failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    GenerativeResizeSize:
      type: object
      required:
      - id
      - target_width
      - target_height
      - status
      - variants
      description: A single target size within a generative resize group, containing
        its variants.
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for this size.
          example: 223e4567-e89b-12d3-a456-426614174001
        target_width:
          type: integer
          description: Target width in pixels.
          example: 1024
        target_height:
          type: integer
          description: Target height in pixels.
          example: 1024
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Aggregate status of this size (based on variant statuses).
          example: pending
        error_code:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.code`.
          example: null
        error_message:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.message`.
          example: null
        error:
          allOf:
          - $ref: '#/components/schemas/GenerativeResizeError'
          nullable: true
          description: Canonical error object; populated when the size failed.
        variants:
          type: array
          description: List of variants generated for this size (3 initial + any extended).
          items:
            $ref: '#/components/schemas/GenerativeResizeVariant'
    GenerativeResizeGroup:
      type: object
      required:
      - id
      - brand_id
      - status
      - created_at
      - sizes
      description: A generative resize group containing all sizes and their variants.
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for this group.
          example: 333e4567-e89b-12d3-a456-426614174002
        brand_id:
          type: string
          format: uuid
          description: ID of the brand that owns this group.
          example: 444e4567-e89b-12d3-a456-426614174003
        source_asset:
          allOf:
          - $ref: '#/components/schemas/Asset'
          nullable: true
          description: The source asset used for resizing. Null if the asset has been
            deleted.
        prompt:
          type: string
          nullable: true
          description: The prompt provided at creation time.
          example: Clean studio background with soft lighting
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Aggregate status of the group.
          example: pending
        error_code:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.code`.
          example: null
        error_message:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.message`.
          example: null
        error:
          allOf:
          - $ref: '#/components/schemas/GenerativeResizeError'
          nullable: true
          description: Canonical error object; populated when the group failed.
        created_at:
          type: string
          format: date-time
          description: Timestamp when this group was created.
          example: '2024-01-01T00:00:00Z'
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when all sizes completed generation.
          example: null
        failed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when group-level failure occurred.
          example: null
        sizes:
          type: array
          description: List of target sizes with their variants.
          items:
            $ref: '#/components/schemas/GenerativeResizeSize'
    GenerativeResizeGroupSummary:
      type: object
      required:
      - id
      - brand_id
      - source_asset_id
      - status
      - sizes_count
      - completed_variants_count
      - total_variants_count
      - sizes
      - created_at
      - updated_at
      description: 'List-view projection of a generative resize group. Includes the
        full nested

        `sizes` (each with its `variants[]`) so the gallery list page can render

        every variant inline without an extra round-trip per group. Aggregate

        counts (`sizes_count`, `completed_variants_count`, `total_variants_count`)

        are kept for backward compatibility and quick progress rendering.

        '
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for this group.
          example: 333e4567-e89b-12d3-a456-426614174002
        brand_id:
          type: string
          format: uuid
          description: ID of the brand that owns this group.
          example: 444e4567-e89b-12d3-a456-426614174003
        source_asset_id:
          type: string
          format: uuid
          description: ID of the source asset.
          example: 550e8400-e29b-41d4-a716-446655440000
        source_asset:
          allOf:
          - $ref: '#/components/schemas/Asset'
          nullable: true
          description: The source asset (preloaded for display). Null if deleted.
        prompt:
          type: string
          nullable: true
          description: The prompt provided at creation time.
          example: Clean studio background with soft lighting
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
          description: Aggregate status of the group.
          example: processing
        error_code:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.code`.
          example: null
        error_message:
          type: string
          nullable: true
          deprecated: true
          description: Deprecated — use `error.message`.
          example: null
        error:
          allOf:
          - $ref: '#/components/schemas/GenerativeResizeError'
          nullable: true
          description: Canonical error object; populated when the group failed.
        sizes_count:
          type: integer
          description: Total number of sizes in this group.
          example: 3
        completed_variants_count:
          type: integer
          description: Number of variants that have completed generation.
          example: 6
        total_variants_count:
          type: integer
          description: Total number of variants across all sizes (including pending/failed).
          example: 9
        created_at:
          type: string
          format: date-time
          description: Timestamp when this group was created.
          example: '2024-01-01T00:00:00Z'
        updated_at:
          type: string
          format: date-time
          description: Timestamp of the last update to this group or any of its children.
          example: '2024-01-01T00:01:00Z'
        completed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when all sizes completed generation.
          example: null
        failed_at:
          type: string
          format: date-time
          nullable: true
          description: Timestamp when group-level failure occurred.
          example: null
        sizes:
          type: array
          description: List of target sizes with their variants (preloaded for list-page
            gallery rendering).
          items:
            $ref: '#/components/schemas/GenerativeResizeSize'
    GenerativeResizeGroupList:
      type: object
      required:
      - items
      - total
      - offset
      - limit
      description: Paginated list of generative resize group summaries.
      properties:
        items:
          type: array
          description: Page of group summaries.
          items:
            $ref: '#/components/schemas/GenerativeResizeGroupSummary'
        total:
          type: integer
          description: Total number of groups matching the query.
          example: 42
        offset:
          type: integer
          description: Number of items skipped.
          example: 0
        limit:
          type: integer
          description: Maximum number of items returned per page.
          example: 20
    ExtendGenerativeResizeSizeResponse:
      type: object
      required:
      - variant
      description: Response containing the newly created variant from an extend operation.
      properties:
        variant:
          $ref: '#/components/schemas/GenerativeResizeVariant'
    MuzeChatMessage:
      type: object
      required:
      - role
      - content
      properties:
        role:
          type: string
          enum:
          - user
          - assistant
          description: Author of the message. The server ignores any role outside
            this set.
          example: user
        content:
          type: string
          description: 'Plain-text message content. English only. Confirm flow: when
            the

            user confirms a generation_proposal via the confirm control, the

            client sends a user message whose content contains the marker

            `[[muze:confirm_generation]]` plus ONLY the execute params

            (fenced JSON): generation_type, prompt, theme, aspect_ratio, and

            product_asset_ids OR start_image_asset_id. The client MUST NOT

            include image_url or resolution — they are display-only and the

            presigned URL must never re-enter the model prompt (it is a

            bearer capability). The server''s execute guard requires the marker

            in the LATEST user message; the model copies the params verbatim.

            '
          example: Show me seasonal opportunities for Q4.
        asset_ids:
          type: array
          items:
            type: string
          description: 'Optional image-asset UUIDs the user attached in the chat composer

            (upload or asset-picker; both produce assets rows). The server

            resolves bytes server-side and injects pixels for the LAST user

            message only; earlier messages'' attachments are annotated as text

            (the model can re-view one via its view_asset tool). At most 10 are

            honored per message (mirrors the client cap). Unknown, cross-brand,

            non-image, oversize, or unsupported-format ids degrade to a text

            note inside the message — the turn never fails.

            '
          example:
          - ec0a6e15-9666-4902-9b0c-cbe4de0c3ca1
    MuzeChatRequest:
      type: object
      required:
      - messages
      properties:
        messages:
          type: array
          minItems: 1
          description: 'Full conversation history, oldest first. The server is stateless
            and

            does not persist history; the client sends the entire array each turn.

            Must be non-empty and the last message must have role `user` (the turn

            the agent answers). For the proactive greeting (page open), send a

            single seed user message (the documented kickoff string); the server

            recognises it via the system prompt and produces the greeting. There

            is no greeting flag.

            '
          items:
            $ref: '#/components/schemas/MuzeChatMessage'
        display_name:
          type: string
          nullable: true
          description: 'Optional display name for the user (from the Clerk profile,
            available

            client-side). Used to personalize the greeting. When absent the

            greeting falls back to a neutral salutation; never produces "Hi ,".

            '
          example: Joanne
    MuzeChatResponse:
      type: object
      required:
      - message
      - suggested_replies
      - prompt_cards
      - source_refs
      - tool_events
      - truncated
      properties:
        message:
          type: string
          description: Muze's natural-language reply for this turn.
        suggested_replies:
          type: array
          description: Tappable suggested follow-up messages (FR9). May be empty.
          items:
            type: string
          example:
          - Show me seasonal opportunities
          - Check today's trends
        prompt_cards:
          type: array
          description: Production-ready prompt cards rendered with a copy button.
            May be empty.
          items:
            $ref: '#/components/schemas/MuzePromptCard'
        source_refs:
          type: array
          description: 'Source items the turn actually fetched, populated deterministically

            from tool results. Empty only when no source returned data.

            '
          items:
            $ref: '#/components/schemas/MuzeSourceRef'
        tool_events:
          type: array
          description: Tools invoked this turn with their outcome status. May be empty.
          items:
            $ref: '#/components/schemas/MuzeToolEvent'
        generation:
          allOf:
          - $ref: '#/components/schemas/MuzeGeneration'
          nullable: true
          description: Present only when this turn triggered a generation; null otherwise.
        generation_proposal:
          allOf:
          - $ref: '#/components/schemas/MuzeGenerationProposal'
          nullable: true
          description: 'Present only when this turn produced a generation proposal

            (propose_generation ran); null otherwise. Nothing has been

            generated yet — render the proposal card and the confirm control.

            '
        strategic_plan:
          allOf:
          - $ref: '#/components/schemas/MuzeStrategicPlan'
          nullable: true
          description: 'Present only when this turn produced a strategic plan (a

            strategy-intent turn — partnership / campaign / audience); null

            otherwise. Rendered as a plan card with a Sources section. Ephemeral

            — never persisted server-side.

            '
        truncated:
          type: boolean
          default: false
          description: 'True when the server-side time/iteration budget ended the
            turn early

            and Muze returned its best-so-far answer (graceful degrade).

            '
    MuzeChatStreamEvent:
      type: string
      description: "A single Server-Sent Event frame, e.g. `event: stage\\ndata: {...}\\\
        n\\n`.\nOpenAPI 3.0.3 cannot model an SSE stream; this string schema exists\
        \ only\nso the response is documented. The code generator consumes the REQUEST\n\
        type (MuzeChatRequest) for this endpoint, not this response type.\n\nNamed\
        \ events emitted over the stream:\n  - event: stage   data: { \"tool\": \"\
        <name>\", \"label\": \"Reading your Brand DNA…\" }\n      Emitted as each\
        \ tool stage begins; drives the visible \"agent working\" UI.\n  - event:\
        \ delta   data: { \"text\": \"<chunk>\" }\n      Incremental response text.\n\
        \  - event: done    data: <the full MuzeChatResponse envelope>\n      Terminal\
        \ success frame; payload is byte-for-byte the sync response body.\n  - event:\
        \ error   data: { \"code\": \"<error_code>\", \"message\": \"<human message>\"\
        \ }\n      Terminal failure frame; the client shows a retryable error (SSE\
        \ is the\n      only client transport — there is no fallback path).\n"
    MuzeGeneration:
      type: object
      required:
      - group_id
      - generation_type
      - link_path
      properties:
        group_id:
          type: string
          description: 'Identifier of the triggered generation group in the existing
            feature.

            Plain string (no `format: uuid`): envelope ids are mixed provenance,

            `source_refs.id` is already a plain string, and the service struct uses

            `string`, so the generated model must not force `uuid.UUID` here.

            '
        generation_type:
          type: string
          enum:
          - scene_forge
          - video
          description: Which existing generation feature was triggered.
          example: scene_forge
        link_path:
          type: string
          description: 'Relative path to the existing list root for the triggered
            generation

            (scene_forge -> `/brands/{brandId}/i2i/scene-forge`, video ->

            `/brands/{brandId}/i2v`). These are the real list roots; no per-id deep

            link exists.

            '
          example: /brands/3fa85f64-5717-4562-b3fc-2c963f66afa6/i2i/scene-forge
    MuzeGenerationProposal:
      type: object
      description: "Confirm-before-generate payload (generation-flow v2). Built\n\
        deterministically by the propose_generation tool — never from\nmodel-emitted\
        \ text.\n\nPrompt enhancement is ASYNC (minutes). propose KICKS IT OFF and\
        \ returns\nimmediately with `prompt_status: \"enhancing\"` + `enhancement_id`\
        \ +\n`enhancement_kind`; it does NOT wait. The client renders the card now\n\
        (preview image + \"enhancing…\") and POLLS the existing prompt-enhancement\n\
        endpoint until it completes, then fills `prompt` with the enhanced text\n\
        and enables confirm:\n  - enhancement_kind \"scene_forge\"     → GET /v1/brands/{brandId}/scene-forge-prompt-enhancements/{enhancement_id}\
        \  (read optimizedPrompt + theme)\n  - enhancement_kind \"image_to_video\"\
        \  → GET /v1/brands/{brandId}/image-to-video-prompt-enhancements/{enhancement_id}\
        \  (read enhancedPrompt)\n`prompt_status: \"failed\"` means enhancement could\
        \ not start (e.g. not\nentitled) — `prompt` already holds the usable draft,\
        \ confirm as-is.\n\nOn confirm, the client sends a user message with the marker\n\
        `[[muze:confirm_generation]]` plus the EXECUTE params only (fenced JSON):\n\
        generation_type, the enhanced prompt, theme, aspect_ratio, and\nproduct_asset_ids\
        \ OR start_image_asset_id — NOT image_url/resolution\n(display-only; the presigned\
        \ URL must not re-enter the prompt). The\nserver refuses execution without\
        \ the marker.\n"
      required:
      - asset_id
      - image_url
      - generation_type
      - prompt_status
      - draft_prompt
      - prompt
      properties:
        asset_id:
          type: string
          description: 'Preview asset UUID (scene_forge: first product asset; video:
            start frame).'
        image_url:
          type: string
          description: 'Presigned S3 GET URL for the preview image. Expires after
            ~15

            minutes; the confirm path uses asset ids, not this URL, so a stale

            preview only breaks the <img> (re-fetch via the assets API).

            '
        resolution:
          type: object
          nullable: true
          description: The preview asset's stored pixel size; null when the asset
            row has no dimensions.
          required:
          - width
          - height
          properties:
            width:
              type: integer
            height:
              type: integer
        generation_type:
          type: string
          enum:
          - scene_forge
          - video
        prompt_status:
          type: string
          enum:
          - enhancing
          - ready
          - failed
          description: '"enhancing" → poll enhancement_id on the enhancement_kind
            endpoint, then fill `prompt`.

            "ready" → `prompt` already holds the final text. "failed" → enhancement
            couldn''t start; `prompt` holds the usable draft.

            '
        enhancement_id:
          type: string
          description: The prompt-enhancement id to poll (present when prompt_status
            is "enhancing").
        enhancement_kind:
          type: string
          enum:
          - scene_forge
          - image_to_video
          description: Which prompt-enhancement endpoint to poll for the enhanced
            prompt.
        draft_prompt:
          type: string
          description: The model's pre-enhancement prompt — shown as a placeholder
            on the card while enhancing.
        prompt:
          type: string
          description: 'The ENHANCED prompt that runs VERBATIM on execute. Empty while

            prompt_status is "enhancing" — the client fills it from the polled

            enhancement result. Holds the draft when prompt_status is "failed".

            '
        theme:
          type: string
          description: Scene Forge enhancement theme (read from the polled enhancement;
            sent back on confirm). Absent for video.
        aspect_ratio:
          type: string
          description: Requested aspect ratio; absent means the feature default.
        product_asset_ids:
          type: array
          items:
            type: string
          description: scene_forge only — the full product asset set for the execute
            round-trip.
        start_image_asset_id:
          type: string
          description: video only — the start-frame asset for the execute round-trip.
    MuzePromptCard:
      type: object
      required:
      - title
      - card_type
      - prompt
      properties:
        title:
          type: string
          description: Short human-readable card title.
          example: Image prompt
        card_type:
          type: string
          enum:
          - image
          - video
          - social
          - retail_media
          description: Which production surface this prompt targets.
          example: image
        prompt:
          type: string
          description: Production-ready prompt text, rendered in a copyable card.
    MuzeSourceRef:
      type: object
      required:
      - ref_type
      - id
      - name
      properties:
        ref_type:
          type: string
          description: 'Which context source produced this reference — the source
            name as an

            OPEN string ("brand_dna", "trends", "seasonal", "retailer", and any

            future folder-discovered domain). Deliberately NOT an enum: ML can add

            a source by dropping a file, with no spec/codegen change (revised

            2026-06-05). Populated deterministically from tool results (not model

            self-report), so tests can assert the ids exist among seeded items.

            '
          example: seasonal
        id:
          type: string
          description: 'Identifier of the source item within its context file (per
            the ML

            schema contract; string, not necessarily a UUID).

            '
          example: back-to-school-2026
        name:
          type: string
          description: The real source item name, quoted verbatim from the source.
          example: Back to School 2026
    MuzeSource:
      type: object
      description: 'A citation backing a strategic plan (FR7). Populated deterministically

        from web-search results and the brand''s own context — never from

        model-emitted text alone — so the plan can never fabricate a source.

        '
      required:
      - title
      - kind
      properties:
        title:
          type: string
          description: Human-readable source title, quoted from the source.
          example: Hulu Advertising — Audience & Reach
        url:
          type: string
          nullable: true
          description: 'Source URL when the citation is a web result; null for non-web

            sources (brand_dna / context items have no external URL).

            '
          example: https://www.hulu.com/advertising
        kind:
          type: string
          enum:
          - web
          - brand_dna
          - context
          description: 'Where the citation came from — `web` (search/fetch result),

            `brand_dna` (the brand''s Brand DNA), or `context` (a trends /

            seasonal / retailer context item).

            '
          example: web
    MuzeStrategicPlan:
      type: object
      description: 'Ephemeral strategic-plan artifact (NAT-1617). Present only on
        a

        strategy-intent turn (publisher partnership, campaign vision, audience

        strategy); null on creative turns. NEVER persisted server-side — it

        rides the `done` frame and lives only in the client''s session history,

        exactly like prompt_cards. The model writes `content` as markdown; the

        client renders it with a Sources section.

        '
      required:
      - plan_type
      - title
      - content
      properties:
        plan_type:
          type: string
          enum:
          - partnership
          - campaign
          - audience
          description: 'Which strategic deliverable this is — publisher partnership
            brief,

            medium/long-term campaign vision, or audience strategy.

            '
          example: partnership
        title:
          type: string
          description: Short human-readable plan title.
          example: Hulu Partnership — Q4 Vision
        content:
          type: string
          description: 'The full plan body as markdown (sections per plan_type). Rendered

            client-side; copyable to markdown.

            '
        sources:
          type: array
          description: 'Citations backing the plan (FR7). May be empty when the plan
            drew

            only on Brand DNA with no external research.

            '
          items:
            $ref: '#/components/schemas/MuzeSource'
    MuzeToolEvent:
      type: object
      required:
      - tool
      - status
      properties:
        tool:
          type: string
          description: Tool name (get_context, list_brand_assets, view_asset, propose_generation,
            execute_generation).
          example: get_context
        status:
          type: string
          description: 'Outcome label for this tool invocation (e.g. ok, empty, error,

            blocked — execute_generation refused because the latest user

            message carried no confirmation marker).

            '
          example: ok
    AspectRatio:
      type: string
      enum:
      - '1:1'
      - '2:3'
      - '3:2'
      - '3:4'
      - '4:3'
      - '9:16'
      - '16:9'
      - '21:9'
      description: Predefined aspect ratios for scene generation
      example: '16:9'
    EnvironmentGeneration:
      type: object
      required:
      - environmentGenerationId
      - brandId
      - prompt
      - status
      - createdAt
      - updatedAt
      properties:
        environmentGenerationId:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the environment generation
          example: 123e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
          readOnly: true
          description: Brand context for the generation
          example: 223e4567-e89b-12d3-a456-426614174000
        prompt:
          type: string
          description: Environment description prompt used for generation
          example: A clean white studio with soft natural lighting
        status:
          $ref: '#/components/schemas/GenerationStatus'
        generatedAsset:
          type: object
          nullable: true
          description: Generated environment asset (available when status is completed)
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
        errorCode:
          type: string
          nullable: true
          description: Error code if generation failed
          example: GENERATION_FAILED
        errorMessage:
          type: string
          nullable: true
          description: Human-readable error message if generation failed
          example: Failed to generate environment from prompt
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp
          example: '2024-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          readOnly: true
          description: Last update timestamp
          example: '2024-01-01T00:00:00Z'
        completedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Completion timestamp (null if not completed)
          example: '2024-01-01T00:05:30Z'
        failedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Failure timestamp (null if not failed)
          example: '2024-01-01T00:05:30Z'
    EnvironmentGenerationInput:
      type: object
      required:
      - prompt
      properties:
        prompt:
          type: string
          minLength: 1
          maxLength: 2500
          description: Environment description prompt for AI generation
          example: A clean white studio with soft natural lighting
      additionalProperties: false
    GenerationStatus:
      type: string
      enum:
      - pending
      - processing
      - completed
      - failed
      description: Status of parent generation entity (environment generation or scene
        forge)
      example: pending
    PromptEnhancement:
      type: object
      required:
      - promptEnhancementId
      - brandId
      - originalPrompt
      - useBrandDna
      - status
      - createdAt
      - updatedAt
      properties:
        promptEnhancementId:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the prompt enhancement
          example: 123e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
          readOnly: true
          description: Brand context for the enhancement
          example: 223e4567-e89b-12d3-a456-426614174000
        originalPrompt:
          type: string
          description: Original prompt text submitted for enhancement
          example: A modern kitchen with stainless steel appliances
        optimizedPrompt:
          type: string
          nullable: true
          description: AI-enhanced prompt (available when status is completed)
          example: A sleek, contemporary kitchen featuring premium stainless steel
            appliances, marble countertops, and soft natural lighting from large windows
        theme:
          type: string
          nullable: true
          description: AI-generated theme for the scene (available when status is
            completed)
          example: Modern Elegance
        status:
          $ref: '#/components/schemas/GenerationStatus'
        errorCode:
          type: string
          nullable: true
          description: Error code if enhancement failed
          example: ENHANCEMENT_FAILED
        errorMessage:
          type: string
          nullable: true
          description: Human-readable error message if enhancement failed
          example: Failed to enhance prompt
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp
          example: '2024-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          readOnly: true
          description: Last update timestamp
          example: '2024-01-01T00:00:00Z'
        completedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Completion timestamp (null if not completed)
          example: '2024-01-01T00:00:30Z'
        failedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Failure timestamp (null if not failed)
          example: '2024-01-01T00:00:30Z'
        useBrandDna:
          type: boolean
          description: Whether Brand DNA was applied to this prompt enhancement
          example: true
        partner:
          $ref: '#/components/schemas/Partner'
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking ML moderation content warnings (NAT-1677). Empty/absent
            when

            the enhanced prompt raises no content flags. DISTINCT from hard errors

            (see `errorCode`/`errorMessage`) — a real failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    PromptEnhancementInput:
      type: object
      required:
      - originalPrompt
      properties:
        originalPrompt:
          type: string
          minLength: 1
          maxLength: 2500
          description: Original prompt text to be enhanced
          example: A modern kitchen with stainless steel appliances
        productAssetIds:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 5
          description: Array of product asset UUIDs (max 5 products)
          example:
          - 550e8400-e29b-41d4-a716-446655440000
        environmentAssetId:
          type: string
          format: uuid
          nullable: true
          description: Optional environment asset UUID
          example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
        useBrandDna:
          type: boolean
          nullable: true
          description: Whether to apply Brand DNA to prompt enhancement (defaults
            to true if omitted)
          example: true
        partner:
          $ref: '#/components/schemas/Partner'
      additionalProperties: false
    SceneForge:
      type: object
      required:
      - sceneForgeId
      - brandId
      - blendingPrompt
      - theme
      - useBrandDna
      - status
      - productAssets
      - variations
      - createdAt
      - updatedAt
      properties:
        sceneForgeId:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the scene forge
          example: 323e4567-e89b-12d3-a456-426614174000
        brandId:
          type: string
          format: uuid
          readOnly: true
          description: Brand context for the scene forge
          example: 223e4567-e89b-12d3-a456-426614174000
        blendingPrompt:
          type: string
          description: Scene composition prompt used for generation
          example: Products displayed on a marble countertop with natural lighting
        aspectRatio:
          type: string
          enum:
          - '1:1'
          - '2:3'
          - '3:2'
          - '3:4'
          - '4:3'
          - '9:16'
          - '16:9'
          - '21:9'
          nullable: true
          description: Target aspect ratio (null if not specified)
        theme:
          type: string
          description: Theme name (from preview, AI-generated, user-edited, or placeholder
            "Untitled Scene")
          example: Product Display Scene
        productAssets:
          type: array
          items:
            $ref: '#/components/schemas/AssetSummary'
          description: Product assets used in the scene (0-5 items)
        environmentAsset:
          type: object
          nullable: true
          description: Optional environment asset used in the scene
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
        status:
          $ref: '#/components/schemas/GenerationStatus'
        variations:
          type: array
          items:
            $ref: '#/components/schemas/SceneForgeGeneratedImage'
          description: Generated image variations (initially 4, can be extended)
        errorCode:
          type: string
          nullable: true
          description: Error code if generation failed
          example: GENERATION_FAILED
        errorMessage:
          type: string
          nullable: true
          description: Human-readable error message if generation failed
          example: Failed to generate scene from inputs
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp
          example: '2024-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          readOnly: true
          description: Last update timestamp
          example: '2024-01-01T00:00:00Z'
        completedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Completion timestamp (null if not completed)
          example: '2024-01-01T00:10:00Z'
        failedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Failure timestamp (null if not failed)
          example: '2024-01-01T00:10:00Z'
        useBrandDna:
          type: boolean
          description: Whether Brand DNA was applied to this scene forge generation
          example: true
    SceneForgeGeneratedImage:
      type: object
      required:
      - generatedImageId
      - sceneForgeId
      - status
      - blendingPrompt
      - liked
      - disliked
      - createdAt
      - updatedAt
      properties:
        generatedImageId:
          type: string
          format: uuid
          readOnly: true
          description: Unique identifier for the generated image variation
          example: 423e4567-e89b-12d3-a456-426614174000
        sceneForgeId:
          type: string
          format: uuid
          readOnly: true
          description: Parent scene forge identifier
          example: 323e4567-e89b-12d3-a456-426614174000
        status:
          $ref: '#/components/schemas/GenerationStatus'
        blendingPrompt:
          type: string
          description: Denormalized blending prompt from parent scene forge
          example: Products displayed on a marble countertop with natural lighting
        asset:
          type: object
          nullable: true
          description: Generated image asset (available when status is completed)
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
        width:
          type: integer
          nullable: true
          description: Width of the generated image in pixels.
        height:
          type: integer
          nullable: true
          description: Height of the generated image in pixels.
        liked:
          type: boolean
          description: Whether user has liked this variation (mutually exclusive with
            disliked)
          example: false
        disliked:
          type: boolean
          description: Whether user has disliked this variation (mutually exclusive
            with liked)
          example: false
        errorCode:
          type: string
          nullable: true
          description: Error code if variation generation failed
          example: GENERATION_FAILED
        errorMessage:
          type: string
          nullable: true
          description: Human-readable error message if variation generation failed
          example: Failed to generate variation
        createdAt:
          type: string
          format: date-time
          readOnly: true
          description: Creation timestamp
          example: '2024-01-01T00:00:00Z'
        updatedAt:
          type: string
          format: date-time
          readOnly: true
          description: Last update timestamp
          example: '2024-01-01T00:00:00Z'
        completedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Completion timestamp (null if not completed)
          example: '2024-01-01T00:02:00Z'
        failedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Failure timestamp (null if not failed)
          example: '2024-01-01T00:02:00Z'
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking partner hardspec-compatibility and ML moderation
            warnings

            (NAT-1677). Empty/absent when the output matches the partner''s image
            specs,

            has no partner, or the partner has no image specs. DISTINCT from hard
            errors

            (see `errorCode`/`errorMessage`) — a real policy violation / failure still

            fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    SceneForgeInput:
      type: object
      required:
      - blendingPrompt
      - promptIsEnhanced
      properties:
        blendingPrompt:
          type: string
          minLength: 1
          maxLength: 2500
          description: Scene composition prompt (original or enhanced)
          example: Products displayed on a marble countertop with natural lighting
        promptIsEnhanced:
          type: boolean
          description: 'Whether the prompt has been AI-enhanced. Set to true only
            when the current prompt text exactly matches an accepted enhancement result.
            Undo and manual edits set this to false.

            '
          example: true
        partner:
          $ref: '#/components/schemas/Partner'
        theme:
          type: string
          nullable: true
          maxLength: 500
          description: Theme from preview (when promptIsEnhanced=true and preview
            was accepted)
          example: Modern Elegance
        aspectRatio:
          type: string
          enum:
          - '1:1'
          - '2:3'
          - '3:2'
          - '3:4'
          - '4:3'
          - '9:16'
          - '16:9'
          - '21:9'
          nullable: true
          description: Target aspect ratio for generation (optional)
        productAssetIds:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 5
          description: Array of product asset UUIDs (max 5 products)
          example:
          - 550e8400-e29b-41d4-a716-446655440000
          - 6ba7b810-9dad-11d1-80b4-00c04fd430c8
        environmentAssetId:
          type: string
          format: uuid
          nullable: true
          description: Optional environment asset UUID (from environment generation
            or uploaded)
          example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
        useBrandDna:
          type: boolean
          nullable: true
          description: Whether to apply Brand DNA to scene generation (defaults to
            true if omitted)
          example: true
      additionalProperties: false
    SceneForgePaginatedResponse:
      type: object
      required:
      - data
      - pagination
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/SceneForge'
          description: Array of scene forge objects
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    SceneForgeUpdate:
      type: object
      properties:
        theme:
          type: string
          minLength: 1
          maxLength: 500
          description: User-editable theme name for the scene forge
          example: Summer Beach Collection
      additionalProperties: false
    TrendThemeSummary:
      type: object
      required:
      - id
      - name
      - momentum
      - supporting_trend_count
      - is_local
      - country_rank
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          description: 3-5 word theme name
        description:
          type: string
          nullable: true
        relevant_industries:
          type: array
          items:
            type: string
          nullable: true
        suggestion:
          type: string
          nullable: true
        momentum:
          type: string
          enum:
          - rising
          - peaking
          - sustained
        supporting_trend_count:
          type: integer
        is_local:
          type: boolean
          default: false
          description: True when one country dominates the theme's direct evidence
            (NAT-1450).
        primary_country:
          type: string
          nullable: true
          pattern: ^[A-Z]{2}$
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 uppercase when is_local=true; null otherwise.
          example: US
        country_rank:
          type: object
          additionalProperties:
            type: integer
            minimum: 1
          description: Per-country rank within the run; ISO-2 keys, lower=better.
            Empty for pre-NAT-1450 themes.
          example:
            US: 3
            GB: 17
            IN: 22
    TrendThemeDetail:
      type: object
      required:
      - id
      - name
      - momentum
      - supporting_trends
      - supporting_trend_count
      - is_local
      - country_rank
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        relevant_industries:
          type: array
          items:
            type: string
          nullable: true
        suggestion:
          type: string
          nullable: true
        momentum:
          type: string
          enum:
          - rising
          - peaking
          - sustained
        supporting_trends:
          type: array
          items:
            $ref: '#/components/schemas/SupportingTrend'
        supporting_trend_count:
          type: integer
        is_local:
          type: boolean
          default: false
          description: True when one country dominates the theme's direct evidence
            (NAT-1450).
        primary_country:
          type: string
          nullable: true
          pattern: ^[A-Z]{2}$
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 uppercase when is_local=true; null otherwise.
          example: US
        country_rank:
          type: object
          additionalProperties:
            type: integer
            minimum: 1
          description: Per-country rank within the run; ISO-2 keys, lower=better.
            Empty for pre-NAT-1450 themes.
          example:
            US: 3
            GB: 17
            IN: 22
    SupportingTrend:
      type: object
      required:
      - title
      - source
      - country
      properties:
        title:
          type: string
        source:
          type: string
          enum:
          - google_trends
          - google_news
          - youtube
          - virlo_trends
          - virlo_hashtags
        country:
          type: string
          description: ISO 3166-1 alpha-2 or GLOBAL
        url:
          type: string
          nullable: true
        views:
          type: integer
          nullable: true
        likes:
          type: integer
          nullable: true
        comments:
          type: integer
          nullable: true
    TrendThemesListResponse:
      type: object
      required:
      - status
      - data
      - pagination
      properties:
        status:
          type: string
          example: success
        run_completed_at:
          type: string
          format: date-time
          nullable: true
          description: ISO 8601 timestamp of when the pipeline run completed. Null
            if no completed runs exist.
        applied_market:
          type: string
          nullable: true
          pattern: ^[A-Z]{2}$
          description: ISO 3166-1 alpha-2 of the market the server used to rank these
            themes; null if no per-market ranking was applied (e.g., latam orgs).
          example: US
        data:
          type: array
          items:
            $ref: '#/components/schemas/TrendThemeSummary'
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    TrendThemeDetailResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/TrendThemeDetail'
    WalmartAdSpec:
      type: object
      required:
      - id
      - internal_name
      - display_name
      - target_platform
      - image_width
      - image_height
      - width
      - height
      - logo_width
      - logo_height
      - max_file_size
      - enabled
      - image_requirement
      - required
      - supports_color_customization
      - max_image_width
      - max_image_height
      - alt_text_letters_only
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the ad spec
          example: 550e8400-e29b-41d4-a716-446655440000
        internal_name:
          type: string
          description: Internal system name
          example: marqueeDesktop
        display_name:
          type: string
          description: Human-readable name
          example: Marquee Desktop
        target_platform:
          type: string
          enum:
          - desktop
          - mobile
          - tablet
          description: Platform type
          example: desktop
        image_width:
          type: integer
          description: Generated image canvas width in pixels
          example: 1510
        image_height:
          type: integer
          description: Generated image canvas height in pixels
          example: 356
        width:
          type: integer
          description: Preview container width in pixels
          example: 1612
        height:
          type: integer
          description: Preview container height in pixels
          example: 178
        logo_width:
          type: integer
          description: Logo maximum width in pixels
          example: 200
        logo_height:
          type: integer
          description: Logo maximum height in pixels
          example: 260
        max_file_size:
          type: integer
          description: Maximum file size in kilobytes
          example: 150
        enabled:
          type: boolean
          description: Whether this ad spec is active
          example: true
        image_requirement:
          type: string
          enum:
          - required
          - optional
          - not_supported
          description: 'Whether a lifestyle image is required, optional, or not supported.

            - required: Image must be provided (8 specs)

            - optional: Can include or omit image (2 specs: skylineDesktop, skylineDesktopV2)

            - not_supported: Logo only, no image (2 specs: skylineApp, skylineAppV2)

            '
          example: required
        required:
          type: boolean
          description: Whether this ad spec is required for creative submission
          example: true
        max_image_width:
          type: integer
          description: Maximum allowed image width in pixels
          example: 5000
        max_image_height:
          type: integer
          description: Maximum allowed image height in pixels
          example: 5000
        supports_color_customization:
          type: boolean
          description: Whether this ad spec supports V2/V3 color customization
          example: false
        background_color_required:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          description: Whether background color customization is required
          example: optional
        text_color:
          type: string
          nullable: true
          description: Text color for the ad unit
          example: white
        background_color_hex:
          type: string
          nullable: true
          description: Default background color in hex format
          example: '#F6F6F6'
        requires_wcag_contrast:
          type: boolean
          nullable: true
          description: Whether WCAG contrast standards must be met
          example: true
        headline_requirement:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          example: required
        headline_max_length:
          type: integer
          nullable: true
          example: 25
        subhead_requirement:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          example: required
        subhead_max_length:
          type: integer
          nullable: true
          example: 55
        subhead_must_end_with:
          type: string
          nullable: true
          description: Valid ending punctuation characters
          example: .!?*
        button_cta_requirement:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          example: required
        button_cta_max_length:
          type: integer
          nullable: true
          example: 16
        button_cta_requires_sentence_case:
          type: boolean
          nullable: true
          description: Whether button CTA must use sentence casing
          example: true
        disclaimer_link_requirement:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          example: optional
        disclaimer_link_max_length:
          type: integer
          nullable: true
          example: 600
        image_alt_text_requirement:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          example: required
        image_alt_text_max_length:
          type: integer
          nullable: true
          example: 150
        logo_alt_text_requirement:
          type: string
          enum:
          - required
          - optional
          - not_applicable
          nullable: true
          example: required
        logo_alt_text_max_length:
          type: integer
          nullable: true
          example: 150
        alt_text_letters_only:
          type: boolean
          description: 'When TRUE, alt text fields (image_alt_text, logo_alt_text)
            must contain only letters (a-z, A-Z) and spaces.

            Matches Walmart pattern ^[a-zA-Z ]+$

            '
          example: true
        created_at:
          type: string
          format: date-time
          description: When the ad spec was created
        updated_at:
          type: string
          format: date-time
          description: When the ad spec was last updated
    WalmartAdSpecsResponse:
      type: object
      required:
      - ad_specs
      properties:
        ad_specs:
          type: array
          items:
            $ref: '#/components/schemas/WalmartAdSpec'
    CreateWalmartCreativeRequest:
      type: object
      required:
      - title
      - source_image_asset_id
      - logo_asset_id
      - headline
      - subhead
      - button_cta
      - image_alt_text
      - logo_alt_text
      properties:
        title:
          type: string
          description: Internal title for the creative
          example: Summer Sale 2025
          minLength: 1
          maxLength: 255
        walmart_folder_id:
          type: string
          nullable: true
          description: Walmart DAM folder ID (optional)
          example: folder_12345
          maxLength: 255
        source_image_asset_id:
          type: string
          format: uuid
          description: Source lifestyle image asset ID
          example: 550e8400-e29b-41d4-a716-446655440001
        logo_asset_id:
          type: string
          format: uuid
          description: Brand logo asset ID
          example: 550e8400-e29b-41d4-a716-446655440002
        offsets:
          allOf:
          - $ref: '#/components/schemas/ResizeOffsets'
          nullable: true
          description: Resize offsets (uses resize_offsets/v1 schema)
        prompt:
          type: string
          nullable: true
          description: Optional AI generation prompt for Modal image generation
          example: A photograph in studio in a white clean background
        headline:
          type: string
          description: Headline text (validated against most restrictive limit)
          example: Save big this summer
          minLength: 1
          maxLength: 255
        subhead:
          type: string
          description: Subhead text (must end with .!?* per Walmart specs)
          example: Up to 50% off everything!
          minLength: 1
          maxLength: 255
        button_cta:
          type: string
          description: Call-to-action button text
          example: Shop now
          minLength: 1
          maxLength: 255
        disclaimer_link:
          type: string
          nullable: true
          description: Disclaimer link text (optional)
          example: 'Terms apply: walmart.com/terms'
          maxLength: 600
        image_alt_text:
          type: string
          description: Alt text for source image
          example: Summer products with discount labels
          minLength: 1
          maxLength: 255
        logo_alt_text:
          type: string
          description: Alt text for brand logo
          example: Brand logo
          minLength: 1
          maxLength: 255
        background_color_hex:
          type: string
          nullable: true
          pattern: ^#[0-9A-Fa-f]{6}$
          description: 'Background color for V2/V3 ad formats (6-digit hex code).

            Only applies to Skyline Desktop V2/V3 and Skyline Mobile V2/V3.

            Default: #374151 (slate gray)

            '
          example: '#374151'
        text_color:
          type: string
          nullable: true
          enum:
          - white
          - gray
          description: 'Text color for V2/V3 ad formats.

            Only applies to enhanced skyline formats.

            Default: white

            '
          example: white
    WalmartCreative:
      type: object
      required:
      - id
      - organization_id
      - brand_id
      - created_by_user_id
      - title
      - source_image_asset_id
      - headline
      - subhead
      - button_cta
      - image_alt_text
      - logo_alt_text
      - status
      - text_generation_status
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the creative
        partner:
          allOf:
          - $ref: '#/components/schemas/Partner'
          readOnly: true
          description: Partner tag (NAT-1676). Always 'walmart' for this Walmart-only
            surface.
        organization_id:
          type: string
          format: uuid
          description: Organization ID (tenant)
        brand_id:
          type: string
          format: uuid
          description: Brand this creative belongs to
        created_by_user_id:
          type: string
          format: uuid
          description: User who created the creative
        title:
          type: string
          description: Internal title
        walmart_folder_id:
          type: string
          nullable: true
          description: Walmart DAM folder ID
        walmart_creative_id:
          type: string
          nullable: true
          description: Walmart external creative ID (after submission)
        source_image_asset_id:
          type: string
          format: uuid
          description: Source image asset
        logo_asset_id:
          type: string
          format: uuid
          nullable: true
          description: Logo asset
        source_image_asset:
          $ref: '#/components/schemas/AssetSummary'
        logo_asset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
          description: Logo asset metadata
        offsets:
          allOf:
          - $ref: '#/components/schemas/ResizeOffsets'
          nullable: true
          description: Resize offsets (uses resize_offsets/v1 schema)
        prompt:
          type: string
          nullable: true
          description: Optional AI generation prompt for Modal image generation
        headline:
          type: string
          description: Global headline text
        subhead:
          type: string
          description: Global subhead text
        button_cta:
          type: string
          description: Global CTA text
        disclaimer_link:
          type: string
          nullable: true
          description: Disclaimer link
        image_alt_text:
          type: string
          description: Global image alt text
        logo_alt_text:
          type: string
          description: Global logo alt text
        background_color_hex:
          type: string
          description: Background color for V2/V3 ad formats (slate gray default)
          example: '#374151'
        text_color:
          type: string
          description: Text color for V2/V3 ad formats (white or gray)
          example: white
        status:
          type: string
          enum:
          - draft
          - generating
          - generation_failed
          - ready_to_submit
          - submitting
          - submission_failed
          - submission_completed
          - walmart_draft
          - pending_approval
          - approved
          - rejected
          description: Creative lifecycle status
        text_generation_status:
          type: string
          enum:
          - pending
          - completed
          - failed
          description: 'AI text generation workflow status. Independent of main creative
            status lifecycle.

            - pending: Text generation in progress or waiting

            - completed: AI successfully generated and updated text fields

            - failed: AI text generation failed, original placeholder text kept

            '
          example: pending
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
          description: 'Classified error from the most recent text generation attempt.

            Populated when text_generation_status is ''failed''; null otherwise.

            error.code is one of {UserRequestError, ModelProviderError, NativeAdsSystemError}.

            '
        is_edited:
          type: boolean
          nullable: true
          description: Whether creative has been edited
        edited_at:
          type: string
          format: date-time
          nullable: true
          description: When creative was last edited
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp
        submitted_at:
          type: string
          format: date-time
          nullable: true
          description: Submission timestamp
        deleted_at:
          type: string
          format: date-time
          nullable: true
          description: Soft delete timestamp
        ad_units:
          type: array
          description: All ad units for this creative (13 items)
          items:
            $ref: '#/components/schemas/WalmartCreativeAdUnit'
        review_comments:
          type: array
          description: Review comments from Walmart (populated on GET if creative
            was submitted)
          items:
            $ref: '#/components/schemas/WalmartCreativeReviewComment'
    WalmartCreativeAdUnit:
      type: object
      required:
      - id
      - organization_id
      - creative_id
      - walmart_creative_ad_spec_id
      - ad_spec
      - status
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Ad unit instance ID
        organization_id:
          type: string
          format: uuid
          description: Organization ID (denormalized for RLS)
        creative_id:
          type: string
          format: uuid
          description: Parent creative ID (internal UUID, not external Walmart ID)
        walmart_creative_ad_spec_id:
          type: string
          format: uuid
          description: Ad spec (format) this unit uses
        ad_spec:
          $ref: '#/components/schemas/WalmartAdSpec'
          description: Full ad spec object (embedded for convenience)
        status:
          type: string
          enum:
          - pending
          - generating
          - generated
          - user_deleted
          - skipped
          - generation_failed
          description: 'Image generation lifecycle status:

            - pending: Awaiting generation

            - generating: Currently being generated

            - generated: Image successfully generated

            - user_deleted: User explicitly removed image (optional ad units only)

            - skipped: Not applicable (for not_supported ad units)

            - generation_failed: Generation failed

            '
          example: generated
        generated_asset_id:
          type: string
          format: uuid
          nullable: true
          description: Generated image asset (NULL until workflow completes)
        preview_asset_id:
          type: string
          format: uuid
          nullable: true
          description: Preview asset
        generated_asset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
          description: Asset summary for generated image (null if not yet generated)
        headline:
          type: string
          nullable: true
          description: Override headline (NULL = use creative-level)
        subhead:
          type: string
          nullable: true
          description: Override subhead (NULL = use creative-level)
        button_cta:
          type: string
          nullable: true
          description: Override CTA (NULL = use creative-level)
        disclaimer_link:
          type: string
          nullable: true
          description: Override disclaimer (NULL = use creative-level)
        image_alt_text:
          type: string
          nullable: true
          description: Override image alt (NULL = use creative-level)
        logo_alt_text:
          type: string
          nullable: true
          description: Override logo alt (NULL = use creative-level)
        background_color_hex:
          type: string
          nullable: true
          description: Ad-unit-specific background color override (NULL = use creative-level
            default)
          example: '#374151'
        text_color:
          type: string
          nullable: true
          description: Ad-unit-specific text color override (NULL = use creative-level
            default)
          example: white
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp
        deleted_at:
          type: string
          format: date-time
          nullable: true
          description: Soft delete timestamp
    WalmartCreativeResponse:
      type: object
      required:
      - walmart_creative
      properties:
        walmart_creative:
          $ref: '#/components/schemas/WalmartCreative'
      description: Full creative response with all details (used by GET endpoint)
    ValidationError:
      type: object
      required:
      - field
      - message
      properties:
        field:
          type: string
          description: Field name that failed validation
          example: headline
        message:
          type: string
          description: Human-readable error message
          example: 'headline exceeds maximum length of 25 characters (current: 48)'
    WalmartCreativeSummary:
      type: object
      required:
      - id
      - organization_id
      - brand_id
      - title
      - status
      - text_generation_status
      - ad_units_count
      - generated_units_count
      - pending_units_count
      - source_image_asset
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Creative ID
          example: 550e8400-e29b-41d4-a716-446655440000
        organization_id:
          type: string
          format: uuid
          description: Organization ID
          example: 550e8400-e29b-41d4-a716-446655440001
        brand_id:
          type: string
          format: uuid
          description: Brand ID
          example: 550e8400-e29b-41d4-a716-446655440002
        partner:
          allOf:
          - $ref: '#/components/schemas/Partner'
          readOnly: true
          description: Partner tag (NAT-1676). Always 'walmart' for this Walmart-only
            surface.
        title:
          type: string
          description: Creative title
          example: Summer Sale 2025
        status:
          type: string
          enum:
          - draft
          - generating
          - generation_failed
          - ready_to_submit
          - submitting
          - submission_failed
          - submission_completed
          - walmart_draft
          - pending_approval
          - approved
          - rejected
          description: Creative status
          example: draft
        text_generation_status:
          type: string
          enum:
          - pending
          - completed
          - failed
          description: 'AI text generation workflow status. Independent of main creative
            status lifecycle.

            - pending: Text generation in progress or waiting

            - completed: AI successfully generated and updated text fields

            - failed: AI text generation failed, original placeholder text kept

            '
          example: pending
        ad_units_count:
          type: integer
          format: int32
          description: Total number of ad units
          example: 13
        generated_units_count:
          type: integer
          format: int32
          description: Number of ad units with generated images
          example: 0
        pending_units_count:
          type: integer
          format: int32
          description: Number of ad units pending generation
          example: 13
        source_image_asset:
          $ref: '#/components/schemas/AssetSummary'
        logo_asset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
          description: Logo asset metadata
        created_at:
          type: string
          format: date-time
          description: Creation timestamp
          example: '2025-01-19T10:00:00Z'
        updated_at:
          type: string
          format: date-time
          description: Last update timestamp
          example: '2025-01-19T10:00:00Z'
    ListWalmartCreativesResponse:
      type: object
      required:
      - data
      - pagination
      properties:
        data:
          type: array
          description: List of creative summaries
          items:
            $ref: '#/components/schemas/WalmartCreativeSummary'
        pagination:
          type: object
          required:
          - current_page
          - total_pages
          - total_items
          - items_per_page
          properties:
            current_page:
              type: integer
              format: int32
              description: Current page number (1-based)
              example: 1
            total_pages:
              type: integer
              format: int32
              description: Total number of pages
              example: 3
            total_items:
              type: integer
              format: int32
              description: Total number of creatives
              example: 42
            items_per_page:
              type: integer
              format: int32
              description: Items per page
              example: 20
    CreateWalmartCreativeResponse:
      type: object
      required:
      - id
      - status
      properties:
        id:
          type: string
          format: uuid
          description: Created creative ID
          example: 550e8400-e29b-41d4-a716-446655440000
        status:
          type: string
          enum:
          - draft
          - generating
          - generation_failed
          - ready_to_submit
          - submitting
          - submission_failed
          - submission_completed
          - walmart_draft
          - pending_approval
          - approved
          - rejected
          description: Initial creative status (always 'draft')
          example: draft
    SubmitWalmartCreativeResponse:
      type: object
      required:
      - message
      - workflow_id
      - creative_id
      properties:
        message:
          type: string
          description: Confirmation message
          example: Creative submission workflow started
        workflow_id:
          type: string
          format: uuid
          description: ID of the created submission workflow
          example: 123e4567-e89b-12d3-a456-426614174000
        creative_id:
          type: string
          format: uuid
          description: ID of the creative being submitted
          example: 987fcdeb-51a2-43d1-b789-123456789abc
    UpdateWalmartCreativeRequest:
      type: object
      description: Request to update Walmart creative. All fields are optional (PATCH
        semantics).
      properties:
        title:
          type: string
          maxLength: 255
          nullable: true
          description: Internal title for the creative
        walmart_folder_id:
          type: string
          maxLength: 255
          nullable: true
          description: Walmart DAM folder ID (optional)
        source_image_asset_id:
          type: string
          format: uuid
          nullable: true
          description: Source image asset ID (triggers regeneration if changed - Phase
            2)
        logo_asset_id:
          type: string
          format: uuid
          nullable: true
          description: Brand logo asset ID
        offsets:
          allOf:
          - $ref: '#/components/schemas/ResizeOffsets'
          nullable: true
          description: Resize offsets (uses resize_offsets/v1 schema)
        prompt:
          type: string
          nullable: true
          description: Optional AI generation prompt for Modal image generation
        headline:
          type: string
          maxLength: 25
          nullable: true
          description: Headline text (validated against most restrictive limit)
        subhead:
          type: string
          maxLength: 30
          nullable: true
          description: Subhead text (must end with .!?* per Walmart specs)
        button_cta:
          type: string
          maxLength: 16
          nullable: true
          description: Call-to-action button text
        disclaimer_link:
          type: string
          maxLength: 600
          nullable: true
          description: Disclaimer link text (optional)
        image_alt_text:
          type: string
          maxLength: 150
          nullable: true
          description: Alt text for source image
        logo_alt_text:
          type: string
          maxLength: 150
          nullable: true
          description: Alt text for brand logo
        background_color_hex:
          type: string
          pattern: ^#[0-9A-Fa-f]{6}$
          nullable: true
          description: Background color for V2/V3 ad formats (6-digit hex code)
        text_color:
          type: string
          enum:
          - white
          - gray
          nullable: true
          description: Text color for V2/V3 ad formats
    PatchWalmartCreativeAdUnitRequest:
      type: object
      description: Request to patch text and color fields for a specific ad unit.
        All fields are optional (PATCH semantics).
      properties:
        headline:
          type: string
          maxLength: 255
          nullable: true
          description: Override headline for this ad unit (NULL = use creative-level
            value)
        subhead:
          type: string
          maxLength: 255
          nullable: true
          description: Override subhead for this ad unit (NULL = use creative-level
            value)
        button_cta:
          type: string
          maxLength: 255
          nullable: true
          description: Override button CTA for this ad unit (NULL = use creative-level
            value)
        disclaimer_link:
          type: string
          maxLength: 600
          nullable: true
          description: Override disclaimer link for this ad unit (NULL = use creative-level
            value)
        image_alt_text:
          type: string
          maxLength: 255
          nullable: true
          description: Override image alt text for this ad unit (NULL = use creative-level
            value)
        logo_alt_text:
          type: string
          maxLength: 255
          nullable: true
          description: Override logo alt text for this ad unit (NULL = use creative-level
            value)
        background_color_hex:
          type: string
          pattern: ^#[0-9A-Fa-f]{6}$
          nullable: true
          description: Override background color for this ad unit (NULL = use creative-level
            value, 6-digit hex code)
        text_color:
          type: string
          enum:
          - white
          - gray
          nullable: true
          description: Override text color for this ad unit (NULL = use creative-level
            value)
    WalmartCreativeAdUnitResponse:
      type: object
      required:
      - ad_unit
      properties:
        ad_unit:
          $ref: '#/components/schemas/WalmartCreativeAdUnit'
      description: Response containing a single ad unit
    AdUnitGenerativeResizeRequest:
      type: object
      description: Request to regenerate a single ad unit's image using generative
        resize. All fields are optional.
      properties:
        offsets:
          allOf:
          - $ref: '#/components/schemas/ResizeOffsets'
          nullable: true
          description: Resize offsets for generative fill (NULL = no offsets, use
            original dimensions)
        prompt:
          type: string
          nullable: true
          description: Optional AI generation prompt for Modal generative resize
          example: A photograph in studio in a white clean background
        new_width:
          type: integer
          nullable: true
          description: Override width for generated image (NULL = use ad spec default
            width). Must be provided with new_height.
          example: 1200
        new_height:
          type: integer
          nullable: true
          description: Override height for generated image (NULL = use ad spec default
            height). Must be provided with new_width.
          example: 800
    AdUnitGenerativeResizeResponse:
      type: object
      required:
      - workflow_id
      - status
      - ad_unit_id
      properties:
        workflow_id:
          type: string
          format: uuid
          description: ID of the created generative resize workflow
          example: 123e4567-e89b-12d3-a456-426614174000
        status:
          type: string
          enum:
          - generating
          description: Creative status after initiating regeneration (always 'generating')
          example: generating
        ad_unit_id:
          type: string
          format: uuid
          description: ID of the ad unit being regenerated
          example: 987fcdeb-51a2-43d1-b789-123456789abc
    CreateAssetValidationRequest:
      type: object
      required:
      - partner
      properties:
        partner:
          type: string
          example: walmart
          description: Partner to validate against
    AssetPartnerValidation:
      type: object
      required:
      - id
      - asset_id
      - partner
      - status
      - valid
      - errors
      - completed_at
      - created_at
      properties:
        id:
          type: string
          format: uuid
        asset_id:
          type: string
          format: uuid
        partner:
          type: string
          example: walmart
        status:
          type: string
          enum:
          - pending
          - processing
          - completed
          - failed
        valid:
          type: boolean
          nullable: true
          description: null while pending/processing, true if all checks pass, false
            if any fail
        errors:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/AssetValidationError'
          description: null while pending/processing or if valid, populated array
            if invalid
        created_at:
          type: string
          format: date-time
        completed_at:
          type: string
          format: date-time
          nullable: true
    AssetValidationError:
      type: object
      properties:
        field:
          type: string
          example: resolution
        message:
          type: string
          example: Video resolution 640x480 is below minimum 1280x720
        actual_value:
          type: string
          nullable: true
          example: 640x480
        expected_value:
          type: string
          nullable: true
          example: 1280x720 to 3840x2160
    CreateAssetValidationResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/AssetPartnerValidation'
    GetAssetValidationResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/AssetPartnerValidation'
    ListAssetValidationsResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/AssetPartnerValidation'
    AssetValidationConflictResponse:
      type: object
      required:
      - status
      - error
      - data
      properties:
        status:
          type: string
          example: error
        error:
          $ref: '#/components/schemas/ErrorError'
        data:
          $ref: '#/components/schemas/AssetPartnerValidation'
    WalmartVideoCreativeStatus:
      type: string
      enum:
      - draft
      - validating
      - validation_failed
      - ready_to_submit
      - submitting
      - submission_failed
      - submission_completed
      - walmart_draft
      - pending_approval
      - approved
      - rejected
      x-enum-varnames:
      - WALMART_VIDEO_CREATIVE_STATUS_DRAFT
      - WALMART_VIDEO_CREATIVE_STATUS_VALIDATING
      - WALMART_VIDEO_CREATIVE_STATUS_VALIDATION_FAILED
      - WALMART_VIDEO_CREATIVE_STATUS_READY_TO_SUBMIT
      - WALMART_VIDEO_CREATIVE_STATUS_SUBMITTING
      - WALMART_VIDEO_CREATIVE_STATUS_SUBMISSION_FAILED
      - WALMART_VIDEO_CREATIVE_STATUS_SUBMISSION_COMPLETED
      - WALMART_VIDEO_CREATIVE_STATUS_WALMART_DRAFT
      - WALMART_VIDEO_CREATIVE_STATUS_PENDING_APPROVAL
      - WALMART_VIDEO_CREATIVE_STATUS_APPROVED
      - WALMART_VIDEO_CREATIVE_STATUS_REJECTED
    WalmartVideoAdUnitStatus:
      type: string
      enum:
      - pending
      - ready
      - validation_failed
      x-enum-varnames:
      - WALMART_VIDEO_AD_UNIT_STATUS_PENDING
      - WALMART_VIDEO_AD_UNIT_STATUS_READY
      - WALMART_VIDEO_AD_UNIT_STATUS_VALIDATION_FAILED
    CreateWalmartVideoCreativeRequest:
      type: object
      required:
      - title
      - video_asset_id
      - logo_asset_id
      - headline
      - subhead
      - button_cta
      - logo_alt_text
      properties:
        title:
          type: string
          description: Internal title for the video creative
          example: Summer Video Campaign 2026
          minLength: 1
          maxLength: 255
        video_asset_id:
          type: string
          format: uuid
          description: Video asset ID
          example: 550e8400-e29b-41d4-a716-446655440001
        logo_asset_id:
          type: string
          format: uuid
          description: Brand logo asset ID
          example: 550e8400-e29b-41d4-a716-446655440002
        headline:
          type: string
          description: Headline text (max 25 chars)
          example: Save big this summer
          minLength: 1
          maxLength: 25
        subhead:
          type: string
          description: Subhead text (max 30 chars, must end with .!?* per Walmart
            specs)
          example: Up to 50% off everything!
          minLength: 1
          maxLength: 30
        button_cta:
          type: string
          description: Call-to-action button text (max 12 chars)
          example: Shop now
          minLength: 1
          maxLength: 12
        logo_alt_text:
          type: string
          description: Logo alt text (max 150 chars)
          example: Brand logo
          minLength: 1
          maxLength: 150
        legal_disclaimer_label:
          type: string
          nullable: true
          description: Legal disclaimer label text (max 600 chars, optional)
          example: Terms apply
          maxLength: 600
        legal_disclaimer_popup_copy:
          type: string
          nullable: true
          description: Legal disclaimer popup copy (max 600 chars, optional)
          example: See store for details. Terms and conditions apply.
          maxLength: 600
        generate_captions:
          type: boolean
          default: false
          description: Whether to generate captions for the video
        walmart_folder_id:
          type: string
          nullable: true
          description: Walmart DAM folder ID (optional)
          example: folder_12345
          maxLength: 255
    UpdateWalmartVideoCreativeRequest:
      type: object
      properties:
        title:
          type: string
          description: Internal title for the video creative
          minLength: 1
          maxLength: 255
        video_asset_id:
          type: string
          format: uuid
          description: Video asset ID
        logo_asset_id:
          type: string
          format: uuid
          description: Brand logo asset ID
        headline:
          type: string
          description: Headline text (max 25 chars)
          minLength: 1
          maxLength: 25
        subhead:
          type: string
          description: Subhead text (max 30 chars)
          minLength: 1
          maxLength: 30
        button_cta:
          type: string
          description: Call-to-action button text (max 12 chars)
          minLength: 1
          maxLength: 12
        logo_alt_text:
          type: string
          description: Logo alt text (max 150 chars)
          minLength: 1
          maxLength: 150
        legal_disclaimer_label:
          type: string
          nullable: true
          description: Legal disclaimer label text (max 600 chars, optional)
          maxLength: 600
        legal_disclaimer_popup_copy:
          type: string
          nullable: true
          description: Legal disclaimer popup copy (max 600 chars, optional)
          maxLength: 600
        generate_captions:
          type: boolean
          description: Whether to generate captions for the video
        walmart_folder_id:
          type: string
          nullable: true
          description: Walmart DAM folder ID (optional)
          maxLength: 255
    UpdateWalmartVideoAdUnitRequest:
      type: object
      properties:
        headline:
          type: string
          nullable: true
          description: Override headline for this ad unit (null = use creative default)
          maxLength: 25
        subhead:
          type: string
          nullable: true
          description: Override subhead for this ad unit (null = use creative default)
          maxLength: 30
        button_cta:
          type: string
          nullable: true
          description: Override CTA for this ad unit (null = use creative default)
          maxLength: 12
        logo_alt_text:
          type: string
          nullable: true
          description: Override logo alt text for this ad unit (null = use creative
            default)
          maxLength: 150
        legal_disclaimer_label:
          type: string
          nullable: true
          description: Override legal disclaimer label for this ad unit (null = use
            creative default)
          maxLength: 600
        legal_disclaimer_popup_copy:
          type: string
          nullable: true
          description: Override legal disclaimer popup copy for this ad unit (null
            = use creative default)
          maxLength: 600
    WalmartVideoAdSpec:
      type: object
      properties:
        id:
          type: string
          format: uuid
        internal_name:
          type: string
          description: Internal identifier (e.g., checkInVideo, brandboxDesktopVideo)
        display_name:
          type: string
          description: Human-readable name
        target_platform:
          type: string
          enum:
          - desktop
          - mobile
          - tablet
        logo_required:
          type: boolean
        logo_width:
          type: integer
          nullable: true
        logo_height:
          type: integer
          nullable: true
        headline_required:
          type: boolean
        headline_max_length:
          type: integer
          nullable: true
        subhead_required:
          type: boolean
        subhead_max_length:
          type: integer
          nullable: true
        button_cta_required:
          type: boolean
        button_cta_max_length:
          type: integer
          nullable: true
        logo_alt_text_required:
          type: boolean
        logo_alt_text_max_length:
          type: integer
          nullable: true
        legal_disclaimer_label_max_length:
          type: integer
          nullable: true
        legal_disclaimer_popup_copy_max_length:
          type: integer
          nullable: true
        alt_text_letters_only:
          type: boolean
          description: If true, logo_alt_text must contain only letters and spaces
        enabled:
          type: boolean
    WalmartVideoAdUnit:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organization_id:
          type: string
          format: uuid
        walmart_video_creative_id:
          type: string
          format: uuid
        walmart_video_ad_spec_id:
          type: string
          format: uuid
        ad_spec:
          $ref: '#/components/schemas/WalmartVideoAdSpec'
        preview_asset:
          nullable: true
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
        status:
          $ref: '#/components/schemas/WalmartVideoAdUnitStatus'
        headline:
          type: string
          nullable: true
          description: Override value or null (uses creative default)
        subhead:
          type: string
          nullable: true
          description: Override value or null (uses creative default)
        button_cta:
          type: string
          nullable: true
          description: Override value or null (uses creative default)
        logo_alt_text:
          type: string
          nullable: true
          description: Override value or null (uses creative default)
        legal_disclaimer_label:
          type: string
          nullable: true
          description: Override value or null (uses creative default)
        legal_disclaimer_popup_copy:
          type: string
          nullable: true
          description: Override value or null (uses creative default)
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    WalmartVideoCreativeReviewComment:
      type: object
      properties:
        id:
          type: string
          format: uuid
        walmart_comment_id:
          type: string
          nullable: true
          description: Walmart's comment ID
        asset:
          type: string
          nullable: true
          description: Asset type that was rejected
        ad_unit:
          type: string
          nullable: true
          description: Ad unit name that was rejected
        message:
          type: string
          description: Review comment message from Walmart
        created_at:
          type: string
          format: date-time
    WalmartVideoCreative:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organization_id:
          type: string
          format: uuid
        brand_id:
          type: string
          format: uuid
        created_by_user_id:
          type: string
          format: uuid
        title:
          type: string
          description: Internal title for the video creative
        video_asset:
          $ref: '#/components/schemas/AssetSummary'
        logo_asset:
          $ref: '#/components/schemas/AssetSummary'
        headline:
          type: string
          description: Default headline text
        subhead:
          type: string
          description: Default subhead text
        button_cta:
          type: string
          description: Default CTA text
        logo_alt_text:
          type: string
          description: Default logo alt text
        legal_disclaimer_label:
          type: string
          nullable: true
          description: Legal disclaimer label text
        legal_disclaimer_popup_copy:
          type: string
          nullable: true
          description: Legal disclaimer popup copy
        generate_captions:
          type: boolean
          description: Whether captions should be generated
        walmart_folder_id:
          type: string
          nullable: true
          description: Walmart DAM folder ID
        walmart_creative_id:
          type: string
          nullable: true
          description: Walmart creative ID after submission
        status:
          $ref: '#/components/schemas/WalmartVideoCreativeStatus'
        text_generation_status:
          type: string
          enum:
          - pending
          - completed
          - failed
          nullable: true
          description: Status of AI text generation workflow
        error:
          allOf:
          - $ref: '#/components/schemas/Error'
          nullable: true
          description: 'Classified error from the most recent text generation attempt.

            Populated when text_generation_status is ''failed''; null otherwise.

            '
        validation_errors:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/ValidationError-2'
          description: Video validation errors (if status is validation_failed)
        is_edited:
          type: boolean
          nullable: true
          description: Whether creative was edited after approval
        edited_at:
          type: string
          format: date-time
          nullable: true
          description: When creative was last edited (post-approval)
        submitted_at:
          type: string
          format: date-time
          nullable: true
          description: When creative was submitted to Walmart
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        ad_units:
          type: array
          items:
            $ref: '#/components/schemas/WalmartVideoAdUnit'
          description: All ad units for this creative (3 specs)
        review_comments:
          type: array
          items:
            $ref: '#/components/schemas/WalmartVideoCreativeReviewComment'
          description: Review comments from Walmart (if rejected)
    WalmartVideoCreativeSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
        title:
          type: string
          description: Internal title for the video creative
        status:
          $ref: '#/components/schemas/WalmartVideoCreativeStatus'
        text_generation_status:
          type: string
          enum:
          - pending
          - completed
          - failed
          nullable: true
          description: Status of AI text generation workflow
        ad_units_count:
          type: integer
          description: Number of ad units (always 3)
        video_asset:
          $ref: '#/components/schemas/AssetSummary'
        created_at:
          type: string
          format: date-time
    CreateWalmartVideoCreativeResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: object
          properties:
            id:
              type: string
              format: uuid
            status:
              $ref: '#/components/schemas/WalmartVideoCreativeStatus'
    GetWalmartVideoCreativeResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/WalmartVideoCreative'
    ListWalmartVideoCreativesResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          description: List of video creative summaries
          items:
            $ref: '#/components/schemas/WalmartVideoCreativeSummary'
        pagination:
          type: object
          required:
          - page
          - page_size
          - total_items
          - total_pages
          properties:
            page:
              type: integer
              description: Current page number (1-indexed)
            page_size:
              type: integer
              description: Number of items per page
            total_items:
              type: integer
              description: Total number of items across all pages
            total_pages:
              type: integer
              description: Total number of pages
    SubmitWalmartVideoCreativeResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: object
          properties:
            message:
              type: string
              example: Video creative submission workflow started
            workflow_id:
              type: string
              format: uuid
            creative_id:
              type: string
              format: uuid
    WalmartMediaStatus:
      type: string
      description: 'Lifecycle status of the Sponsored Video creative. Superset of
        Walmart''s

        three media states: `pending`/`uploading` are internal pre-upload states,

        `processing` maps to Walmart PENDING, `available` maps to Walmart AVAILABLE,

        `failed` covers both a spec failure (valid=false) and a Walmart-side

        upload/processing failure (valid=true).

        '
      enum:
      - pending
      - uploading
      - processing
      - available
      - failed
      x-enum-varnames:
      - WALMART_MEDIA_STATUS_PENDING
      - WALMART_MEDIA_STATUS_UPLOADING
      - WALMART_MEDIA_STATUS_PROCESSING
      - WALMART_MEDIA_STATUS_AVAILABLE
      - WALMART_MEDIA_STATUS_FAILED
      example: pending
    SponsoredVideoValidationError:
      type: object
      required:
      - field
      - message
      properties:
        field:
          type: string
          description: Field that failed validation
          example: duration
        message:
          type: string
          description: Human-readable error message
          example: Video duration 45s exceeds the maximum of 30s for Sponsored Video.
        actual_value:
          type: string
          nullable: true
          description: The actual value found
          example: '45'
        expected_value:
          type: string
          nullable: true
          description: The expected value
          example: <= 30
    CreateWalmartSponsoredVideoCreativeRequest:
      type: object
      required:
      - label
      - video_asset_id
      properties:
        label:
          type: string
          description: 'User label; becomes the Walmart mediaName. Max 45 chars, no
            special

            characters.

            '
          example: Summer Promo Video
          minLength: 1
          maxLength: 45
        video_asset_id:
          type: string
          format: uuid
          description: Source video asset ID (must belong to the brand)
          example: 550e8400-e29b-41d4-a716-446655440001
    UpdateWalmartSponsoredVideoCreativeRequest:
      type: object
      required:
      - label
      properties:
        label:
          type: string
          description: 'New label. Allowed only while status is `pending` or a spec
            `failed`

            (valid=false), i.e. before the video reaches Walmart. Max 45 chars,

            no special characters.

            '
          example: Summer Promo Video v2
          minLength: 1
          maxLength: 45
    WalmartSponsoredVideoCreative:
      type: object
      required:
      - id
      - brand_id
      - label
      - video_asset_id
      - walmart_media_status
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        organization_id:
          type: string
          format: uuid
          readOnly: true
        brand_id:
          type: string
          format: uuid
          readOnly: true
        created_by_user_id:
          type: string
          format: uuid
          readOnly: true
        label:
          type: string
          description: User label; becomes Walmart mediaName
          example: Summer Promo Video
        video_asset_id:
          type: string
          format: uuid
          description: Source video asset ID
        video_asset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
          description: Nested summary of the source video asset
        walmart_media_id:
          type: string
          nullable: true
          description: 'Walmart media id, set after the complete call. Presence drives

            idempotent retry (retry resumes at polling when this is set).

            '
          example: media_abc123
        walmart_media_status:
          $ref: '#/components/schemas/WalmartMediaStatus'
        valid:
          type: boolean
          nullable: true
          description: 'Validation discriminator. null = not yet validated, true =
            passed specs

            (a `failed` here is a Walmart-side failure and is retryable),

            false = failed specs (terminal, not retryable).

            '
        validation_errors:
          type: array
          nullable: true
          items:
            $ref: '#/components/schemas/SponsoredVideoValidationError'
          description: 'Per-field spec validation errors. Populated only when valid=false;

            null for a Walmart-side failure.

            '
        submitted_at:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: When the workflow last started (set on create and each retry)
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true
    WalmartSponsoredVideoCreativeSummary:
      type: object
      required:
      - id
      - label
      - walmart_media_status
      - created_at
      properties:
        id:
          type: string
          format: uuid
        label:
          type: string
        walmart_media_status:
          $ref: '#/components/schemas/WalmartMediaStatus'
        valid:
          type: boolean
          nullable: true
        walmart_media_id:
          type: string
          nullable: true
        video_asset:
          allOf:
          - $ref: '#/components/schemas/AssetSummary'
          nullable: true
        created_at:
          type: string
          format: date-time
    CreateWalmartSponsoredVideoCreativeResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: object
          properties:
            id:
              type: string
              format: uuid
            walmart_media_status:
              $ref: '#/components/schemas/WalmartMediaStatus'
        message:
          type: string
          example: Sponsored Video creative created; upload workflow started
    GetWalmartSponsoredVideoCreativeResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/WalmartSponsoredVideoCreative'
        message:
          type: string
          example: ''
    ListWalmartSponsoredVideoCreativesResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          description: List of Sponsored Video creative summaries
          items:
            $ref: '#/components/schemas/WalmartSponsoredVideoCreativeSummary'
        pagination:
          type: object
          required:
          - page
          - page_size
          - total_items
          - total_pages
          properties:
            page:
              type: integer
              description: Current page number (1-indexed)
            page_size:
              type: integer
              description: Number of items per page
            total_items:
              type: integer
              description: Total number of items across all pages
            total_pages:
              type: integer
              description: Total number of pages
    RetryWalmartSponsoredVideoCreativeResponse:
      type: object
      properties:
        status:
          type: string
          example: success
        data:
          type: object
          properties:
            message:
              type: string
              example: Sponsored Video upload workflow restarted
            workflow_id:
              type: string
              format: uuid
            creative_id:
              type: string
              format: uuid
    TemplateStatus:
      type: string
      enum:
      - draft
      - published
      description: Publish state of a template.
      example: draft
    Dimensions:
      type: object
      required:
      - width
      - height
      properties:
        width:
          type: integer
          description: Canvas width in pixels.
          example: 1080
        height:
          type: integer
          description: Canvas height in pixels.
          example: 1080
    CreateTemplateRequest:
      type: object
      required:
      - name
      - dimensions
      - layers
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          example: Summer Sale
        dimensions:
          $ref: '#/components/schemas/Dimensions'
        layers:
          type: array
          description: Layer documents (FE LayerApi shape). Stored verbatim.
          items:
            type: object
            additionalProperties: true
        status:
          allOf:
          - $ref: '#/components/schemas/TemplateStatus'
          description: Initial publish state. Defaults to draft when omitted.
        partners:
          type: array
          description: Partner slugs this template targets (NAT-1676, many-to-many).
          items:
            $ref: '#/components/schemas/Partner'
        contentType:
          allOf:
          - $ref: '#/components/schemas/ContentType'
          nullable: true
          description: Content-type slug this template targets (NAT-1677, partner-agnostic).
            Maps to templates.content_type.
    UpdateTemplateRequest:
      type: object
      description: Full-document save (PUT). Any subset of fields may be provided.
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        dimensions:
          $ref: '#/components/schemas/Dimensions'
        layers:
          type: array
          items:
            type: object
            additionalProperties: true
        status:
          allOf:
          - $ref: '#/components/schemas/TemplateStatus'
        partners:
          type: array
          description: Partner slugs this template targets (NAT-1676, many-to-many).
          items:
            $ref: '#/components/schemas/Partner'
        contentType:
          allOf:
          - $ref: '#/components/schemas/ContentType'
          nullable: true
          description: Content-type slug this template targets (NAT-1677, partner-agnostic).
            Maps to templates.content_type.
    SetTemplateStatusRequest:
      type: object
      required:
      - status
      properties:
        status:
          $ref: '#/components/schemas/TemplateStatus'
    Template:
      type: object
      required:
      - id
      - brandId
      - name
      - dimensions
      - status
      - layers
      - createdAt
      - updatedAt
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        brandId:
          type: string
          format: uuid
          readOnly: true
        name:
          type: string
          example: Summer Sale
        dimensions:
          $ref: '#/components/schemas/Dimensions'
        status:
          $ref: '#/components/schemas/TemplateStatus'
        partners:
          type: array
          description: Partner slugs this template targets (NAT-1676, many-to-many).
          items:
            $ref: '#/components/schemas/Partner'
        contentType:
          allOf:
          - $ref: '#/components/schemas/ContentType'
          nullable: true
          description: Content-type slug this template targets (NAT-1677, partner-agnostic).
            Maps to templates.content_type.
        layers:
          type: array
          description: Layer documents (FE LayerApi shape).
          items:
            type: object
            additionalProperties: true
        thumbnailUrl:
          type: string
          nullable: true
          readOnly: true
          description: Presigned URL of the rendered thumbnail (null until first render).
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
        lastEditedAt:
          type: string
          format: date-time
          nullable: true
          readOnly: true
          description: Last content/layer edit timestamp (distinct from updatedAt).
    TemplateResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/Template'
    ListTemplatesResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/Template'
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    FontCatalogueEntry:
      type: object
      required:
      - family
      - label
      - isCustom
      properties:
        family:
          type: string
          description: Font family name (the value persisted on a text layer's `font`).
          example: Inter
        isCustom:
          type: boolean
          description: True for brand-uploaded custom fonts (S3-hosted); false for
            the curated Google catalogue.
          example: false
        label:
          type: string
          description: Human-friendly display label for the picker.
          example: Inter
        weights:
          type: array
          description: Available numeric weights (e.g. 400, 700).
          items:
            type: integer
        previewUrl:
          type: string
          nullable: true
          description: Optional preview/stylesheet URL (presigned for custom uploads;
            Google css2 for catalogue entries).
        files:
          type: object
          nullable: true
          additionalProperties:
            type: string
          description: Optional variant→face-url map for uploaded/brand-hosted fonts.
    ListFontsResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/FontCatalogueEntry'
    FontResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/FontCatalogueEntry'
    CreativeResizeStatus:
      type: string
      enum:
      - queued
      - rendering
      - done
      - failed
      x-enum-varnames:
      - CreativeResizeStatusQueued
      - CreativeResizeStatusRendering
      - CreativeResizeStatusDone
      - CreativeResizeStatusFailed
      description: Resize sub-process lifecycle state.
    CreativeExportStatus:
      type: string
      enum:
      - pending
      - done
      - failed
      x-enum-varnames:
      - CreativeExportStatusPending
      - CreativeExportStatusDone
      - CreativeExportStatusFailed
      description: Export state — pending until the FE uploads the combined image
        via /export; done when the export committed; failed when a blocking compose
        hardspec violation (dimensions, aspect, format, file size, or text char-limits)
        rejected the export (NAT-1716). A failed export has no export asset and no
        download URL; the offending checks are on `warnings`.
    CreateCreativeRequest:
      type: object
      required:
      - sourceAssetId
      - templateId
      properties:
        sourceAssetId:
          type: string
          format: uuid
          description: The source image asset (e.g. a Scene Forge output) to fit into
            the template.
        templateId:
          type: string
          format: uuid
          description: The template to build from. Its document is copied into the
            creative; its first image slot sets the resize target dims.
        partner:
          $ref: '#/components/schemas/Partner'
    UpdateCreativeRequest:
      type: object
      required:
      - document
      properties:
        document:
          type: object
          additionalProperties: true
          description: The edited creative document (the FE's working copy — edits
            the creative, not the template).
    Creative:
      type: object
      required:
      - id
      - brandId
      - document
      - resizeStatus
      - exportStatus
      - createdAt
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        brandId:
          type: string
          format: uuid
          readOnly: true
        templateId:
          type: string
          format: uuid
          nullable: true
        document:
          type: object
          additionalProperties: true
          description: The creative's own editable document (copied from the template
            at create; FE edits it and composites it at export).
        sourceAssetId:
          type: string
          format: uuid
          nullable: true
        sourceUrl:
          type: string
          nullable: true
          readOnly: true
        resizeStatus:
          $ref: '#/components/schemas/CreativeResizeStatus'
        resizedAssetId:
          type: string
          format: uuid
          nullable: true
        resizedUrl:
          type: string
          nullable: true
          readOnly: true
          description: Presigned URL of the resized source image (when resize done).
        resizeFailureReason:
          type: string
          nullable: true
        exportStatus:
          $ref: '#/components/schemas/CreativeExportStatus'
        exportAssetId:
          type: string
          format: uuid
          nullable: true
        exportUrl:
          type: string
          nullable: true
          readOnly: true
          description: Presigned URL of the exported combined image (when exported).
            WITHHELD (null) while moderationStatus is pending or blocked.
        moderationStatus:
          type: string
          nullable: true
          readOnly: true
          description: 'Final-creative ML text-moderation gate (NAT-1677). null =
            not moderated

            (downloadable); pending = moderation running (exportUrl withheld); approved

            (exportUrl exposed); blocked (exportUrl withheld — see the error-severity

            entries in warnings for the per-layer reasons). Only creatives whose

            (partner, content_type) has a hardspec are gated. FE polls this after
            export.

            '
        createdAt:
          type: string
          format: date-time
          readOnly: true
        updatedAt:
          type: string
          format: date-time
          readOnly: true
        contentType:
          allOf:
          - $ref: '#/components/schemas/ContentType'
          nullable: true
          description: Content-type slug (NAT-1677). Inherited from the source template
            at create. Maps to compose_creatives.content_type.
        warnings:
          type: array
          nullable: true
          description: 'Non-blocking partner hardspec-compatibility and ML moderation
            warnings

            (NAT-1677). For compose this carries the export-time hardspec + promo-copy

            warnings (surfaced via the /export op, which returns this Creative).

            Empty/absent when the creative matches the partner''s specs, has no partner,

            or the partner has no image specs. DISTINCT from hard errors — a real

            policy violation / failure still fails via error_type.

            '
          items:
            $ref: '#/components/schemas/GenerationWarning'
    CreativeResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          $ref: '#/components/schemas/Creative'
    ListCreativesResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/Creative'
        pagination:
          $ref: '#/components/schemas/PaginationInfo'
    WebfontApi:
      type: object
      required:
      - family
      - category
      - variants
      - subsets
      - files
      - menu
      properties:
        family:
          type: string
          example: ABeeZee
        category:
          type: string
          description: sans-serif | serif | display | handwriting | monospace
          example: sans-serif
        variants:
          type: array
          description: Weight + style tokens (regular, italic, 700, 700italic, ...).
          items:
            type: string
        subsets:
          type: array
          items:
            type: string
        files:
          type: object
          description: variant → TTF url.
          additionalProperties:
            type: string
        menu:
          type: string
          description: Single-glyph preview face URL.
    ListWebfontsResponse:
      type: object
      required:
      - status
      - data
      properties:
        status:
          type: string
          example: success
        data:
          type: array
          items:
            $ref: '#/components/schemas/WebfontApi'
    StatusResponse:
      type: object
      required:
      - status
      properties:
        status:
          type: string
          example: success
    ErrorError:
      type: object
      required:
      - code
      - message
      properties:
        code:
          type: string
          example: INVALID_REQUEST
        message:
          type: string
          example: Invalid input data provided
        details:
          description: Additional error context (optional, can be object or array)
    AssetQualityTagLevelEnum:
      type: string
      enum:
      - ok
      - warning
      - critical
      x-enum-varnames:
      - AssetQualityTagLevelOk
      - AssetQualityTagLevelWarning
      - AssetQualityTagLevelCritical
      description: Severity level of the quality issue
    AssetQualityTagReasonCodeEnum:
      type: string
      enum:
      - low-quality-scores
      - low-resolution
      - lossy-format
      - other
      x-enum-varnames:
      - AssetQualityTagReasonCodeLowQualityScores
      - AssetQualityTagReasonCodeLowResolution
      - AssetQualityTagReasonCodeLossyFormat
      - AssetQualityTagReasonCodeOther
      description: Specific reason for the quality assessment
    AssetQualityTag:
      type: object
      required:
      - level
      properties:
        level:
          $ref: '#/components/schemas/AssetQualityTagLevelEnum'
        reasonCode:
          $ref: '#/components/schemas/AssetQualityTagReasonCodeEnum'
        reason:
          type: string
          description: Human-readable description of the quality issue. This might
            come from vision-LLMs.
          example: Image appears blurry due to low resolution.
        recommendation:
          type: string
          description: Recommended action to fix the quality issue.
          example: Upload higher resolution image (Above 1000 pixels).
    AssessmentStatus:
      type: string
      enum:
      - processing
      - complete
      - failed
      x-enum-varnames:
      - AssessmentStatusProcessing
      - AssessmentStatusComplete
      - AssessmentStatusFailed
      description: Overall status of quality assessment operation (both immediate
        checks and background workflow)
    AssetQualityAssessment:
      type: object
      description: Wrapper model tracking overall quality assessment status
      required:
      - assetId
      - status
      properties:
        assetId:
          type: string
          format: uuid
          description: ID of the asset being assessed
        status:
          $ref: '#/components/schemas/AssessmentStatus'
          description: Current status of the quality assessment workflow
    CreateBrandRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          example: Acme Corporation
        industry:
          type: string
          minLength: 1
          maxLength: 50
          example: Technology
        description:
          type: string
          minLength: 10
          maxLength: 280
          example: Leading provider of innovative cloud solutions
        mission:
          type: string
          maxLength: 1000
          example: To accelerate the world's transition to sustainable technology
        values:
          type: array
          items:
            type: string
            maxLength: 50
          maxItems: 10
          example:
          - Innovation
          - Sustainability
          - Customer Focus
        tone:
          type: array
          items:
            type: string
            enum:
            - Professional
            - Casual
            - Friendly
            - Authoritative
            - Playful
            - Innovative
            - Traditional
            - Luxurious
            maxItems: 5
          example:
          - Professional
          - Innovative
        voice:
          type: array
          items:
            type: string
            maxLength: 50
          maxItems: 5
          example:
          - Clear
          - Confident
          - Expert
        logoAssetId:
          type: string
          format: uuid
          description: ID of an existing asset to be used as the brand's logo, should
            be a logo asset.
          example: 123e4567-e89b-12d3-a456-426614174000
          nullable: true
      required:
      - name
      - industry
      - description
      - mission
      - values
      - tone
      - voice
    UpdateBrandRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          example: Acme Corporation
          nullable: true
        industry:
          type: string
          minLength: 1
          maxLength: 50
          example: Technology
          nullable: true
        description:
          type: string
          minLength: 10
          maxLength: 280
          example: Leading provider of innovative cloud solutions
          nullable: true
        mission:
          type: string
          maxLength: 1000
          example: To accelerate the world's transition to sustainable technology
          nullable: true
        values:
          type: array
          items:
            type: string
            maxLength: 50
          maxItems: 10
          example:
          - Innovation
          - Sustainability
          - Customer Focus
          nullable: true
        tone:
          type: array
          items:
            type: string
            enum:
            - Professional
            - Casual
            - Friendly
            - Authoritative
            - Playful
            - Innovative
            - Traditional
            - Luxurious
            maxItems: 5
          example:
          - Professional
          - Innovative
          nullable: true
        voice:
          type: array
          items:
            type: string
            maxLength: 50
          maxItems: 5
          example:
          - Clear
          - Confident
          - Expert
          nullable: true
        logoAssetId:
          type: string
          format: uuid
          description: ID of an existing asset to update the brand's logo. Send null
            to disassociate logo.
          example: 123e4567-e89b-12d3-a456-426614174000
          nullable: true
    BrandDnaResponse:
      type: object
      properties:
        brandId:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - none
          - pending
          - extracting
          - ready
          - failed
          description: Current Brand DNA extraction status
        version:
          type: integer
          description: Current Brand DNA version (0 if no extraction has been done)
        brandDna:
          type: object
          nullable: true
          description: The merged Brand DNA JSON (null if not ready)
        sourceAssetIds:
          type: array
          items:
            type: string
            format: uuid
          description: Asset IDs of PDFs used in this version
      required:
      - brandId
      - status
      - version
    PartnerFilter:
      type: string
      description: Partner list filter. Omit for the `default` bucket only; `all`
        returns every partner; otherwise a single partner slug.
      enum:
      - all
      - default
      - walmart
      - chewy
      x-enum-varnames:
      - PARTNER_FILTER_ALL
      - PARTNER_FILTER_DEFAULT
      - PARTNER_FILTER_WALMART
      - PARTNER_FILTER_CHEWY
      example: all
    WalmartCreativeReviewComment:
      type: object
      required:
      - id
      - message
      - created_at
      properties:
        id:
          type: string
          format: uuid
          description: Internal comment ID
        walmart_comment_id:
          type: string
          nullable: true
          description: Walmart's comment ID
        asset:
          type: string
          nullable: true
          description: 'Asset type: logo, image, headline, etc.'
          example: logo
        ad_unit:
          type: string
          nullable: true
          description: Ad unit internal name (e.g., marqueeDesktop)
          example: marqueeDesktop
        message:
          type: string
          description: Review feedback message from Walmart
          example: Logo image quality is too low. Please provide higher resolution.
        created_at:
          type: string
          format: date-time
          description: When comment was created
    ValidationError-2:
      type: object
      required:
      - field
      - message
      properties:
        field:
          type: string
          description: Field that failed validation
          example: format
        message:
          type: string
          description: Human-readable error message
          example: Video format 'avi' is not supported. Must be MP4 or MOV.
        actual_value:
          type: string
          nullable: true
          description: The actual value found
          example: avi
        expected_value:
          type: string
          nullable: true
          description: The expected value
          example: MP4 or MOV
    GenerativeResizeError:
      type: object
      required:
      - code
      - message
      description: 'Canonical error object surfaced on failed Variant / Size / Group
        nodes. `code`

        is one of `UserRequestError` | `ModelProviderError` | `NativeAdsSystemError`;

        legacy / non-canonical DB values are clamped to `NativeAdsSystemError` at

        read time. `message` is user-facing.

        '
      properties:
        code:
          type: string
        message:
          type: string
          nullable: true
  parameters:
    CreativeIdPath:
      name: creativeId
      in: path
      required: true
      schema:
        type: string
        format: uuid
    AdUnitIdPath:
      name: adUnitId
      in: path
      required: true
      schema:
        type: string
        format: uuid
