{
  "openapi": "3.0.3",
  "info": {
    "title": "X Video Downloader API",
    "description": "REST API for downloading publicly available videos from X (Twitter). See https://xvideodownloader.org/developers/api for the human-readable reference.",
    "version": "1.0.0",
    "contact": {
      "url": "https://xvideodownloader.org/contact"
    }
  },
  "servers": [{ "url": "https://xvideodownloader.org" }],
  "security": [{}, { "bearerAuth": [] }],
  "paths": {
    "/api/download": {
      "post": {
        "summary": "Create a download task",
        "operationId": "createDownload",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url"],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "X/Twitter post URL (x.com or twitter.com)"
                  },
                  "filename": { "type": "string", "description": "Custom output filename. SVIP only." },
                  "format": { "type": "string", "description": "Custom ffmpeg format string. SVIP only." },
                  "playlistIndex": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Video index for multi-video tweets (0-based)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Download task created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "example": true },
                    "cached": { "type": "boolean" },
                    "download": { "type": "object", "properties": { "id": { "type": "integer" } } },
                    "video": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "integer" },
                        "status": { "type": "string", "enum": ["queued", "running", "done", "failed"] }
                      }
                    },
                    "remaining": { "type": "integer", "description": "Downloads left today, -1 if unlimited" }
                  }
                }
              }
            }
          },
          "400": { "description": "EMPTY_URL, INVALID_URL_FORMAT, or UNSUPPORTED_HOST" },
          "429": { "description": "RATE_LIMIT — daily download limit reached" }
        }
      }
    },
    "/api/downloads/{id}": {
      "get": {
        "summary": "Get a download task's status and metadata",
        "operationId": "getDownload",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": {
            "description": "Task details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "task": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "integer" },
                        "url": { "type": "string" },
                        "status": { "type": "string", "enum": ["queued", "running", "done", "failed"] },
                        "error_code": { "type": "string", "nullable": true },
                        "file_size": { "type": "integer", "nullable": true },
                        "duration": { "type": "number", "nullable": true },
                        "width": { "type": "integer", "nullable": true },
                        "height": { "type": "integer", "nullable": true }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": { "description": "Not found" }
        }
      },
      "delete": {
        "summary": "Delete a download record",
        "operationId": "deleteDownload",
        "description": "Cannot delete a task that is still running.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } }],
        "responses": {
          "200": { "description": "Deleted" },
          "409": { "description": "Task is still running" }
        }
      }
    },
    "/api/file/{id}": {
      "get": {
        "summary": "Get the downloaded file",
        "operationId": "getFile",
        "description": "302-redirects to the file's public R2 URL. Pass ?dl=1 to count it against your daily quota; omit it for a read-only preview that does not consume quota.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } },
          { "name": "dl", "in": "query", "required": false, "schema": { "type": "string", "enum": ["1"] } }
        ],
        "responses": {
          "302": { "description": "Redirect to the file" },
          "409": { "description": "Video not ready for download" },
          "429": { "description": "RATE_LIMIT — daily download limit reached (only with ?dl=1)" },
          "404": { "description": "Download not found, or no file URL available" }
        }
      }
    },
    "/api/downloads": {
      "get": {
        "summary": "List download history",
        "operationId": "listDownloads",
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": { "type": "integer", "default": 50, "maximum": 200 }
          }
        ],
        "responses": {
          "200": {
            "description": "Download history",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "integer" },
                          "url": { "type": "string" },
                          "status": { "type": "string" },
                          "created_at": { "type": "string", "format": "date-time" }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/user/usage": {
      "get": {
        "summary": "Get today's usage against your plan's daily limit",
        "operationId": "getUsage",
        "responses": {
          "200": {
            "description": "Usage info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "used": { "type": "integer" },
                    "limit": { "type": "integer", "description": "-1 means unlimited (SVIP)" },
                    "remaining": { "type": "integer" },
                    "plan": { "type": "string", "enum": ["free", "svip"] }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/user/subscription": {
      "get": {
        "summary": "Get current plan and legacy subscription status",
        "operationId": "getSubscription",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Plan info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "plan": { "type": "string", "enum": ["free", "svip"] },
                    "hasPurchasedCredits": { "type": "boolean" },
                    "subscription": {
                      "type": "object",
                      "nullable": true,
                      "description": "Non-null only for legacy recurring subscribers or lifetime SVIP purchasers.",
                      "properties": {
                        "status": { "type": "string" },
                        "cancelAtPeriodEnd": { "type": "boolean" },
                        "currentPeriodEnd": { "type": "integer", "nullable": true },
                        "isManaged": {
                          "type": "boolean",
                          "description": "True only for a real recurring Stripe subscription. False for a one-time lifetime SVIP purchase — there is nothing to manage."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Obtain a token via the CLI's `auth login` device-authorization flow, or by signing in on the website."
      }
    }
  }
}
