{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Unblur Video API",
    "version": "1.0.0",
    "description": "Programmatic AI video enhancement API. Register a public HTTPS video or upload a local file, create an asynchronous enhancement job, poll its status, and download the persisted result. API access requires an active plan with API access.",
    "termsOfService": "https://unblurvideo.ai/terms-of-service",
    "license": {
      "name": "Proprietary; use governed by the Terms of Service",
      "url": "https://unblurvideo.ai/terms-of-service"
    },
    "contact": {
      "name": "Unblur Video Support",
      "url": "https://unblurvideo.ai/docs/api",
      "email": "support@unblurvideo.ai"
    }
  },
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://unblurvideo.ai/docs/api"
  },
  "servers": [
    {
      "url": "https://unblurvideo.ai/api/v1",
      "description": "Production API"
    }
  ],
  "tags": [
    { "name": "Discovery", "description": "Public API discovery metadata." },
    { "name": "Uploads", "description": "Register remote videos or upload local files." },
    { "name": "Jobs", "description": "Create and inspect asynchronous enhancement jobs." },
    { "name": "Credits", "description": "Inspect credit balances and subscription state." }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getApiDiscovery",
        "summary": "Discover the API",
        "description": "Returns the API version, documentation URL, OpenAPI URL, and principal resource paths. Authentication is not required.",
        "tags": ["Discovery"],
        "security": [],
        "responses": {
          "200": {
            "description": "API discovery metadata.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/DiscoveryResponse" }
              }
            }
          }
        }
      }
    },
    "/uploads": {
      "post": {
        "operationId": "createUpload",
        "summary": "Register a video upload",
        "description": "Use source_url mode to fetch a public HTTPS video, or presigned mode to obtain a temporary URL for uploading raw local-file bytes. The JSON body is limited to 16 KiB. Supported formats are MP4, MOV, and WebM; maximum file size is 500 MiB.",
        "tags": ["Uploads"],
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  { "$ref": "#/components/schemas/SourceUrlUploadRequest" },
                  { "$ref": "#/components/schemas/PresignedUploadRequest" }
                ]
              },
              "examples": {
                "sourceUrl": {
                  "value": {
                    "mode": "source_url",
                    "source_url": "https://example.com/video.mp4"
                  }
                },
                "presigned": {
                  "value": {
                    "mode": "presigned",
                    "filename": "clip.mp4",
                    "content_type": "video/mp4",
                    "size_bytes": 10485760
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The remote video was imported or a presigned upload URL was created.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    { "$ref": "#/components/schemas/SourceUrlUploadResponse" },
                    { "$ref": "#/components/schemas/PresignedUploadResponse" }
                  ]
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "502": { "$ref": "#/components/responses/BadGateway" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" },
          "504": { "$ref": "#/components/responses/GatewayTimeout" }
        }
      }
    },
    "/uploads/{id}/confirm": {
      "post": {
        "operationId": "confirmUpload",
        "summary": "Confirm a presigned upload",
        "description": "Verifies the stored object, validates its size and content type, and extracts video metadata synchronously. The optional JSON body is limited to 4 KiB.",
        "tags": ["Uploads"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/UploadId" }],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ConfirmUploadRequest" },
              "example": { "size_bytes": 10485760 }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The upload was confirmed. Reconfirming an uploaded file returns its current public metadata.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ConfirmedUploadResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "413": { "$ref": "#/components/responses/PayloadTooLarge" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/jobs": {
      "post": {
        "operationId": "createJob",
        "summary": "Create an enhancement job",
        "description": "Creates an asynchronous enhancement job. Full jobs deduct credits at creation; preview jobs are free and render an approximately three-second watermarked preview. Identical active jobs are returned without a second charge. The JSON body is limited to 16 KiB.",
        "tags": ["Jobs"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateJobRequest" },
              "example": {
                "upload_id": "0c9dc431-d334-4b70-8e17-d8a64f896c2d",
                "target_resolution": "1080p",
                "preview": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "An existing active or idempotently mapped job was returned with duplicate=true.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/DuplicateJobResponse" }
              }
            }
          },
          "201": {
            "description": "A new enhancement job was created.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreatedJobResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "422": { "$ref": "#/components/responses/UnprocessableEntity" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      },
      "get": {
        "operationId": "listJobs",
        "summary": "List enhancement jobs",
        "description": "Returns non-deleted jobs in newest-first order. Persisted completed outputs include temporary four-hour download URLs.",
        "tags": ["Jobs"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" },
          { "$ref": "#/components/parameters/JobStatus" }
        ],
        "responses": {
          "200": {
            "description": "A newest-first array of jobs.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JobListResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalServerError" }
        }
      }
    },
    "/jobs/{id}": {
      "get": {
        "operationId": "getJob",
        "summary": "Get and synchronize a job",
        "description": "Returns a job owned by the authenticated account. Polling active jobs synchronizes provider status and persists completed output before exposing a temporary four-hour download URL. Poll every 5–10 seconds.",
        "tags": ["Jobs"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/JobId" }],
        "responses": {
          "200": {
            "description": "Current synchronized job state.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JobDetailResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalServerError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/credits": {
      "get": {
        "operationId": "getCredits",
        "summary": "Get credit balances",
        "description": "Returns total, subscription, and one-time credit balances with the current plan and subscription state.",
        "tags": ["Credits"],
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Current credit and subscription information.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreditsResponse" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/InternalServerError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Unblur Video API key (ubv_...)",
        "description": "Create a key in the dashboard and send Authorization: Bearer ubv_.... The complete key is shown only once and must remain server-side."
      }
    },
    "parameters": {
      "UploadId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Upload UUID returned by POST /uploads.",
        "schema": { "type": "string", "format": "uuid" }
      },
      "JobId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Enhancement job UUID.",
        "schema": { "type": "string", "format": "uuid" }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Caller-generated key scoped to the account. The same key and normalized request return the original job; different parameters return 409. Strongly recommended for production.",
        "schema": { "type": "string", "minLength": 1, "maxLength": 128 },
        "example": "7f7f2f78-3cb4-4e2d-92e2-5d7dc7cf70f9"
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 }
      },
      "Offset": {
        "name": "offset",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 0, "default": 0 }
      },
      "JobStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "schema": { "$ref": "#/components/schemas/JobStatus" }
      }
    },
    "headers": {
      "WwwAuthenticate": {
        "description": "Bearer authentication challenge.",
        "schema": {
          "type": "string",
          "example": "Bearer realm=\"Unblur Video API\", charset=\"UTF-8\""
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": { "type": "integer", "minimum": 0 }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid JSON, fields, identifier, query, file declaration, source URL, or idempotency key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Unauthorized": {
        "description": "The API key is missing, invalid, revoked, disabled, or expired.",
        "headers": { "WWW-Authenticate": { "$ref": "#/components/headers/WwwAuthenticate" } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "PaymentRequired": {
        "description": "The account has insufficient credits.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Forbidden": {
        "description": "The account is banned or its subscription does not include API access.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "NotFound": {
        "description": "The upload, job, or usage record does not exist or is not owned by the account.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "Conflict": {
        "description": "Resource state, pending metadata, concurrent creation, or idempotency conflict. METADATA_PENDING includes Retry-After: 5.",
        "headers": { "Retry-After": { "$ref": "#/components/headers/RetryAfter" } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "PayloadTooLarge": {
        "description": "The JSON body exceeds its route limit or the video exceeds 500 MiB.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "UnprocessableEntity": {
        "description": "The source URL is unsafe or unresolvable, or the video metadata or resolution is unsuitable.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "TooManyRequests": {
        "description": "The account-level rate limit was exceeded.",
        "headers": { "Retry-After": { "$ref": "#/components/headers/RetryAfter" } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "InternalServerError": {
        "description": "Internal, configuration, storage, or processing-provider error.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "BadGateway": {
        "description": "A public source URL could not be downloaded or persisted.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "ServiceUnavailable": {
        "description": "Rate limiting or processing is temporarily unavailable, or provider submission requires reconciliation. Do not blindly resubmit JOB_RECONCILIATION_REQUIRED.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      },
      "GatewayTimeout": {
        "description": "The server timed out downloading a public source URL.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
      }
    },
    "schemas": {
      "DiscoveryResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/DiscoveryData" }
        }
      },
      "DiscoveryData": {
        "type": "object",
        "required": ["name", "version", "documentationUrl", "openapiUrl", "endpoints"],
        "properties": {
          "name": { "type": "string", "example": "Unblur Video API" },
          "version": { "type": "string", "example": "v1" },
          "documentationUrl": { "type": "string", "format": "uri" },
          "openapiUrl": { "type": "string", "format": "uri" },
          "endpoints": {
            "type": "object",
            "required": ["uploads", "jobs", "credits"],
            "properties": {
              "uploads": { "type": "string", "example": "/api/v1/uploads" },
              "jobs": { "type": "string", "example": "/api/v1/jobs" },
              "credits": { "type": "string", "example": "/api/v1/credits" }
            }
          }
        }
      },
      "SourceUrlUploadRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["mode", "source_url"],
        "properties": {
          "mode": { "type": "string", "const": "source_url" },
          "source_url": {
            "type": "string",
            "format": "uri",
            "minLength": 1,
            "maxLength": 4096,
            "description": "Public HTTPS URL on port 443. Credentials, private addresses, and unsafe redirects are rejected."
          }
        }
      },
      "PresignedUploadRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["filename", "content_type", "size_bytes"],
        "properties": {
          "mode": {
            "type": "string",
            "const": "presigned",
            "description": "Optional; omitting mode also selects presigned upload."
          },
          "filename": {
            "type": "string",
            "minLength": 1,
            "maxLength": 255,
            "description": "Must end in .mp4, .mov, or .webm and match content_type."
          },
          "content_type": { "$ref": "#/components/schemas/VideoContentType" },
          "size_bytes": { "type": "integer", "minimum": 1, "maximum": 524288000 }
        }
      },
      "ConfirmUploadRequest": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "size_bytes": {
            "type": "integer",
            "minimum": 1,
            "maximum": 524288000,
            "description": "When supplied, must match the stored object."
          }
        }
      },
      "VideoContentType": {
        "type": "string",
        "enum": ["video/mp4", "video/quicktime", "video/webm"]
      },
      "VideoMetadata": {
        "type": "object",
        "properties": {
          "resolution": { "type": "string", "example": "720p" },
          "width": { "type": "integer", "minimum": 1, "example": 1280 },
          "height": { "type": "integer", "minimum": 1, "example": 720 },
          "duration": { "type": "number", "exclusiveMinimum": 0, "description": "Seconds.", "example": 12.4 },
          "fps": { "type": "number", "exclusiveMinimum": 0, "example": 30 }
        }
      },
      "UploadMetadataStatus": {
        "type": "string",
        "enum": ["ready", "pending", "failed"]
      },
      "SourceUrlUploadResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/SourceUrlUploadData" }
        }
      },
      "SourceUrlUploadData": {
        "type": "object",
        "required": ["uploadId", "status", "sizeBytes", "contentType", "metadata", "metadataStatus"],
        "properties": {
          "uploadId": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "const": "uploaded" },
          "sizeBytes": { "type": "integer", "minimum": 1, "maximum": 524288000 },
          "contentType": { "$ref": "#/components/schemas/VideoContentType" },
          "metadata": { "$ref": "#/components/schemas/NullableVideoMetadata" },
          "metadataStatus": { "$ref": "#/components/schemas/UploadMetadataStatus" }
        }
      },
      "PresignedUploadResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/PresignedUploadData" }
        }
      },
      "PresignedUploadData": {
        "type": "object",
        "required": ["uploadId", "uploadUrl", "expiresInSeconds"],
        "properties": {
          "uploadId": { "type": "string", "format": "uuid" },
          "uploadUrl": {
            "type": "string",
            "format": "uri",
            "description": "PUT raw file bytes here with the declared Content-Type."
          },
          "expiresInSeconds": { "type": "integer", "const": 600 }
        }
      },
      "ConfirmedUploadResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/ConfirmedUploadData" }
        }
      },
      "ConfirmedUploadData": {
        "type": "object",
        "required": ["uploadId", "status", "sizeBytes", "metadata", "metadataStatus"],
        "properties": {
          "uploadId": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "const": "uploaded" },
          "sizeBytes": { "type": ["integer", "null"], "minimum": 1, "maximum": 524288000 },
          "metadata": { "$ref": "#/components/schemas/NullableVideoMetadata" },
          "metadataStatus": { "$ref": "#/components/schemas/UploadMetadataStatus" }
        }
      },
      "NullableVideoMetadata": {
        "oneOf": [
          { "$ref": "#/components/schemas/VideoMetadata" },
          { "type": "null" }
        ]
      },
      "CreateJobRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["upload_id", "target_resolution"],
        "properties": {
          "upload_id": { "type": "string", "format": "uuid" },
          "target_resolution": { "$ref": "#/components/schemas/TargetResolution" },
          "preview": { "type": "boolean", "default": false }
        }
      },
      "TargetResolution": {
        "type": "string",
        "enum": ["1080p", "2k", "4k"]
      },
      "NullableTargetResolution": {
        "oneOf": [
          { "$ref": "#/components/schemas/TargetResolution" },
          { "type": "null" }
        ]
      },
      "JobStatus": {
        "type": "string",
        "enum": ["pending", "in_queue", "processing", "completed", "failed", "cancelled"]
      },
      "JobMode": {
        "type": "string",
        "enum": ["preview", "full"]
      },
      "CreatedJobResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/CreatedJobData" }
        }
      },
      "DuplicateJobResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/DuplicateJobData" }
        }
      },
      "CreatedJobData": {
        "type": "object",
        "required": ["id", "status", "targetResolution", "preview", "jobMode", "creditCost", "createdAt"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "targetResolution": { "$ref": "#/components/schemas/NullableTargetResolution" },
          "preview": { "type": "boolean" },
          "jobMode": { "$ref": "#/components/schemas/JobMode" },
          "creditCost": { "type": ["integer", "null"] },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "DuplicateJobData": {
        "type": "object",
        "required": ["id", "status", "targetResolution", "preview", "jobMode", "creditCost", "createdAt", "duplicate"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "targetResolution": { "$ref": "#/components/schemas/NullableTargetResolution" },
          "preview": { "type": "boolean" },
          "jobMode": { "$ref": "#/components/schemas/JobMode" },
          "creditCost": { "type": ["integer", "null"] },
          "createdAt": { "type": "string", "format": "date-time" },
          "duplicate": { "type": "boolean", "const": true }
        }
      },
      "JobListResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/JobListItem" }
          }
        }
      },
      "JobListItem": {
        "type": "object",
        "required": ["id", "uploadId", "taskType", "targetResolution", "preview", "jobMode", "status", "creditCost", "errorMessage", "needsReconciliation", "outputUrl", "startedAt", "completedAt", "createdAt"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "uploadId": { "type": ["string", "null"], "format": "uuid" },
          "taskType": { "type": "string", "const": "video_upscale" },
          "targetResolution": { "$ref": "#/components/schemas/NullableTargetResolution" },
          "preview": { "type": "boolean" },
          "jobMode": { "$ref": "#/components/schemas/JobMode" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "creditCost": { "type": ["integer", "null"] },
          "errorMessage": { "type": ["string", "null"] },
          "needsReconciliation": { "type": "boolean" },
          "outputUrl": {
            "type": ["string", "null"],
            "format": "uri",
            "description": "Four-hour URL for a persisted completed output; otherwise null."
          },
          "startedAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "completedAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "JobDetailResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/JobDetail" }
        }
      },
      "JobDetail": {
        "type": "object",
        "required": ["id", "uploadId", "taskType", "targetResolution", "preview", "jobMode", "status", "creditCost", "errorMessage", "needsReconciliation", "outputUrl", "processing", "startedAt", "submittedAt", "completedAt", "lastPolledAt", "failedAt", "createdAt"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "uploadId": { "type": ["string", "null"], "format": "uuid" },
          "taskType": { "type": "string", "const": "video_upscale" },
          "targetResolution": { "$ref": "#/components/schemas/NullableTargetResolution" },
          "preview": { "type": "boolean" },
          "jobMode": { "$ref": "#/components/schemas/JobMode" },
          "status": { "$ref": "#/components/schemas/JobStatus" },
          "creditCost": { "type": ["integer", "null"] },
          "errorMessage": { "type": ["string", "null"] },
          "needsReconciliation": {
            "type": "boolean",
            "description": "If true, do not blindly resubmit; provider outcome requires safe reconciliation."
          },
          "outputUrl": {
            "type": ["string", "null"],
            "format": "uri",
            "description": "Four-hour URL for a persisted completed output; otherwise null."
          },
          "processing": {
            "type": "object",
            "required": ["delayTime", "executionTime"],
            "properties": {
              "delayTime": { "type": ["number", "null"] },
              "executionTime": { "type": ["number", "null"] }
            }
          },
          "startedAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "submittedAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "completedAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "lastPolledAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "failedAt": { "$ref": "#/components/schemas/NullableDateTime" },
          "createdAt": { "type": "string", "format": "date-time" }
        }
      },
      "NullableDateTime": {
        "type": ["string", "null"],
        "format": "date-time"
      },
      "CreditsResponse": {
        "type": "object",
        "required": ["success", "data"],
        "properties": {
          "success": { "type": "boolean", "const": true },
          "data": { "$ref": "#/components/schemas/CreditsData" }
        }
      },
      "CreditsData": {
        "type": "object",
        "required": ["totalCredits", "subscriptionCredits", "oneTimeCredits", "planName", "subscriptionStatus", "currentPeriodEnd"],
        "properties": {
          "totalCredits": { "type": "integer" },
          "subscriptionCredits": { "type": "integer" },
          "oneTimeCredits": { "type": "integer" },
          "planName": { "type": ["string", "null"] },
          "subscriptionStatus": {
            "type": ["string", "null"],
            "description": "Provider subscription status or inactive_period_ended."
          },
          "currentPeriodEnd": { "$ref": "#/components/schemas/NullableDateTime" }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "required": ["success", "error", "code"],
        "properties": {
          "success": { "type": "boolean", "const": false },
          "error": { "type": "string" },
          "code": {
            "type": "string",
            "description": "Stable machine-readable code such as INVALID_INPUT, MISSING_API_KEY, INSUFFICIENT_CREDITS, METADATA_PENDING, RATE_LIMIT_EXCEEDED, or SERVICE_UNAVAILABLE."
          }
        }
      }
    }
  }
}
