openapi: 3.0.3
info:
  title: WaveForge Preview (ChatGPT Actions)
  version: "1.0.0"
  description: |
    Queue a watermarked 720p music-visualizer preview from a public audio URL.
    Preview is free (no credits charged) and capped at 60 seconds (auto-trimmed).
    The picture is driven by the actual audio mix — no generated performances.
    Poll the status endpoint until `status` is completed and a preview page is available.
servers:
  - url: https://waveforge.net
paths:
  /api/agent/v1/preview:
    post:
      operationId: createAgentPreview
      summary: Queue a preview render from an audio URL
      description: |
        Creates a preview job from a public https audio file and optional cover image.
        Call this when the user has a finished song or beat (a public audio link) and
        wants a video of it. Returns an opaque id and a status URL to poll.
        rights_attested must be true — the caller affirms rights to the media.
      x-openai-isConsequential: false
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [audio_url, rights_attested]
              properties:
                audio_url:
                  type: string
                  description: Public https URL of the audio file (mp3, wav, or m4a).
                  example: https://example.com/track.mp3
                image_url:
                  type: string
                  description: Optional public cover-image URL.
                  example: https://example.com/cover.jpg
                title:
                  type: string
                  maxLength: 120
                  description: Optional title shown on the video.
                rights_attested:
                  type: boolean
                  description: Must be true. Affirms you have rights to the audio and image.
      responses:
        "200":
          description: Queued (desktop worker online)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewAccepted"
        "202":
          description: Queued while the desktop worker is offline (CPU fallback)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewAccepted"
        "400":
          description: Validation error, SSRF-blocked URL, or rights_attested false
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "401":
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "429":
          description: Caller, conversation, or global daily cap reached
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /api/agent/v1/status/{id}:
    get:
      operationId: getAgentPreviewStatus
      summary: Poll a preview's status
      description: |
        Returns the current status of a preview job. Poll every few seconds until
        status is "completed" or "failed". No raw internal job id is exposed.
      x-openai-isConsequential: false
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: The opaque id returned by createAgentPreview (starts with ado_).
          schema:
            type: string
            pattern: "^ado_"
      responses:
        "200":
          description: Status payload
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreviewStatus"
        "401":
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          description: Unknown id or feature disabled
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
  schemas:
    PreviewAccepted:
      type: object
      properties:
        id:
          type: string
          description: Opaque preview id (ado_...).
        status:
          type: string
          description: queued or processing.
        status_url:
          type: string
          description: Path to poll for status.
        preview_page:
          type: string
          nullable: true
          description: URL of the preview page once available.
        queue_position:
          type: integer
          description: Position in the render queue.
        worker_online:
          type: boolean
          description: Whether the GPU worker is online.
        message:
          type: string
        audio_trimmed_to_60s:
          type: boolean
          description: True if the audio was trimmed to 60 seconds.
        note:
          type: string
        tos:
          type: string
        takedown_contact:
          type: string
          nullable: true
    PreviewStatus:
      type: object
      properties:
        id:
          type: string
        status:
          type: string
          description: queued, processing, completed, or failed.
        progress:
          type: integer
          description: 0-100 completion percentage.
        preview_page:
          type: string
          nullable: true
          description: URL of the finished preview once completed.
        queue_position:
          type: integer
        worker_online:
          type: boolean
        message:
          type: string
        error:
          type: string
          nullable: true
        tos:
          type: string
        takedown_contact:
          type: string
          nullable: true
    Error:
      type: object
      properties:
        error:
          type: string
        tos:
          type: string
        takedownContact:
          type: string
