{
  "openapi": "3.1.0",
  "info": {
    "title": "AI Video Maker API",
    "version": "2.0.0",
    "description": "Quote, create, monitor, retrieve, and cancel AI video tasks. API credits are separate from website subscription entitlements."
  },
  "servers": [{ "url": "https://aivideomaker.ai" }],
  "components": {
    "securitySchemes": {
      "apiKey": { "type": "apiKey", "in": "header", "name": "key" }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Stable unique key for this logical generation. Repeating the same request with the same key returns the original task without charging again.",
        "schema": { "type": "string", "minLength": 8, "maxLength": 128 }
      },
      "MaxCredits": {
        "name": "X-Max-Credits",
        "in": "header",
        "required": false,
        "description": "Maximum charge approved by the caller. The request is rejected before billing if the authoritative quote is higher.",
        "schema": { "type": "integer", "minimum": 0 }
      }
    },
    "schemas": {
      "TaskStatus": {
        "type": "string",
        "enum": ["SUBMITTED", "PROGRESS", "COMPLETED", "FAILED", "CANCEL"]
      },
      "MiniMaxH3Request": {
        "type": "object",
        "required": ["content"],
        "properties": {
          "content": { "type": "string" },
          "duration": { "type": "integer", "minimum": 5, "maximum": 20, "default": 5 },
          "resolution": { "type": "string", "enum": ["720p", "1080p"], "default": "720p" },
          "tier": { "type": "string", "enum": ["turbo", "base"], "default": "turbo" },
          "aspectRatio": {
            "type": "string",
            "enum": ["auto", "21:9", "16:9", "4:3", "1:1", "3:4", "9:16"],
            "default": "16:9"
          },
          "imageUrl": { "type": ["string", "null"] },
          "lastFrameUrl": { "type": ["string", "null"] },
          "referenceImageUrls": { "type": "array", "maxItems": 4, "items": { "type": "string" } },
          "referenceVideoUrl": { "type": ["string", "null"], "format": "uri" },
          "referenceAudioUrls": {
            "type": "array",
            "maxItems": 2,
            "items": { "type": "string", "format": "uri" }
          }
        },
        "allOf": [
          {
            "description": "Frame inputs and reference assets are mutually exclusive. Image fields accept public HTTP(S) URLs or image data URIs; video and audio fields accept public HTTP(S) URLs."
          }
        ]
      },
      "Quote": {
        "type": "object",
        "required": [
          "model",
          "credits",
          "listPriceUsd",
          "usdPerCredit",
          "currentBalance",
          "affordable",
          "billable"
        ],
        "properties": {
          "model": { "type": "string" },
          "credits": { "type": "integer", "minimum": 0 },
          "listPriceUsd": { "type": "number", "minimum": 0 },
          "usdPerCredit": { "type": "number", "const": 0.01 },
          "currentBalance": { "type": "integer", "minimum": 0 },
          "affordable": { "type": "boolean" },
          "billable": { "type": "boolean", "const": false }
        }
      },
      "SubmittedTask": {
        "type": "object",
        "required": [
          "status",
          "taskId",
          "creditsCharged",
          "idempotentReplay",
          "responseUrl",
          "statusUrl",
          "cancelUrl"
        ],
        "properties": {
          "status": { "$ref": "#/components/schemas/TaskStatus" },
          "taskId": { "type": "string" },
          "creditsCharged": { "type": "integer", "minimum": 0 },
          "idempotentReplay": { "type": "boolean" },
          "responseUrl": { "type": "string", "format": "uri" },
          "statusUrl": { "type": "string", "format": "uri" },
          "cancelUrl": { "type": "string", "format": "uri" }
        }
      },
      "Task": {
        "type": "object",
        "required": [
          "id",
          "model",
          "input",
          "status",
          "creditsCharged",
          "creditsRefunded",
          "listValueCents"
        ],
        "properties": {
          "id": { "type": "string" },
          "createdAt": { "type": "string", "format": "date-time" },
          "model": { "type": "string" },
          "input": { "type": "object" },
          "output": {
            "oneOf": [
              { "type": "null" },
              {
                "type": "object",
                "properties": {
                  "url": { "type": "string", "format": "uri" },
                  "msg": { "type": "string" },
                  "error": { "type": "string" }
                }
              }
            ]
          },
          "status": { "$ref": "#/components/schemas/TaskStatus" },
          "creditsCharged": { "type": "integer", "minimum": 0 },
          "creditsRefunded": { "type": "integer", "minimum": 0 },
          "listValueCents": {
            "type": "integer",
            "minimum": 0,
            "description": "List-price value of net credits consumed; this is not payment revenue."
          },
          "idempotencyKey": { "type": ["string", "null"] },
          "completedAt": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "status": { "const": "FAILED" },
          "errorCode": {
            "type": "string",
            "examples": [
              "AUTH_FAILED",
              "BUDGET_EXCEEDED",
              "IDEMPOTENCY_CONFLICT",
              "INSUFFICIENT_CREDITS",
              "RATE_LIMITED"
            ]
          },
          "message": { "type": "string" },
          "error": { "type": "string" }
        }
      }
    }
  },
  "security": [{ "apiKey": [] }],
  "paths": {
    "/api/v1/account": {
      "get": {
        "summary": "Validate setup and inspect account limits",
        "description": "Non-billable doctor endpoint for agents. Returns balance, API-key guardrails, and supported models.",
        "responses": {
          "200": { "description": "API setup is valid" },
          "401": { "description": "Missing, invalid, disabled, or deleted API key" },
          "429": { "description": "Shared query limit exceeded; honor Retry-After" }
        }
      }
    },
    "/api/v1/quote/{model}": {
      "post": {
        "summary": "Validate and quote a generation",
        "description": "Uses the same model-field validation and credit calculation as generation, but never creates a task or charges credits. Media accessibility and content safety checks run when a task is created.",
        "parameters": [
          { "name": "model", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "type": "object" } } }
        },
        "responses": {
          "200": {
            "description": "Authoritative non-billable quote",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/Quote" } }
            }
          },
          "400": { "description": "Invalid model or payload" },
          "401": { "description": "Missing, invalid, disabled, or deleted API key" }
        }
      }
    },
    "/api/v1/generate/minimax": {
      "post": {
        "summary": "Create a MiniMax H3 task",
        "description": "Quote first. MiniMax H3 list price is $0.03-$0.05 per generated second depending on resolution and tier. A stable idempotency key makes an identical retry safe; X-Max-Credits prevents a charge above the caller's approval.",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" },
          { "$ref": "#/components/parameters/MaxCredits" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": { "schema": { "$ref": "#/components/schemas/MiniMaxH3Request" } }
          }
        },
        "responses": {
          "200": {
            "description": "Task accepted or an identical idempotent request replayed",
            "content": {
              "application/json": { "schema": { "$ref": "#/components/schemas/SubmittedTask" } }
            }
          },
          "400": { "description": "Invalid model or payload" },
          "401": { "description": "Missing, invalid, disabled, or deleted API key" },
          "402": { "description": "Insufficient API credits" },
          "409": { "description": "Idempotency key reused with different request data" },
          "422": { "description": "Budget guard exceeded or content rejected" },
          "429": { "description": "API-key generation rate limit exceeded" }
        }
      }
    },
    "/api/v1/tasks": {
      "get": {
        "summary": "List tasks for the current API key",
        "responses": {
          "200": {
            "description": "Newest tasks first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tasks": { "type": "array", "items": { "$ref": "#/components/schemas/Task" } }
                  }
                }
              }
            }
          },
          "429": { "description": "Shared query limit exceeded; honor Retry-After" }
        }
      }
    },
    "/api/v1/tasks/{taskId}": {
      "get": {
        "summary": "Get task details and output",
        "parameters": [
          { "name": "taskId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Task details",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Task" } } }
          },
          "429": { "description": "Shared query limit exceeded; honor Retry-After" }
        }
      }
    },
    "/api/v1/tasks/{taskId}/status": {
      "get": {
        "summary": "Get task status",
        "parameters": [
          { "name": "taskId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Current status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "status": { "$ref": "#/components/schemas/TaskStatus" } }
                }
              }
            }
          },
          "429": { "description": "Shared query limit exceeded; honor Retry-After" }
        }
      }
    },
    "/api/v1/tasks/{taskId}/cancel": {
      "put": {
        "summary": "Cancel a submitted task",
        "parameters": [
          { "name": "taskId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Task cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": { "status": { "const": "CANCEL" }, "taskId": { "type": "string" } }
                }
              }
            }
          }
        }
      }
    }
  }
}
