{
  "openapi": "3.1.0",
  "info": {
    "title": "OpenTweet API",
    "version": "1.0.0",
    "description": "Post, schedule, and manage X (Twitter) content from your code or an AI agent. One API key, no X developer account, no OAuth. See https://opentweet.io/docs for guides.",
    "contact": { "name": "OpenTweet", "url": "https://opentweet.io/docs" }
  },
  "servers": [{ "url": "https://opentweet.io/api/v1", "description": "Production" }],
  "security": [{ "bearerAuth": [] }],
  "tags": [
    { "name": "Posts", "description": "Create, schedule, and manage tweets and threads" },
    { "name": "Articles", "description": "Long-form X Articles" },
    { "name": "Accounts", "description": "Account and connected X profiles" },
    { "name": "Media", "description": "Upload media for posts" },
    { "name": "Analytics", "description": "Posting analytics" }
  ],
  "paths": {
    "/posts": {
      "get": {
        "tags": ["Posts"],
        "summary": "List posts",
        "description": "List your tweets, optionally filtered by status.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["draft", "scheduled", "posted", "failed"] } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } },
          { "name": "x_account_id", "in": "query", "schema": { "type": "string" } }
        ],
        "responses": { "200": { "description": "A list of posts", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PostList" } } } } }
      },
      "post": {
        "tags": ["Posts"],
        "summary": "Create a tweet, thread, or scheduled post",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatePost" } } } },
        "responses": {
          "201": { "description": "Post created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } },
          "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Missing or invalid API key" }
        }
      }
    },
    "/posts/{id}": {
      "get": {
        "tags": ["Posts"],
        "summary": "Get a post",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "The post", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Post" } } } }, "404": { "description": "Not found" } }
      },
      "delete": {
        "tags": ["Posts"],
        "summary": "Delete a post",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Deleted" } }
      }
    },
    "/posts/{id}/publish": {
      "post": {
        "tags": ["Posts"],
        "summary": "Publish a draft or scheduled post immediately",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": { "200": { "description": "Published" } }
      }
    },
    "/posts/batch-schedule": {
      "post": {
        "tags": ["Posts"],
        "summary": "Schedule up to 50 posts in one call",
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": ["schedules"],
            "properties": { "schedules": { "type": "array", "maxItems": 50, "items": {
              "type": "object",
              "required": ["post_id", "scheduled_date"],
              "properties": { "post_id": { "type": "string" }, "scheduled_date": { "type": "string", "format": "date-time" } }
            } } }
          } } }
        },
        "responses": { "200": { "description": "Scheduled" } }
      }
    },
    "/articles": {
      "get": { "tags": ["Articles"], "summary": "List X Articles", "responses": { "200": { "description": "List of articles" } } },
      "post": {
        "tags": ["Articles"],
        "summary": "Create a long-form X Article",
        "requestBody": { "required": true, "content": { "application/json": { "schema": {
          "type": "object", "required": ["title", "body"],
          "properties": { "title": { "type": "string" }, "body": { "type": "string", "description": "Markdown" }, "scheduled_date": { "type": "string", "format": "date-time" } }
        } } } },
        "responses": { "201": { "description": "Article created" } }
      }
    },
    "/accounts": {
      "get": { "tags": ["Accounts"], "summary": "List connected X accounts", "responses": { "200": { "description": "Connected accounts" } } }
    },
    "/me": {
      "get": { "tags": ["Accounts"], "summary": "Get account status", "description": "Subscription plan, daily limits, post counts, connected accounts.", "responses": { "200": { "description": "Account status" }, "401": { "description": "Missing or invalid API key" } } }
    },
    "/upload": {
      "post": {
        "tags": ["Media"],
        "summary": "Upload media",
        "requestBody": { "required": true, "content": { "multipart/form-data": { "schema": { "type": "object", "properties": { "file": { "type": "string", "format": "binary" } } } } } },
        "responses": { "200": { "description": "Returns a media URL for use in media_urls" } }
      }
    },
    "/analytics/overview": {
      "get": { "tags": ["Analytics"], "summary": "Posting analytics overview", "responses": { "200": { "description": "Stats, streaks, trends" } } }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "ot_ API key", "description": "Your OpenTweet API key (prefix ot_). Create one at https://opentweet.io/developer." }
    },
    "schemas": {
      "CreatePost": {
        "type": "object",
        "required": ["text"],
        "properties": {
          "text": { "type": "string", "maxLength": 280, "description": "Tweet text. For threads, use thread_tweets instead." },
          "scheduled_date": { "type": "string", "format": "date-time", "description": "ISO 8601. Mutually exclusive with publish_now. Omit both to save a draft." },
          "publish_now": { "type": "boolean", "description": "Publish immediately. Mutually exclusive with scheduled_date." },
          "is_thread": { "type": "boolean" },
          "thread_tweets": { "type": "array", "items": { "type": "string" }, "description": "Tweets in the thread when is_thread is true." },
          "media_urls": { "type": "array", "items": { "type": "string" }, "description": "URLs returned by /upload." },
          "category": { "type": "string" },
          "x_account_id": { "type": "string", "description": "Target a specific connected X account (Advanced and Agency plans)." }
        }
      },
      "Post": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "text": { "type": "string" },
          "status": { "type": "string", "enum": ["draft", "scheduled", "posted", "failed"] },
          "scheduled_date": { "type": "string", "format": "date-time", "nullable": true },
          "is_thread": { "type": "boolean" },
          "x_post_id": { "type": "string", "nullable": true }
        }
      },
      "PostList": {
        "type": "object",
        "properties": { "posts": { "type": "array", "items": { "$ref": "#/components/schemas/Post" } }, "total": { "type": "integer" } }
      },
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" }, "code": { "type": "string" }, "details": { "type": "string" } }
      }
    }
  }
}
