{
  "openapi": "3.0.3",
  "info": {
    "title": "Anim8e Episode Workflow API",
    "version": "1.2.0",
    "description": "Durable source-to-preproduction workflow. Output selection controls returned data; the complete preparation pipeline still runs. Video rendering is a separate creator operation. Source review remains a distinct human assessment. Location preparation analyses full source shots by default. references.byShot[].locationAnalysis contains sourceStart/sourceEnd, method, verifiedAt and locations keyed by normalized name. Each location includes timestamp, frameUrl, frameSha256, evidence and views (start/end source seconds, timestamp, camera, evidence, frameUrl/frameSha256). Null means not analysed; it is not verification. Existing completed renders are preserved. Supporting camera evidence informs one primary animated location card; separate animated cards for every angle are not implied. Shared asset verification: status/result include verification status ready, repairing, needs_input, paused or not_checked. Ready requires fresh complete visual and file evidence. POST ?action=verify starts bounded source inspection and repairs; pause_verification/resume_verification control only this work. Bodies: jobId, requestId, optional shotIds. Video is never submitted by verification. Missing identity can require input; no guaranteed clean report."
  },
  "servers": [
    {
      "url": "https://baalveer.anim8e.com/v2s"
    }
  ],
  "security": [
    {
      "workflowKey": []
    },
    {
      "bearerAuth": []
    },
    {
      "studioSession": []
    }
  ],
  "paths": {
    "/workflow-api.php": {
      "post": {
        "operationId": "controlEpisodePreparation",
        "summary": "Prepare, resume, verify or repair episode assets",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "prepare",
                "resume",
                "verify",
                "pause_verification",
                "resume_verification"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "anyOf": [
                  {
                    "$ref": "#/components/schemas/Prepare"
                  },
                  {
                    "$ref": "#/components/schemas/Resume"
                  },
                  {
                    "$ref": "#/components/schemas/VerificationRequest"
                  }
                ]
              },
              "examples": {
                "prepare": {
                  "value": {
                    "requestId": "episode-101-prepare-001",
                    "episodeNumber": 101,
                    "source": {
                      "url": "https://www.youtube.com/watch?v=VIDEO_ID_HERE"
                    },
                    "outputs": [
                      "script",
                      "sequence_plan",
                      "shot_packets",
                      "references",
                      "verification"
                    ],
                    "options": {
                      "maxClipSeconds": 30,
                      "generateMissingAssets": true,
                      "reuseSavedWork": true
                    }
                  }
                },
                "verify": {
                  "value": {
                    "jobId": "wf_5_0123456789abcdef01234567",
                    "requestId": "verify-episode-5-001"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Durable job accepted or prior matching request recovered. job.id, status, stage, progress, sourceReview and links are returned."
          },
          "401": {
            "description": "Sign in or provide an API key."
          },
          "403": {
            "description": "Operation is outside the account or key scope."
          },
          "422": {
            "description": "Invalid or unsupported inputs; nothing dispatched."
          },
          "503": {
            "description": "Service unavailable or uncertain dispatch; retry the exact request with the same requestId."
          }
        }
      },
      "get": {
        "operationId": "inspectEpisodeWorkflow",
        "summary": "Get status, selected results, artifacts, or this schema",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "status",
                "result",
                "artifact",
                "schema"
              ]
            }
          },
          {
            "name": "jobId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Required except for schema."
          },
          {
            "name": "outputs",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Optional comma-separated subset: script, sequence_plan, shot_packets, references, verification"
          },
          {
            "name": "name",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "script.txt",
                "script.pdf",
                "shot-plan.json",
                "seedance_prompt_batches.json",
                "seedance_prompt_batches.md",
                "result.json",
                "continuity-validation.json"
              ]
            },
            "description": "Required for artifact."
          }
        ],
        "responses": {
          "200": {
            "description": "Read-only response. Results may be partial: inspect outputs[name].available and issues. Technical checks and human source verification are separate."
          },
          "401": {
            "description": "Authentication required (schema is public)."
          },
          "422": {
            "description": "Invalid job or output selection."
          },
          "503": {
            "description": "Unavailable dependency; saved work is retained."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Scoped management API key. Send only to baalveer.anim8e.com over HTTPS."
      },
      "studioSession": {
        "type": "apiKey",
        "in": "cookie",
        "name": "sfa_balveer_session"
      },
      "workflowKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Anim8e-Workflow-Key",
        "description": "Preferred on this deployment; the hosting proxy strips Authorization headers."
      }
    },
    "schemas": {
      "Prepare": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "requestId",
          "episodeNumber",
          "source"
        ],
        "properties": {
          "requestId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,80}$",
            "description": "Reuse unchanged when retrying an uncertain request."
          },
          "episodeNumber": {
            "type": "integer",
            "minimum": 1,
            "maximum": 2000
          },
          "source": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "HTTPS YouTube video URL; must agree with the episode catalog or saved source."
              }
            }
          },
          "outputs": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "enum": [
                "script",
                "sequence_plan",
                "shot_packets",
                "references",
                "verification"
              ]
            },
            "default": [
              "script",
              "sequence_plan",
              "shot_packets",
              "references",
              "verification"
            ]
          },
          "options": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "maxClipSeconds": {
                "type": "integer",
                "enum": [
                  30
                ],
                "default": 30
              },
              "generateMissingAssets": {
                "type": "boolean",
                "enum": [
                  true
                ],
                "default": true
              },
              "reuseSavedWork": {
                "type": "boolean",
                "enum": [
                  true
                ],
                "default": true
              }
            }
          }
        }
      },
      "Resume": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "requestId",
          "jobId"
        ],
        "properties": {
          "requestId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,80}$"
          },
          "jobId": {
            "type": "string"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "retryWithSameRequestId": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "VerificationRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "jobId",
          "requestId"
        ],
        "properties": {
          "jobId": {
            "type": "string",
            "pattern": "^wf_[0-9]{1,4}_[a-f0-9]{24}$"
          },
          "requestId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{8,100}$"
          },
          "shotIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "For verify only: explicit included shot IDs. Omit to check all included shots. Resume and pause retain the saved scope."
          }
        }
      }
    }
  }
}
