{
  "openapi": "3.1.0",
  "info": {
    "title": "TwitterAPIs API",
    "version": "1.0.0",
    "description": "REST API for Twitter and X data. Search tweets and users, resolve a single tweet into its full thread, read profiles and timelines, page the follower graph, and run write actions over plain HTTP with Bearer auth and JSON. Pay per call: almost every call is $0.0008 (standard reads plus simple write actions like, retweet, bookmark, follow, their undos, and delete), tweet/thread is $0.004, full tweet history is $0.0024, tweet creation and DM reads are $0.0016, and account reads are free. New accounts start with $0.50 in free credits."
  },
  "servers": [
    {
      "url": "https://api.twitterapis.com/twitter"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Your API account: credit balance, usage totals, payment history, and product feedback filed from the tool you are using. Served from the API root (https://api.twitterapis.com/account/* and /feedback), not under /twitter, because billing owns their authentication. Free."
    },
    {
      "name": "Account Session",
      "description": "Bring your own X session cookies (recommended), or mint a session from a username and password, so write actions and private-data reads act as your account. Free."
    },
    {
      "name": "Search",
      "description": "Full-text and structured search across tweets and users. Filter by query operators, author, date, language, and engagement."
    },
    {
      "name": "Tweet Details",
      "description": "Resolve a single tweet into its full object: replies, retweeters, and the complete conversation thread."
    },
    {
      "name": "User Reads",
      "description": "Read a profile, its timeline, media, mentions, affiliates, and follow relationships by username or numeric ID."
    },
    {
      "name": "Direct Messages",
      "description": "Read your account's DM inbox and the message history of a single conversation, and send new messages, all acting as the account behind your registered session."
    },
    {
      "name": "Follower Graph",
      "description": "Page through followers and following lists, including the verified-only and v2 cursor-paginated variants."
    },
    {
      "name": "List Data",
      "description": "Read the members of any public Twitter/X List."
    },
    {
      "name": "Trends",
      "description": "Read what is trending on Twitter/X right now, worldwide, for a single country, for one X Explore tab or for the trends X labels Business and finance, plus the full set of locations trends are available for."
    },
    {
      "name": "Spaces",
      "description": "Read an X Space by id: title, host, speakers, topics, timing and audience counts, for a Space that is scheduled, running or already ended."
    },
    {
      "name": "Communities",
      "description": "Read an X Community: its metadata and rules, its member and moderator rosters, its own post timeline including the pinned post, and the inverse relation, every community a given account belongs to. These are public reads that do not run as your account, so the four fields that describe the CALLER's own relationship to a community (role, can_join, is_pinned, viewer_relationship_type) always come back null."
    },
    {
      "name": "Write Actions",
      "description": "Act on behalf of an authenticated account: post, delete, like, retweet, bookmark and follow, each with its undo, plus the compose surface (private drafts and scheduled posts). MOST of these bill at $0.0008 per call, the same as a standard read, but not all: tweet/create, draft/create, draft/edit, draft/list, scheduled/create and scheduled/list are $0.0016. Read the price on the endpoint, never off this line."
    },
    {
      "name": "Articles",
      "description": "Create, edit, publish, and read X's long-form Articles (X's internal name: Notes). Publishing posts a real announcement tweet; reading a published article is a public call that needs no session."
    },
    {
      "name": "Grok",
      "description": "Ask X's own in-app Grok a question and get the answer back with the pages it cited. Grok reads X in real time, so it answers about posts and accounts a general model has never seen. Runs as your account, returns one buffered JSON document rather than a stream, and stores nothing: you pass prior turns back yourself."
    },
    {
      "name": "Monitoring",
      "description": "Watch an X account for new posts and get them pushed to your own webhook, HMAC-signed, retried for 21 minutes on failure. Polls on a shared interval and never spends your read credits: monitor and webhook management are free account administration, not metered reads."
    }
  ],
  "paths": {
    "/account/me": {
      "get": {
        "operationId": "account-me",
        "summary": "Account Info",
        "description": "Returns the account behind your API key: remaining credits, credits consumed, total requests served, and when the account was created. Use it to show a balance in your own dashboard or to alert before you run out of credits. This call is free and is not metered. Cost: Free per call.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/account/me\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/account/me\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/account/me\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Your credit balance, lifetime usage, and account details for the API key making the call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "email": {
                      "type": "string",
                      "description": "Email address on the account."
                    },
                    "name": {
                      "type": "string",
                      "description": "Account holder name."
                    },
                    "credits_remaining": {
                      "type": "number",
                      "description": "Credits currently available, in USD."
                    },
                    "credits_used": {
                      "type": "number",
                      "description": "Total credits consumed to date, in USD."
                    },
                    "total_requests": {
                      "type": "number",
                      "description": "Total number of API requests served for this account."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp of when the account was created."
                    }
                  }
                },
                "example": {
                  "email": "you@example.com",
                  "name": "Your Name",
                  "credits_remaining": 946.4048,
                  "credits_used": 454.1516,
                  "total_requests": 622007,
                  "created_at": "2026-01-14T09:22:31.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ]
    },
    "/account/payments": {
      "get": {
        "operationId": "account-payments",
        "summary": "Payment History",
        "description": "Returns the payment history for the account behind your API key, ordered newest first. Each entry records what was paid, how many credits it added, and whether the payment completed. Use it to reconcile top-ups against your own billing records. This call is free. Cost: Free per call.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/account/payments\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/account/payments\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/account/payments\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Every credit top-up on your account, newest first, with amount, credits added, and status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payments": {
                      "type": "array",
                      "description": "Payment records, newest first. Empty when the account has never topped up.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                },
                "example": {
                  "payments": [
                    {
                      "amount": 100,
                      "credits_added": 100,
                      "status": "completed",
                      "created_at": "2026-06-02T14:08:55.000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ]
    },
    "/feedback": {
      "post": {
        "operationId": "feedback-post",
        "summary": "Send Feedback",
        "description": "Files a product feedback report against your account. It exists for AI agents (Claude Code, Cursor, any MCP client) working against this API: when a call fails, a capability is missing, or the user asks for it, the agent drafts a report locally, the user reviews it, and the client sends it here. The report reaches the team as a stored row plus a Slack post, and the returned id lets the agent read its status later. Free, never metered, rate limited to 10 per minute per key. Cost: Free per call.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/feedback\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"type\": \"bug\", \"title\": \"tweet/thread returns 500 on a quoted reply\", \"details\": \"what happened: tweet/thread?id=1899999999999999999 answered 500 server_error, expected the 4-post thread.\\nrepro: GET tweet/thread with that id.\\nevidence: status 500, request id req_01J9K2, twitter_tweet_thread via claude-code/2.1.259.\", \"area\": \"tweet/thread\", \"evidence\": {\"tool\": \"twitter_tweet_thread\", \"endpoint\": \"tweet/thread\", \"status\": 500, \"request_id\": \"req_01J9K2\", \"client\": \"claude-code/2.1.259\", \"mcp_version\": \"0.9.6\"}, \"client\": \"claude-code/2.1.259 via @twitterapis/mcp@0.9.6\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/feedback\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\n        \"type\": \"bug\",\n        \"title\": \"tweet/thread returns 500 on a quoted reply\",\n        \"details\": \"what happened: tweet/thread?id=1899999999999999999 answered 500 server_error, expected the 4-post thread.\\nrepro: GET tweet/thread with that id.\\nevidence: status 500, request id req_01J9K2, twitter_tweet_thread via claude-code/2.1.259.\",\n        \"area\": \"tweet/thread\",\n        \"evidence\": {\"tool\": \"twitter_tweet_thread\", \"endpoint\": \"tweet/thread\", \"status\": 500, \"request_id\": \"req_01J9K2\", \"client\": \"claude-code/2.1.259\", \"mcp_version\": \"0.9.6\"},\n        \"client\": \"claude-code/2.1.259 via @twitterapis/mcp@0.9.6\",\n    },\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/feedback\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({\n    type: \"bug\",\n    title: \"tweet/thread returns 500 on a quoted reply\",\n    details: \"what happened: tweet/thread?id=1899999999999999999 answered 500 server_error, expected the 4-post thread.\\nrepro: GET tweet/thread with that id.\\nevidence: status 500, request id req_01J9K2, twitter_tweet_thread via claude-code/2.1.259.\",\n    area: \"tweet/thread\",\n    evidence: { tool: \"twitter_tweet_thread\", endpoint: \"tweet/thread\", status: 500, request_id: \"req_01J9K2\", client: \"claude-code/2.1.259\", mcp_version: \"0.9.6\" },\n    client: \"claude-code/2.1.259 via @twitterapis/mcp@0.9.6\",\n  }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "201": {
            "description": "File a bug, idea or missing-capability report from the tool you are using, typically drafted by your AI agent and sent after you review it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The report's id (a UUID). Pass it to GET feedback/{id} to read its status and the team's response."
                    },
                    "status": {
                      "type": "string",
                      "description": "Always \"new\" on creation. Moves to triaged, shipped or declined as the team works the report."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp of when the report was stored."
                    }
                  }
                },
                "example": {
                  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
                  "status": "new",
                  "created_at": "2026-09-04T10:15:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "field",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "field": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "invalid_request",
                  "field": "title",
                  "message": "title must be 120 characters or fewer (got 131)."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Invalid API key"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Too many requests. Limit: 10 per minute."
                }
              }
            }
          },
          "502": {
            "description": "HTTP 502",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "upstream_unavailable",
                  "message": "The feedback service is temporarily unavailable. Retry shortly."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Internal server error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "description": "One of bug, idea or missing_capability. Anything else is rejected with 400 naming type.",
                    "example": "bug"
                  },
                  "title": {
                    "type": "string",
                    "description": "One line, 1 to 120 characters after trimming. Say what broke or what is missing, not how the user feels about it.",
                    "example": "tweet/thread returns 500 on a quoted reply"
                  },
                  "details": {
                    "type": "string",
                    "description": "1 to 8000 characters. Recommended shape, three labelled bullets: what happened (observed vs expected, the exact error text if short), repro (minimal steps), evidence (endpoint, status, request id, tool name, client, version), optionally after a one-line summary of the goal. No quotes of the conversation.",
                    "example": "what happened: tweet/thread?id=1899999999999999999 answered 500 server_error, expected the 4-post thread. repro: GET tweet/thread with that id. evidence: status 500, request id req_01J9K2, twitter_tweet_thread via claude-code/2.1.259."
                  },
                  "area": {
                    "type": "string",
                    "description": "The endpoint or feature the report concerns, for example tweet/thread or monitor webhooks. Up to 80 characters.",
                    "example": "tweet/thread"
                  },
                  "evidence": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Identifiers only, never payloads: tool, endpoint, status, request_id, client, mcp_version. Must serialize to 4096 bytes or fewer, and must be a JSON object (an array is rejected); either failure is a 400 naming evidence.",
                    "example": {
                      "tool": "twitter_tweet_thread",
                      "endpoint": "tweet/thread",
                      "status": 500,
                      "request_id": "req_01J9K2",
                      "client": "claude-code/2.1.259",
                      "mcp_version": "0.9.6"
                    }
                  },
                  "client": {
                    "type": "string",
                    "description": "The calling agent or tool and its version, so a fix can be matched to what sent the report. Up to 120 characters.",
                    "example": "claude-code/2.1.259 via @twitterapis/mcp@0.9.6"
                  }
                },
                "required": [
                  "type",
                  "title",
                  "details"
                ]
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ],
      "get": {
        "operationId": "feedback-get",
        "summary": "List Feedback",
        "description": "Returns the calling account's own feedback reports, newest first, keyset-paginated on (created_at desc, id desc). Each item carries the same summary fields as GET feedback/{id} (id, type, title, area, status, response, created_at, updated_at) and never details or evidence, so paging this endpoint can never turn into a bulk export of a report's full body: read one by id to get that. Free, never metered, and shares the 10-per-minute limiter with POST feedback and GET feedback/{id}. Cost: Free per call.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/feedback?limit=10&status=triaged\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/feedback\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"limit\": 10, \"status\": \"triaged\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/feedback\");\nurl.search = new URLSearchParams({ limit: 10, status: \"triaged\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through every feedback report your account has filed, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "feedback": {
                      "type": "array",
                      "description": "Array of reports, newest first: id, type, title, area, status, response, created_at, updated_at. Identical shape to a single GET feedback/{id} result; never details or evidence.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of reports in this page, never the account's total report count."
                    },
                    "limit": {
                      "type": "integer",
                      "description": "The limit actually applied to this call: the requested value, or 25 if omitted."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Pass back as cursor to fetch the next page. Null exactly on the last page.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "feedback": [
                    {
                      "id": "9a2b6e31-9b7b-4a44-8d19-2b6ec1c9a411",
                      "type": "bug",
                      "title": "tweet/thread returns 500 on a quoted reply",
                      "area": "tweet/thread",
                      "status": "triaged",
                      "response": "Reproduced. The quoted post was deleted mid-thread; a fix is in review.",
                      "created_at": "2026-09-04T10:15:00.000Z",
                      "updated_at": "2026-09-04T14:02:11.000Z"
                    },
                    {
                      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
                      "type": "idea",
                      "title": "add a webhook event for monitor degraded state",
                      "area": "monitor webhooks",
                      "status": "new",
                      "response": null,
                      "created_at": "2026-09-01T08:44:12.000Z",
                      "updated_at": "2026-09-01T08:44:12.000Z"
                    }
                  ],
                  "count": 2,
                  "limit": 25,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "field",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "field": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "invalid_request",
                  "field": "limit",
                  "message": "limit must be an integer from 1 to 100 (got \"0\")."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Invalid API key"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Too many requests. Limit: 10 per minute."
                }
              }
            }
          },
          "502": {
            "description": "HTTP 502",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "upstream_unavailable",
                  "message": "The feedback service is temporarily unavailable. Retry shortly."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Internal server error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max reports to return, 1 to 100. Defaults to 25. Anything else is rejected with 400 naming limit.",
            "schema": {
              "type": "integer",
              "description": "Max reports to return, 1 to 100. Defaults to 25. Anything else is rejected with 400 naming limit.",
              "example": "25"
            },
            "example": "25"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque continuation token from a previous response's next_cursor. Omit it to start from the newest report. A cursor that cannot be decoded is 400 naming cursor, never a silently empty page.",
            "schema": {
              "type": "string",
              "description": "Opaque continuation token from a previous response's next_cursor. Omit it to start from the newest report. A cursor that cannot be decoded is 400 naming cursor, never a silently empty page.",
              "example": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wOS0wMVQwODo0NDoxMi4wMDBaIiwiaWQiOiI3YzllNjY3OSJ9"
            },
            "example": "eyJjcmVhdGVkX2F0IjoiMjAyNi0wOS0wMVQwODo0NDoxMi4wMDBaIiwiaWQiOiI3YzllNjY3OSJ9"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter to one of new, triaged, shipped or declined. Anything else is rejected with 400 naming status.",
            "schema": {
              "type": "string",
              "description": "Filter to one of new, triaged, shipped or declined. Anything else is rejected with 400 naming status.",
              "example": "new"
            },
            "example": "new"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter to one of bug, idea or missing_capability. Anything else is rejected with 400 naming type.",
            "schema": {
              "type": "string",
              "description": "Filter to one of bug, idea or missing_capability. Anything else is rejected with 400 naming type.",
              "example": "bug"
            },
            "example": "bug"
          }
        ]
      }
    },
    "/feedback/{id}": {
      "get": {
        "operationId": "feedback-id",
        "summary": "Feedback Status",
        "description": "Returns one feedback report filed from your account, by id: what was sent (type, title, area), its status (new, triaged, shipped or declined), the team's response text or null, and timestamps. updated_at moves only when status or response changes, so an agent can tell a report that has been looked at from one that has not. Free, never metered. Any id that is not on your account answers 404, including ids that are not UUIDs. Cost: Free per call.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/feedback/{id}\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/feedback/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/feedback/{id}\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read one feedback report you filed: its current status and the team's response, if any.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The report's id (a UUID), as returned by POST feedback."
                    },
                    "type": {
                      "type": "string",
                      "description": "bug, idea or missing_capability, as filed."
                    },
                    "title": {
                      "type": "string",
                      "description": "The title as filed."
                    },
                    "area": {
                      "type": "string",
                      "description": "The endpoint or feature named at filing, or null if none was given.",
                      "nullable": true
                    },
                    "status": {
                      "type": "string",
                      "description": "One of new (received, not yet reviewed), triaged (accepted into the queue), shipped (the fix or feature is live) or declined (will not be done; response says why)."
                    },
                    "response": {
                      "type": "string",
                      "description": "The team's reply text, or null until one is written.",
                      "nullable": true
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp of when the report was stored."
                    },
                    "updated_at": {
                      "type": "string",
                      "description": "ISO 8601. Equals created_at until the status or the response changes, and moves only then."
                    }
                  }
                },
                "example": {
                  "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
                  "type": "bug",
                  "title": "tweet/thread returns 500 on a quoted reply",
                  "area": "tweet/thread",
                  "status": "triaged",
                  "response": "Reproduced. The quoted post was deleted mid-thread; a fix is in review.",
                  "created_at": "2026-09-04T10:15:00.000Z",
                  "updated_at": "2026-09-04T14:02:11.000Z"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Invalid API key"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "not_found",
                  "message": "No feedback with that id on this account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Too many requests. Limit: 10 per minute."
                }
              }
            }
          },
          "502": {
            "description": "HTTP 502",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "upstream_unavailable",
                  "message": "The feedback service is temporarily unavailable. Retry shortly."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "Internal server error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ]
    },
    "/customer/session": {
      "post": {
        "operationId": "customer-session",
        "summary": "Register Session",
        "description": "Register your X session cookies so write actions (like, retweet, bookmark, follow, create or delete a tweet) and private-data reads (home timeline, bookmarks, likes, DMs, followers-you-know) run as your account. Supply auth_token and ct0 once; the session is stored against your API key and applied automatically. This call is free. Cost: Free per call.",
        "tags": [
          "Account Session"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/customer/session\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"auth_token\": \"abc123...\", \"ct0\": \"def456...\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/customer/session\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"auth_token\": \"abc123...\", \"ct0\": \"def456...\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/customer/session\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ auth_token: \"abc123...\", ct0: \"def456...\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Register your auth_token and ct0 cookies once so every write and private read acts as your account, or pass them per call as x-auth-token / x-ct0 headers.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the session is stored."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable confirmation."
                    },
                    "username": {
                      "type": "string",
                      "description": "The X handle resolved from the session, or null when it could not be resolved.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "message": "Session registered. Private-data endpoints will read as your account.",
                  "username": "myhandle"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "auth_token": {
                    "type": "string",
                    "description": "The auth_token cookie value from a logged-in x.com browser session."
                  },
                  "ct0": {
                    "type": "string",
                    "description": "The ct0 CSRF cookie value from the same x.com browser session."
                  },
                  "user_agent": {
                    "type": "string",
                    "description": "Browser user-agent to send with session requests. Defaults to a current Chrome UA if omitted."
                  },
                  "proxy_url": {
                    "type": "string",
                    "description": "HTTP or SOCKS proxy URL the session egresses through, for example http://user:pass@host:port. This is a property of the session, so every call made with this API key on this session uses it, reads as well as writes. Defaults to direct, which means we choose the egress."
                  }
                },
                "required": [
                  "auth_token",
                  "ct0"
                ]
              }
            }
          }
        }
      }
    },
    "/customer/session/delete": {
      "post": {
        "operationId": "customer-session-delete",
        "summary": "Revoke Session",
        "description": "Delete the X session cookies stored against your API key. The key is taken from the authenticated request, and the handler reads no identity from the body, the query string, or any second header, so a call can only ever remove the caller's own stored session. It is idempotent and answers 200 whether or not a row was there to remove. This call is free. Cost: Free per call.",
        "tags": [
          "Account Session"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/customer/session/delete\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/customer/session/delete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/customer/session/delete\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({}),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Delete the auth_token and ct0 you registered, so we no longer hold your X session cookies. Self-serve, idempotent, and free.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Always true. The request was accepted and no stored session for your API key remains."
                    },
                    "deleted": {
                      "type": "boolean",
                      "description": "True when a stored session was found and removed. False when nothing was stored for this API key, for example after an earlier revoke, or when you only ever sent per-call x-auth-token and x-ct0 credentials."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable confirmation. The wording differs depending on whether a stored session was removed."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": true,
                  "message": "Your stored Twitter session was deleted. The auth_token and ct0 you registered are no longer on our servers. This does not log the account out of x.com: to invalidate the cookies themselves, revoke the session from your X account settings as well."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      }
    },
    "/customer/session/status": {
      "get": {
        "operationId": "customer-session-status",
        "summary": "Session Status",
        "description": "Read the X session stored against your API key without changing it. Returns the account the session actually resolved to, whether it is still live or has been marked dead, when it was registered and last used, and which egress tier a write would leave on. It never returns auth_token, ct0, or any proxy URL. The key is taken from the authenticated request and the handler reads no identity from the body, the query string, or any second header, so a call can only ever read the caller's own session. This call is free. Cost: Free per call.",
        "tags": [
          "Account Session"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/customer/session/status\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/customer/session/status\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/customer/session/status\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read back the session you registered: which X account it resolved to, whether it is still alive, and whether the proxy you supplied is the one your writes leave from. Free.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "registered": {
                      "type": "boolean",
                      "description": "True when a session is stored for your API key. False when you never registered one, or revoked it. Per-call credentials sent as x-auth-token and x-ct0 are never stored, so a caller who only uses that path always sees false."
                    },
                    "username": {
                      "type": "string",
                      "description": "The X handle the stored session resolved to when it was registered. Read back from storage, not from anything you send, so it is the field that settles whether you are acting as the account you expect. Null when resolution never succeeded.",
                      "nullable": true
                    },
                    "twitter_user_id": {
                      "type": "string",
                      "description": "The numeric X user id for the same account. Null when resolution never succeeded.",
                      "nullable": true
                    },
                    "status": {
                      "type": "string",
                      "description": "Either ok or dead. dead is stamped when X rejects the cookies as expired or deauthorized, so it is an observation rather than a guess. A dead session is still stored and still revocable; re-register to resume."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO timestamp of when this session was first registered."
                    },
                    "updated_at": {
                      "type": "string",
                      "description": "ISO timestamp of the last time the session was registered or replaced. Equal to created_at when it has never been re-registered."
                    },
                    "last_used_at": {
                      "type": "string",
                      "description": "ISO timestamp of the last call that acted as this session. Null if it has never been used. A last_used_at that stopped moving is often the first sign of a stalled integration.",
                      "nullable": true
                    },
                    "egress": {
                      "type": "object",
                      "additionalProperties": true,
                      "properties": {
                        "source": {
                          "type": "string",
                          "description": "Which egress tier a write on this session would use: session (the proxy you registered), sticky_residential or pool_residential (an exit we assign and keep stable for this account), or direct (our shared server IP)."
                        },
                        "customer_proxy_in_use": {
                          "type": "boolean",
                          "description": "True when the proxy_url you registered is the one your writes leave from. This is the direct answer to whether your own proxy is being honoured."
                        },
                        "note": {
                          "type": "string",
                          "description": "One line explaining that tier and what to do about it. On the direct tier it explains why a shared IP raises the chance of a challenge."
                        }
                      }
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable summary. Differs for a live session, a dead one, and no session at all."
                    }
                  }
                },
                "example": {
                  "registered": true,
                  "username": "yourhandle",
                  "twitter_user_id": "1234567890123456789",
                  "status": "ok",
                  "created_at": "2026-08-19T19:44:03.433Z",
                  "updated_at": "2026-08-19T19:44:03.433Z",
                  "last_used_at": "2026-08-26T12:34:37.015Z",
                  "egress": {
                    "source": "session",
                    "customer_proxy_in_use": true,
                    "note": "Writes leave through the proxy you registered on this session. Keep it sticky, one dedicated IP per account, and geo-matched to where the account normally signs in."
                  },
                  "message": "Your registered Twitter session is stored and marked live. A per-request proxy sent as x-proxy-url overrides the egress shown here for that call only."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      }
    },
    "/user/user_login": {
      "post": {
        "operationId": "user-user-login",
        "summary": "User Login",
        "description": "Log in to an X account with a username and password (plus a TOTP secret when two-factor authentication is enabled). The API runs the login itself and stores the resulting session server-side against your API key; authenticated-account reads and the write tools then act as that account. It does NOT return session cookies: the response is {ok, username, message}, never auth_token/ct0/twid. Bringing your own auth_token and ct0 via POST /customer/session stays the primary, recommended path, since it never sends a password over the wire. This call costs $0.01, billed only on a successful login; a rejected attempt (bad credentials, captcha, etc.) is never charged. Cost: $0.0100 per call.",
        "tags": [
          "Account Session"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.01,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/user/user_login\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"username\": \"myhandle\", \"password\": \"hunter2\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/user/user_login\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"username\": \"myhandle\", \"password\": \"hunter2\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/user/user_login\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ username: \"myhandle\", password: \"hunter2\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Log in to X with a username and password (plus TOTP for 2FA) and store the resulting session against your API key, so authenticated-account reads and write tools then act as that account. A convenience alternative to bringing your own cookies via Register Session.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the session was created and stored against your API key."
                    },
                    "username": {
                      "type": "string",
                      "description": "The X handle the session belongs to."
                    },
                    "message": {
                      "type": "string",
                      "description": "Human-readable confirmation. On success: \"Logged in. Private-data endpoints will now read as your account.\""
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "username": "myhandle",
                  "message": "Logged in. Private-data endpoints will now read as your account."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "two_factor_required",
                  "message": "This account has 2FA enabled. Include `totp_secret` in the request body."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "bad_credentials",
                  "message": "Username or password was rejected by Twitter. A missing or revoked API key also answers 401, with error unauthorized."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "409": {
            "description": "HTTP 409",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "account_locked",
                  "message": "This account is locked; confirm it from the app, then retry."
                }
              }
            }
          },
          "422": {
            "description": "HTTP 422",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "captcha_required",
                  "message": "Login requires a captcha that could not be solved automatically."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Either this API key hit its per-minute limit or Twitter throttled the login itself. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "502": {
            "description": "HTTP 502",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "login_failed",
                  "message": "Login could not be completed."
                }
              }
            }
          },
          "503": {
            "description": "HTTP 503",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "login_unavailable",
                  "message": "Login egress is exhausted. Try again shortly."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "username": {
                    "type": "string",
                    "description": "The X account username or handle (without the leading @). Aliased as user_name for callers migrating from a twitterapi.io-shaped body."
                  },
                  "password": {
                    "type": "string",
                    "description": "The X account password."
                  },
                  "totp_secret": {
                    "type": "string",
                    "description": "The base32 two-factor (TOTP) secret, required only when the account has 2FA enabled. The API derives the current one-time code from it; omit for accounts without 2FA."
                  },
                  "proxy_url": {
                    "type": "string",
                    "description": "HTTP or SOCKS proxy the login itself runs through, for example http://user:pass@host:port. Optional; defaults to direct egress when omitted."
                  },
                  "user_agent": {
                    "type": "string",
                    "description": "Browser User-Agent sent for the login request. Optional; defaults to a current Chrome UA when omitted."
                  }
                },
                "required": [
                  "username",
                  "password"
                ]
              }
            }
          }
        }
      }
    },
    "/tweet/advanced_search": {
      "get": {
        "operationId": "tweet-advanced-search",
        "summary": "Advanced Tweet Search",
        "description": "Run a full-text tweet search using the same operator syntax as Twitter/X advanced search. Combine free text with operators such as from:, to:, since:, until:, min_faves:, and lang: to filter precisely. Results are cursor-paginated at roughly 20 tweets per call. Cost: $0.0008 per call.",
        "tags": [
          "Search"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/advanced_search?query=from%3Anaval%20min_faves%3A1000&product=Latest\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/advanced_search\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"query\": \"from:naval min_faves:1000\", \"product\": \"Latest\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/advanced_search\");\nurl.search = new URLSearchParams({ query: \"from:naval min_faves:1000\", product: \"Latest\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/tweet/advanced_search?query=from:naval&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/tweet/advanced_search\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"query\": \"from:naval\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { query: \"from:naval\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/tweet/advanced_search\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Search tweets with Twitter's full query-operator syntax, paginated with cursors.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "query": {
                      "type": "string",
                      "description": "Echo of the query you sent."
                    },
                    "product": {
                      "type": "string",
                      "description": "Echo of the ranking product applied to the search."
                    },
                    "tweets": {
                      "type": "array",
                      "description": "Matching tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    },
                    "incomplete": {
                      "type": "boolean",
                      "description": "Present and true only when X soft-limited the search that served this page, so the page may be missing rows. Absent on every healthy page."
                    },
                    "incomplete_reason": {
                      "type": "string",
                      "description": "Why the page is incomplete: upstream_soft_limit. Present only with incomplete."
                    },
                    "upstream_limit": {
                      "type": "object",
                      "description": "X's own limit signal for this page (its error codes and message). Present only with incomplete.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "query": "from:naval min_faves:1000",
                  "product": "Latest",
                  "count": 20,
                  "next_cursor": "DAABCgABF...",
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "Reading > scrolling. Build the input, the output takes care of itself.",
                      "created_at": "Tue Feb 20 14:02:11 +0000 2026",
                      "author": {
                        "id": "745273",
                        "username": "naval",
                        "name": "Naval"
                      },
                      "favorite_count": 4821,
                      "retweet_count": 612,
                      "reply_count": 88,
                      "quote_count": 14,
                      "bookmark_count": 203,
                      "view_count": 219340
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "Search query using Twitter operator syntax.",
            "schema": {
              "type": "string",
              "description": "Search query using Twitter operator syntax.",
              "example": "from:naval min_faves:1000"
            },
            "example": "from:naval min_faves:1000"
          },
          {
            "name": "product",
            "in": "query",
            "required": false,
            "description": "Ranking and result type: Latest, Top, People, Photos, or Videos. Defaults to Latest.",
            "schema": {
              "type": "string",
              "description": "Ranking and result type: Latest, Top, People, Photos, or Videos. Defaults to Latest.",
              "example": "Latest"
            },
            "example": "Latest"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Accepted but not honoured on this endpoint: the upstream page is fixed at roughly 20 results and raising count does not return more. Use cursor to read further.",
            "schema": {
              "type": "integer",
              "description": "Accepted but not honoured on this endpoint: the upstream page is fixed at roughly 20 results and raising count does not return more. Use cursor to read further.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/search": {
      "get": {
        "operationId": "user-search",
        "summary": "User Search",
        "description": "Search X's People directory by keyword. Matches against display name and handle; bio text is not searched, so a term that appears only in a bio returns no match. Useful for discovery, lead lists, and resolving partial handles into full profiles. Cost: $0.0008 per call.",
        "tags": [
          "Search"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/search?query=machine%20learning\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/search\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"query\": \"machine learning\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/search\");\nurl.search = new URLSearchParams({ query: \"machine learning\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Find users by keyword across display names and handles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Matching user objects for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk",
                      "description": "",
                      "followers_count": 211000000,
                      "verified": true
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "Name, keyword or partial handle to search for. Matched against display name and handle, not bio.",
            "schema": {
              "type": "string",
              "description": "Name, keyword or partial handle to search for. Matched against display name and handle, not bio.",
              "example": "machine learning"
            },
            "example": "machine learning"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/tweet/detail": {
      "get": {
        "operationId": "tweet-detail",
        "summary": "Tweet Detail",
        "description": "Resolve a tweet ID into its complete object, including author, engagement counts, attached media, and any quoted tweet. The starting point for any single-tweet workflow. Cost: $0.0008 per call.",
        "tags": [
          "Tweet Details"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/detail?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/detail\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/detail\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch a single tweet's full object by ID.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "Echo of the tweet ID you requested."
                    },
                    "tweet": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Tweet"
                        }
                      ],
                      "description": "The resolved tweet object."
                    }
                  }
                },
                "example": {
                  "id": "1759123456789012345",
                  "tweet": {
                    "id": "1759123456789012345",
                    "text": "Shipping the new docs today.",
                    "created_at": "Tue Feb 20 14:02:11 +0000 2026",
                    "author": {
                      "id": "745273",
                      "username": "naval",
                      "name": "Naval"
                    },
                    "favorite_count": 4821,
                    "retweet_count": 612,
                    "reply_count": 88,
                    "quote_count": 14,
                    "bookmark_count": 203,
                    "view_count": 219340
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to fetch. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to fetch. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet, for example https://x.com/naval/status/1759123456789012345. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet, for example https://x.com/naval/status/1759123456789012345. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/tweet/replies": {
      "get": {
        "operationId": "tweet-replies",
        "summary": "Tweet Replies",
        "description": "Fetch the direct replies to a given tweet, cursor-paginated. Combine with Tweet Detail to reconstruct a discussion or measure reply sentiment. Cost: $0.0008 per call.",
        "tags": [
          "Tweet Details"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/replies?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/replies\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/replies\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through the replies to a tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Reply tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "sort": {
                      "type": "string",
                      "description": "The reply ordering applied to this response: relevance, latest, or likes."
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "DAABCgABF...",
                  "tweets": [
                    {
                      "id": "1759123999000111222",
                      "text": "Congrats on the launch!",
                      "created_at": "Tue Feb 20 14:30:02 +0000 2026",
                      "author": {
                        "id": "9921",
                        "username": "devjane",
                        "name": "Jane"
                      },
                      "favorite_count": 12,
                      "reply_count": 1
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the parent tweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the parent tweet. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the parent tweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the parent tweet. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Reply ordering: relevance (default), latest, or likes.",
            "schema": {
              "type": "string",
              "description": "Reply ordering: relevance (default), latest, or likes.",
              "example": "latest"
            },
            "example": "latest"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/tweet/replies-complete": {
      "get": {
        "operationId": "tweet-replies-complete",
        "summary": "Tweet Replies (Complete)",
        "description": "Fetch all direct replies to a tweet in a single call. The endpoint walks the reply pages for you and returns them together, instead of one cursor page at a time, and reports whether it reached the end. Each call is bounded by max and a server-side time budget, so a large conversation can come back incomplete with a cursor to resume from. Cost: $0.0024 per call.",
        "tags": [
          "Tweet Details"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0024,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/replies-complete?id=1759123456789012345&max=200\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/replies-complete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\", \"max\": 200},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/replies-complete\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\", max: \"200\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch every reply under a tweet in one call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of replies returned in this call."
                    },
                    "tweets": {
                      "type": "array",
                      "description": "The replies gathered across every page walked.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "is_complete": {
                      "type": "boolean",
                      "description": "True when X signalled the end of the conversation. False when the call stopped early: on max, the time budget, the page cap, or a page after the first failing. Resume with next_cursor."
                    },
                    "pages_fetched": {
                      "type": "integer",
                      "description": "How many reply pages were walked to build this response."
                    },
                    "sort": {
                      "type": "string",
                      "description": "The reply ordering applied to this response: relevance, latest, or likes."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": null,
                  "has_more": false,
                  "is_complete": true,
                  "pages_fetched": 1,
                  "sort": "relevance",
                  "tweets": [
                    {
                      "id": "1759123999000111222",
                      "text": "Congrats on the launch!",
                      "created_at": "Tue Feb 20 14:30:02 +0000 2026",
                      "author": {
                        "id": "9921",
                        "username": "devjane",
                        "name": "Jane"
                      },
                      "favorite_count": 12,
                      "reply_count": 1
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the parent tweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the parent tweet. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the parent tweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the parent tweet. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "max",
            "in": "query",
            "required": false,
            "description": "Target number of replies to collect in this call (default 500). Pages arrive whole, so count can pass max by up to one page. Larger values take longer.",
            "schema": {
              "type": "integer",
              "description": "Target number of replies to collect in this call (default 500). Pages arrive whole, so count can pass max by up to one page. Larger values take longer.",
              "example": "200"
            },
            "example": "200"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "description": "Reply ordering: relevance (default), latest, or likes.",
            "schema": {
              "type": "string",
              "description": "Reply ordering: relevance (default), latest, or likes.",
              "example": "latest"
            },
            "example": "latest"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Resume point from a previous response's next_cursor when is_complete was false.",
            "schema": {
              "type": "string",
              "description": "Resume point from a previous response's next_cursor when is_complete was false."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/tweet/retweeters": {
      "get": {
        "operationId": "tweet-retweeters",
        "summary": "Tweet Retweeters",
        "description": "Fetch the users who retweeted a given tweet, cursor-paginated. Useful for amplification analysis and identifying the accounts that spread a post. Cost: $0.0008 per call.",
        "tags": [
          "Tweet Details"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/retweeters?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/retweeters\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/retweeters\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List the users who retweeted a tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Users who retweeted, for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "9921",
                      "username": "devjane",
                      "name": "Jane",
                      "followers_count": 4200,
                      "verified": false
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/tweet/quotes": {
      "get": {
        "operationId": "tweet-quotes",
        "summary": "Tweet Quotes",
        "description": "Fetch the quote tweets of a given tweet, cursor-paginated as full tweet objects, so you can read the commentary people attached rather than just count it. This endpoint is search-backed rather than served by a dedicated X operation, and every response says so in-band via source, search_query and quote_matched. Cost: $0.0008 per call.",
        "tags": [
          "Tweet Details"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/quotes?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/quotes\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/quotes\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/tweet/quotes?id=1759123456789012345&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/tweet/quotes\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"id\": \"1759123456789012345\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { id: \"1759123456789012345\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/tweet/quotes\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through the tweets that quote a tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Quote tweets for this page, as full tweet objects. Each one that X embedded the original on carries the requested tweet under quoted_tweet.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of tweets returned in this page. This is what the SEARCH returned, never the tweet's true quote total, which is quote_count on the tweet object (see Tweet Detail). The two will differ because of search-index lag and because deleted, protected and withheld quotes are not in the index."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Pass it straight back as ?cursor=. Null when there is no further page.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when this page returned tweets and carried a usable next_cursor. False on the final page."
                    },
                    "source": {
                      "type": "string",
                      "description": "Always \"search\". Present so a caller comparing these numbers against X's UI knows this endpoint is served by X's search index and not by a dedicated quote-tweets operation."
                    },
                    "search_query": {
                      "type": "string",
                      "description": "The exact query sent upstream, quoted_tweet_id:<id>, so a surprising result is debuggable without reading our source."
                    },
                    "quote_matched": {
                      "type": "integer",
                      "description": "How many of the returned tweets demonstrably quote the requested id, read off each tweet's embedded quoted_tweet. Equal to count means every row is a genuine quote. Zero on a non-empty page means X stopped honouring the search operator and the rows are junk that merely contain the number."
                    },
                    "quote_count": {
                      "type": "integer",
                      "description": "The tweet's real quote total as X reports it, read from the embedded original on the returned rows, from a cached tweet lookup, or (first page only) one live tweet lookup. Null when it could not be read, or when X reported 0, because a missing count reads as 0.",
                      "nullable": true
                    },
                    "coverage": {
                      "type": "string",
                      "description": "Whether this answer is the whole set: complete (the search ended on the first page with at least quote_count genuine quotes), partial (the search ended on the first page with fewer, so search withheld some), or unknown (anything that cannot be proven: more pages to walk, a later page, no total, or a page where no row demonstrably quotes the tweet)."
                    },
                    "coverage_hint": {
                      "type": "string",
                      "description": "Present only when coverage is partial: a one-line reason, that X search does not return every quote for some accounts."
                    },
                    "requested_count": {
                      "type": "integer",
                      "description": "The count you asked for, echoed as a number (20 when you sent none, null when it was not a number).",
                      "nullable": true
                    },
                    "effective_count": {
                      "type": "integer",
                      "description": "The page size actually requested upstream, 1-20."
                    },
                    "product_used": {
                      "type": "string",
                      "description": "Which ordering actually served this page: Top or Latest. Differs from the product you asked for only when top_fallback is true."
                    },
                    "top_fallback": {
                      "type": "boolean",
                      "description": "Present and true only when you asked for product=Top, the first Top page came back empty, and the page was served from Latest instead. X's ranked search returns an empty first page for some tweets that do have quotes, so an empty Top page is never passed off as zero quotes. Page on with the next_cursor as usual: after a fallback it is tagged so it keeps serving Latest even if you send product=Top again."
                    },
                    "incomplete": {
                      "type": "boolean",
                      "description": "Present and true only when X soft-limited the search that served this page, so the page may be missing rows. Absent on every healthy page."
                    },
                    "incomplete_reason": {
                      "type": "string",
                      "description": "Why the page is incomplete: upstream_soft_limit. Present only with incomplete."
                    },
                    "upstream_limit": {
                      "type": "object",
                      "description": "X's own limit signal for this page (its error codes and message). Present only with incomplete.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "count": 2,
                  "next_cursor": "DAADDAABCgABF...",
                  "has_more": true,
                  "tweets": [
                    {
                      "id": "1759987654321098765",
                      "text": "This is the clearest write-up of the problem I have read all year.",
                      "created_at": "Tue Feb 20 16:02:11 +0000 2026",
                      "author": {
                        "id": "9921",
                        "username": "devjane",
                        "name": "Jane"
                      },
                      "is_quote": true,
                      "quoted_tweet": {
                        "id": "1759123456789012345",
                        "text": "Launching today."
                      },
                      "favorite_count": 41
                    },
                    {
                      "id": "1759988812345678901",
                      "text": "Adding one caveat to this.",
                      "created_at": "Tue Feb 20 16:20:44 +0000 2026",
                      "author": {
                        "id": "3310",
                        "username": "buildlogs",
                        "name": "Build Logs"
                      },
                      "is_quote": true,
                      "quoted_tweet": {
                        "id": "1759123456789012345",
                        "text": "Launching today."
                      },
                      "favorite_count": 7
                    }
                  ],
                  "source": "search",
                  "search_query": "quoted_tweet_id:1759123456789012345",
                  "quote_matched": 2,
                  "requested_count": 20,
                  "effective_count": 20,
                  "quote_count": 48,
                  "coverage": "unknown"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet whose quotes you want. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet whose quotes you want. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet whose quotes you want. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet whose quotes you want. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to request for this page, 1-20. Defaults to 20. X's search returns at most 20 per page, so a larger number is clamped to 20 rather than erroring, and the response echoes both requested_count and effective_count.",
            "schema": {
              "type": "integer",
              "description": "Max items to request for this page, 1-20. Defaults to 20. X's search returns at most 20 per page, so a larger number is clamped to 20 rather than erroring, and the response echoes both requested_count and effective_count.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "product",
            "in": "query",
            "required": false,
            "description": "Search ordering: Latest (default, reverse-chronological) or Top (X's ranked ordering, materially slower upstream). Any other value falls back to Latest rather than changing what the endpoint means.",
            "schema": {
              "type": "string",
              "description": "Search ordering: Latest (default, reverse-chronological) or Top (X's ranked ordering, materially slower upstream). Any other value falls back to Latest rather than changing what the endpoint means.",
              "example": "Latest"
            },
            "example": "Latest"
          },
          {
            "name": "strict",
            "in": "query",
            "required": false,
            "description": "Set to true to drop every returned row that does not demonstrably quote the requested tweet, instead of only counting them in quote_matched. Default false, because X does not embed the quoted original on every search result, so strict mode can hide real quotes.",
            "schema": {
              "type": "boolean",
              "description": "Set to true to drop every returned row that does not demonstrably quote the requested tweet, instead of only counting them in quote_matched. Default false, because X does not embed the quoted original on every search result, so strict mode can hide real quotes.",
              "example": "false"
            },
            "example": "false"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/tweet/thread": {
      "get": {
        "operationId": "tweet-thread",
        "summary": "Tweet Thread",
        "description": "Given the first tweet of a thread, return the ordered list of tweets that make up the author's connected thread. The endpoint reads forward from the tweet you pass and does not walk backwards, so pass the thread's first tweet, which is the conversation_id carried on every tweet in that thread. Passing a later tweet returns only the tail of the thread. Cost: $0.0040 per call.",
        "tags": [
          "Tweet Details"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.004,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/tweet/thread?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/tweet/thread\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/thread\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Reconstruct a thread forward from its first tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Ordered tweets composing the thread.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of tweets in the thread. The whole thread is returned in one call, so there is no cursor and no second page."
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "1/ Here is how we made the API 100x cheaper.",
                      "author": {
                        "id": "745273",
                        "username": "naval"
                      }
                    },
                    {
                      "id": "1759123456789012346",
                      "text": "2/ It starts with batching ~20 tweets per call.",
                      "author": {
                        "id": "745273",
                        "username": "naval"
                      }
                    }
                  ],
                  "count": 2
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of any tweet in the thread. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of any tweet in the thread. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of any tweet in the thread. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of any tweet in the thread. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/info": {
      "get": {
        "operationId": "user-info",
        "summary": "User Info by Username",
        "description": "Resolve a username into the full user object: bio, follower and following counts, verification status, location, and avatar. The canonical entry point for profile lookups. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/info?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/info\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/info\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch a full profile by @handle.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/User"
                        }
                      ],
                      "description": "The resolved user object."
                    }
                  }
                },
                "example": {
                  "user": {
                    "id": "745273",
                    "username": "naval",
                    "name": "Naval",
                    "description": "Angel investor.",
                    "followers_count": 2100000,
                    "following_count": 421,
                    "verified": true,
                    "profile_image_url": "https://pbs.twimg.com/profile_images/.../avatar.jpg"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/info_by_id": {
      "get": {
        "operationId": "user-info-by-id",
        "summary": "User Info by ID",
        "description": "Resolve a numeric user ID into the full user object. Use this when you already have the stable ID (handles can change, IDs do not). Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/info_by_id?user_id=745273\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/info_by_id\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"user_id\": \"745273\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/info_by_id\");\nurl.search = new URLSearchParams({ user_id: \"745273\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch a full profile by numeric user ID.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/User"
                        }
                      ],
                      "description": "The resolved user object."
                    }
                  }
                },
                "example": {
                  "user": {
                    "id": "745273",
                    "username": "naval",
                    "name": "Naval",
                    "followers_count": 2100000,
                    "verified": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the user.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the user.",
              "example": "745273"
            },
            "example": "745273"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/status": {
      "get": {
        "operationId": "user-status",
        "summary": "User Status",
        "description": "Return the liveness state of a handle: alive, suspended, not_found, or unavailable. Every outcome is an HTTP 200 and the caller branches on the status field. This exists because a standard profile lookup collapses suspended, deleted, and never-existed into one indistinguishable 404. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/status?userName=openai\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/status\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"userName\": \"openai\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/status\");\nurl.search = new URLSearchParams({ userName: \"openai\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Check whether an account is alive, suspended, or deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "userName": {
                      "type": "string",
                      "description": "The handle you asked about, echoed back."
                    },
                    "status": {
                      "type": "string",
                      "description": "One of alive, suspended, not_found, or unavailable. `unavailable` means X reported a state we do not map to the other three; the reason field carries its wording."
                    },
                    "id": {
                      "type": "string",
                      "description": "The numeric user ID when the account is alive; null otherwise.",
                      "nullable": true
                    },
                    "reason": {
                      "type": "string",
                      "description": "X's own explanation when it gives one; null for a healthy account.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "userName": "openai",
                  "status": "alive",
                  "id": "1634058197493178368",
                  "reason": null
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "userName",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @. The alias `username` is also accepted.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @. The alias `username` is also accepted.",
              "example": "openai"
            },
            "example": "openai"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/user_about": {
      "get": {
        "operationId": "user-user-about",
        "summary": "User About",
        "description": "Read a profile's full About object: identity, bio, location, linked website, avatar, verification and identity-verification flags, professional account type and categories, follower and following counts, the account creation date, and X's \"About this account\" transparency panel (account country, how the account was created, and username-change history). Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/user_about?username=stripe\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/user_about\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"stripe\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/user_about\");\nurl.search = new URLSearchParams({ username: \"stripe\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch a profile's extended About / professional details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "about": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/About"
                        }
                      ],
                      "description": "The profile's full About object: identity, bio, location, linked website, avatar, verification and identity-verification flags, professional account type and categories, follower and following counts, the account creation date, and X's \"About this account\" transparency panel (account country, how the account was created, and username-change history)."
                    }
                  }
                },
                "example": {
                  "about": {
                    "id": "13334762",
                    "username": "stripe",
                    "name": "Stripe",
                    "description": "Payments infrastructure for the internet.",
                    "location": "San Francisco, CA",
                    "url": "https://stripe.com",
                    "is_blue_verified": true,
                    "verified": true,
                    "verified_type": "Business",
                    "professional_type": "Business",
                    "professional_categories": [
                      "Software Company"
                    ],
                    "followers_count": 312000,
                    "following_count": 412,
                    "created_at": "Tue Feb 12 18:02:11 +0000 2008",
                    "profile_image_url": "https://pbs.twimg.com/profile_images/1841086032213626880/example_normal.jpg",
                    "is_identity_verified": false,
                    "verified_since": null,
                    "account_based_in": "United States",
                    "created_via": "United States App Store",
                    "username_changes": {
                      "count": 0,
                      "last_changed_at": null
                    },
                    "created_country_accurate": true,
                    "location_accurate": true,
                    "learn_more_url": "https://help.twitter.com/managing-your-account/about-twitter-verified-accounts"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @. Required: unlike the other user reads, this endpoint cannot be called with user_id alone.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @. Required: unlike the other user reads, this endpoint cannot be called with user_id alone.",
              "example": "stripe"
            },
            "example": "stripe"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID. Not currently a substitute for username on this endpoint: a user_id-only request fails upstream. Resolve the ID to a handle with GET /user/info_by_id and pass username.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID. Not currently a substitute for username on this endpoint: a user_id-only request fails upstream. Resolve the ID to a handle with GET /user/info_by_id and pass username.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/user_about/batch": {
      "get": {
        "operationId": "user-user-about-batch",
        "summary": "User About Batch",
        "description": "Read the full About object for up to 100 accounts in one request: the same object GET /user/user_about returns, including X's \"About this account\" transparency panel (account country, how the account was created, and username-change history). Results come back in request order, each with its about object or an error code. Cost: $0.0008 per billed item.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/user_about/batch?usernames=stripe,nasa,openai\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/user_about/batch\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"usernames\": \"stripe,nasa,openai\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/user_about/batch\");\nurl.search = new URLSearchParams({ usernames: \"stripe,nasa,openai\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch the About object for up to 100 accounts in one request.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "requested": {
                      "type": "integer",
                      "description": "Number of distinct accounts in the request, after duplicates were removed."
                    },
                    "served": {
                      "type": "integer",
                      "description": "Number of items that returned an about object."
                    },
                    "billed_items": {
                      "type": "integer",
                      "description": "Number of items this call was billed for: every account X answered for, found or not_found. Multiply by $0.0008 for the charge."
                    },
                    "results": {
                      "type": "array",
                      "description": "One entry per requested account, in request order.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "username": {
                            "type": "string",
                            "description": "The handle as you sent it, without the leading @. Present when the request used usernames."
                          },
                          "user_id": {
                            "type": "string",
                            "description": "The numeric user ID as you sent it. Present when the request used user_ids."
                          },
                          "about": {
                            "allOf": [
                              {
                                "$ref": "#/components/schemas/About"
                              }
                            ],
                            "description": "The account's full About object, the same object GET /user/user_about returns. Present only on a found item."
                          },
                          "error": {
                            "type": "string",
                            "description": "Present only on an item without an about object. One of not_found (X confirmed no such account; billed), forbidden (X refuses this account to every caller; not billed, retrying will not help), rate_limited or unavailable (failed on our side; not billed, safe to retry)."
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "requested": 3,
                  "served": 1,
                  "billed_items": 2,
                  "results": [
                    {
                      "username": "stripe",
                      "about": {
                        "id": "102812444",
                        "username": "stripe",
                        "name": "Stripe",
                        "verified_type": "Business",
                        "professional_type": "Business",
                        "account_based_in": "United States",
                        "created_via": "Web",
                        "username_changes": {
                          "count": 0,
                          "last_changed_at": null
                        },
                        "created_country_accurate": true
                      }
                    },
                    {
                      "username": "no_such_handle",
                      "error": "not_found"
                    },
                    {
                      "username": "nasa",
                      "error": "rate_limited"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "bad_request",
                  "message": "Provide `usernames` or `user_ids`, not both."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "unauthorized",
                  "message": "Missing or invalid x-api-key header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Not enough credits for 3 items. Top up, or send a smaller batch."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "batch_in_progress",
                  "message": "One batch per API key at a time. Retry when the running batch returns. Not billed."
                }
              }
            }
          },
          "503": {
            "description": "HTTP 503",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "upstream_unavailable",
                  "message": "No item could be fetched right now. This is temporary; retry shortly."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "usernames",
            "in": "query",
            "required": false,
            "description": "Comma-separated handles, with or without the leading @. Send this or user_ids, never both. Between 1 and 100 distinct entries after duplicates are removed (handles compare case-insensitively). A malformed handle returns a 400 for the whole request.",
            "schema": {
              "type": "string",
              "description": "Comma-separated handles, with or without the leading @. Send this or user_ids, never both. Between 1 and 100 distinct entries after duplicates are removed (handles compare case-insensitively). A malformed handle returns a 400 for the whole request.",
              "example": "stripe,nasa,openai"
            },
            "example": "stripe,nasa,openai"
          },
          {
            "name": "user_ids",
            "in": "query",
            "required": false,
            "description": "Comma-separated numeric user IDs, as an alternative to usernames. Send this or usernames, never both. Same 1 to 100 limit. Each ID is resolved to its current handle, then looked up; results echo each ID as you sent it. Leading zeros are ignored for duplicates (012 and 12 are one account).",
            "schema": {
              "type": "string",
              "description": "Comma-separated numeric user IDs, as an alternative to usernames. Send this or usernames, never both. Same 1 to 100 limit. Each ID is resolved to its current handle, then looked up; results echo each ID as you sent it. Leading zeros are ignored for duplicates (012 and 12 are one account).",
              "example": "44196397,11348282"
            },
            "example": "44196397,11348282"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/media": {
      "get": {
        "operationId": "user-media",
        "summary": "User Media",
        "description": "Fetch the media tweets posted by a user, cursor-paginated. Returns the tweet objects from the account's Media tab, with media URLs included under extended_entities.media. The tab occasionally surfaces a link-or-card tweet with no attachment, so guard on extended_entities before reading it. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/media?username=nasa\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/media\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"nasa\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/media\");\nurl.search = new URLSearchParams({ username: \"nasa\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through a profile's media tweets (images and video).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Media tweets for this page (each carries its attachments under extended_entities.media).",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1759987654321000111",
                      "text": "A new image of the Pillars of Creation.",
                      "extended_entities": {
                        "media": [
                          {
                            "type": "photo",
                            "media_url_https": "https://pbs.twimg.com/media/abc.jpg",
                            "url": "https://t.co/abc123",
                            "ext_alt_text": "The Pillars of Creation imaged by JWST."
                          }
                        ]
                      },
                      "author": {
                        "id": "11348282",
                        "username": "nasa"
                      }
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "nasa"
            },
            "example": "nasa"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/tweets": {
      "get": {
        "operationId": "user-tweets",
        "summary": "User Tweets",
        "description": "Page through a user's public timeline, cursor-paginated at roughly 20 tweets per call. The page mirrors the account's timeline as X returns it, so it contains original tweets, retweets, and the account's own replies. Each tweet carries is_retweet and is_reply, so filter client-side if you want original posts only. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/tweets?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/tweets\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/tweets\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/tweets?username=naval&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/tweets\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"username\": \"naval\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { username: \"naval\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/tweets\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch a user's public timeline (original tweets, retweets, and their own replies).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Timeline tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "Reading > scrolling.",
                      "created_at": "Tue Feb 20 14:02:11 +0000 2026",
                      "author": {
                        "id": "745273",
                        "username": "naval"
                      },
                      "favorite_count": 4821
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Accepted but not honoured on this endpoint: the upstream timeline page is fixed at roughly 20 tweets and raising count does not return more. Use cursor to read further back.",
            "schema": {
              "type": "integer",
              "description": "Accepted but not honoured on this endpoint: the upstream timeline page is fixed at roughly 20 tweets and raising count does not return more. Use cursor to read further back.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/tweets_and_replies": {
      "get": {
        "operationId": "user-tweets-and-replies",
        "summary": "User Tweets and Replies",
        "description": "Page through a user's public timeline including the replies the account posted. This endpoint resolves to the same upstream timeline as GET /user/tweets and returns the same tweets in the same order, so treat it as an alias kept for compatibility rather than a wider result set. Each tweet carries is_retweet and is_reply for client-side filtering. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/tweets_and_replies?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/tweets_and_replies\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/tweets_and_replies\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch a user's timeline including their replies (same upstream timeline as User Tweets).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Timeline tweets and replies for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "@founder Great point, here is the data.",
                      "author": {
                        "id": "745273",
                        "username": "naval"
                      }
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Accepted but not honoured on this endpoint: the upstream timeline page is fixed at roughly 20 tweets and raising count does not return more. Use cursor to read further back.",
            "schema": {
              "type": "integer",
              "description": "Accepted but not honoured on this endpoint: the upstream timeline page is fixed at roughly 20 tweets and raising count does not return more. Use cursor to read further back.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/mentions": {
      "get": {
        "operationId": "user-mentions",
        "summary": "User Mentions",
        "description": "Return the tweets that mention a given account, cursor-paginated. This is the canonical way to read a handle's mentions; it is a thin wrapper over a to:username search and returns the same tweet objects. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/mentions?username=twitterapis\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/mentions\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"twitterapis\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/mentions\");\nurl.search = new URLSearchParams({ username: \"twitterapis\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch tweets that mention a username.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Tweets mentioning the username, for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    },
                    "incomplete": {
                      "type": "boolean",
                      "description": "Present and true only when X soft-limited the search that served this page, so the page may be missing rows. Absent on every healthy page."
                    },
                    "incomplete_reason": {
                      "type": "string",
                      "description": "Why the page is incomplete: upstream_soft_limit. Present only with incomplete."
                    },
                    "upstream_limit": {
                      "type": "object",
                      "description": "X's own limit signal for this page (its error codes and message). Present only with incomplete.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1759555444333222111",
                      "text": "@twitterapis just shipped great docs.",
                      "author": {
                        "id": "9921",
                        "username": "devjane"
                      }
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @ to find mentions of.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @ to find mentions of.",
              "example": "twitterapis"
            },
            "example": "twitterapis"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Accepted but not honoured on this endpoint: the upstream page is fixed at roughly 20 results and raising count does not return more. Use cursor to read further.",
            "schema": {
              "type": "integer",
              "description": "Accepted but not honoured on this endpoint: the upstream page is fixed at roughly 20 results and raising count does not return more. Use cursor to read further.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/affiliates": {
      "get": {
        "operationId": "user-affiliates",
        "summary": "User Affiliates",
        "description": "Return the affiliated accounts linked under an organization's Verified Organizations profile. Useful for mapping a company to its employees and brand accounts. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/affiliates?username=stripe\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/affiliates\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"stripe\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/affiliates\");\nurl.search = new URLSearchParams({ username: \"stripe\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List the affiliated sub-accounts of an organization profile.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Affiliated user accounts for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "12345",
                      "username": "stripedev",
                      "name": "Stripe Developers",
                      "verified": true
                    }
                  ],
                  "next_cursor": ""
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle of the organization account.",
            "schema": {
              "type": "string",
              "description": "Handle of the organization account.",
              "example": "stripe"
            },
            "example": "stripe"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "team",
            "in": "query",
            "required": false,
            "description": "Affiliate team filter, when the organization exposes teams.",
            "schema": {
              "type": "string",
              "description": "Affiliate team filter, when the organization exposes teams."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/check_follow_relationship": {
      "get": {
        "operationId": "user-check-follow-relationship",
        "summary": "Check Follow Relationship",
        "description": "Return the directional relationship between a source and target user: whether source follows target (following) and target follows source (followed_by), plus block, mute, and DM-eligibility flags. An account that does not exist returns a 404 with error not_found; the relationship object is null when X returns none. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/check_follow_relationship?source_user_id=745273&target_user_id=2178758961\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/check_follow_relationship\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"source_user_id\": \"745273\", \"target_user_id\": \"2178758961\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/check_follow_relationship\");\nurl.search = new URLSearchParams({ source_user_id: \"745273\", target_user_id: \"2178758961\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Check whether one user follows another.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "relationship": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Relationship"
                        }
                      ],
                      "description": "The directional relationship between source and target. Null when X returns no relationship object.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "relationship": {
                    "source_id": "745273",
                    "target_id": "2178758961",
                    "following": true,
                    "followed_by": false,
                    "blocking": null,
                    "blocked_by": null,
                    "muting": null,
                    "can_dm": true
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "source_user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the account whose following is checked. Send this or source_username.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the account whose following is checked. Send this or source_username.",
              "example": "745273"
            },
            "example": "745273"
          },
          {
            "name": "source_username",
            "in": "query",
            "required": false,
            "description": "Handle of the source account, as an alternative to source_user_id. Resolved to its ID first; an unknown handle returns a 404 and nothing is billed.",
            "schema": {
              "type": "string",
              "description": "Handle of the source account, as an alternative to source_user_id. Resolved to its ID first; an unknown handle returns a 404 and nothing is billed.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "target_user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the account being checked against. Send this or target_username.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the account being checked against. Send this or target_username.",
              "example": "2178758961"
            },
            "example": "2178758961"
          },
          {
            "name": "target_username",
            "in": "query",
            "required": false,
            "description": "Handle of the target account, as an alternative to target_user_id. Resolved to its ID first; an unknown handle returns a 404 and nothing is billed.",
            "schema": {
              "type": "string",
              "description": "Handle of the target account, as an alternative to target_user_id. Resolved to its ID first; an unknown handle returns a 404 and nothing is billed.",
              "example": "openai"
            },
            "example": "openai"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/check_follow_relationship/batch": {
      "get": {
        "operationId": "user-check-follow-relationship-batch",
        "summary": "Check Follow Relationship Batch",
        "description": "Check the directional relationship between one fixed account and up to 100 others in one request: one source against up to 100 targets, or one target against up to 100 sources. Each item carries the same relationship object GET /user/check_follow_relationship returns, read from the source's side: whether the source follows the target (following) and the target follows the source (followed_by), plus block, mute, and DM-eligibility flags. Results come back in request order, each with its relationship object or an error code. Cost: $0.0008 per billed item.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/check_follow_relationship/batch?source_username=stripe&target_usernames=nasa,openai,no_such_handle\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/check_follow_relationship/batch\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"source_username\": \"stripe\", \"target_usernames\": \"nasa,openai,no_such_handle\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/check_follow_relationship/batch\");\nurl.search = new URLSearchParams({ source_username: \"stripe\", target_usernames: \"nasa,openai,no_such_handle\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Check one account's follow relationship with up to 100 others in one request.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source_user_id": {
                      "type": "string",
                      "description": "Numeric ID of the single source account. Present when the list is targets."
                    },
                    "target_user_id": {
                      "type": "string",
                      "description": "Numeric ID of the single target account. Present when the list is sources."
                    },
                    "requested": {
                      "type": "integer",
                      "description": "Number of distinct accounts in the list, after duplicates were removed."
                    },
                    "served": {
                      "type": "integer",
                      "description": "Number of items that returned a relationship object."
                    },
                    "billed_items": {
                      "type": "integer",
                      "description": "Number of pairs this call was billed for: every pair that came back with a relationship object (not_found is free). Multiply by $0.0008 for the charge."
                    },
                    "results": {
                      "type": "array",
                      "description": "One entry per listed account, in request order.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "target_username": {
                            "type": "string",
                            "description": "The target handle as you sent it, without the leading @. Present when the request used target_usernames."
                          },
                          "target_user_id": {
                            "type": "string",
                            "description": "The target ID as you sent it. Present when the request used target_user_ids."
                          },
                          "source_username": {
                            "type": "string",
                            "description": "The source handle as you sent it, without the leading @. Present when the request used source_usernames."
                          },
                          "source_user_id": {
                            "type": "string",
                            "description": "The source ID as you sent it. Present when the request used source_user_ids."
                          },
                          "relationship": {
                            "allOf": [
                              {
                                "$ref": "#/components/schemas/Relationship"
                              }
                            ],
                            "description": "The relationship between this pair, the same object GET /user/check_follow_relationship returns, read from the source's side: following is true when the source follows the target, followed_by when the target follows the source, plus blocking, blocked_by, muting, can_dm, source_id and target_id. Present only on a found item."
                          },
                          "error": {
                            "type": "string",
                            "description": "Present only on an item without a relationship object. One of not_found (no relationship to report, because an account does not exist or a listed handle did not resolve; not billed), forbidden (X refuses this pair to every caller; not billed, retrying will not help), rate_limited or unavailable (failed on our side; not billed, safe to retry)."
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "source_user_id": "102812444",
                  "requested": 3,
                  "served": 2,
                  "billed_items": 2,
                  "results": [
                    {
                      "target_username": "nasa",
                      "relationship": {
                        "source_id": "102812444",
                        "target_id": "11348282",
                        "following": false,
                        "followed_by": true,
                        "blocking": null,
                        "blocked_by": null,
                        "muting": null,
                        "can_dm": false
                      }
                    },
                    {
                      "target_username": "openai",
                      "relationship": {
                        "source_id": "102812444",
                        "target_id": "4398626122",
                        "following": true,
                        "followed_by": true,
                        "blocking": null,
                        "blocked_by": null,
                        "muting": null,
                        "can_dm": true
                      }
                    },
                    {
                      "target_username": "no_such_handle",
                      "error": "not_found"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "bad_request",
                  "message": "Send a list on ONE side only: target_usernames/target_user_ids or source_usernames/source_user_ids."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "unauthorized",
                  "message": "Missing or invalid x-api-key header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Not enough credits for 3 items. Top up, or send a smaller batch."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "not_found",
                  "message": "Could not resolve @no_such_handle."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "batch_in_progress",
                  "message": "One batch per API key at a time. Retry when the running batch returns. Not billed."
                }
              }
            }
          },
          "503": {
            "description": "HTTP 503",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message",
                    "retry_after_seconds"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "retry_after_seconds": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "error": "upstream_unavailable",
                  "message": "No item could be fetched right now. This is temporary; retry shortly.",
                  "retry_after_seconds": 5
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "source_user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the single source account, when the list is targets. Used as sent, with no lookup; wins over source_username when both are sent.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the single source account, when the list is targets. Used as sent, with no lookup; wins over source_username when both are sent.",
              "example": "102812444"
            },
            "example": "102812444"
          },
          {
            "name": "source_username",
            "in": "query",
            "required": false,
            "description": "Handle of the single source account, when the list is targets. Resolved to its numeric ID first; an unknown handle returns a 404 and nothing is billed.",
            "schema": {
              "type": "string",
              "description": "Handle of the single source account, when the list is targets. Resolved to its numeric ID first; an unknown handle returns a 404 and nothing is billed.",
              "example": "stripe"
            },
            "example": "stripe"
          },
          {
            "name": "target_usernames",
            "in": "query",
            "required": false,
            "description": "Comma-separated target handles, with or without the leading @, checked against the single source. Send this or target_user_ids, never both, and never together with a source list. Between 1 and 100 distinct entries after duplicates are removed (handles compare case-insensitively). A malformed handle returns a 400 for the whole request.",
            "schema": {
              "type": "string",
              "description": "Comma-separated target handles, with or without the leading @, checked against the single source. Send this or target_user_ids, never both, and never together with a source list. Between 1 and 100 distinct entries after duplicates are removed (handles compare case-insensitively). A malformed handle returns a 400 for the whole request.",
              "example": "nasa,openai"
            },
            "example": "nasa,openai"
          },
          {
            "name": "target_user_ids",
            "in": "query",
            "required": false,
            "description": "Comma-separated numeric target IDs, as an alternative to target_usernames. Same 1 to 100 limit. Leading zeros are ignored for duplicates (012 and 12 are one account); results echo each ID as you sent it.",
            "schema": {
              "type": "string",
              "description": "Comma-separated numeric target IDs, as an alternative to target_usernames. Same 1 to 100 limit. Leading zeros are ignored for duplicates (012 and 12 are one account); results echo each ID as you sent it.",
              "example": "11348282,4398626122"
            },
            "example": "11348282,4398626122"
          },
          {
            "name": "target_user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the single target account, when the list is sources. Used as sent, with no lookup; wins over target_username when both are sent.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the single target account, when the list is sources. Used as sent, with no lookup; wins over target_username when both are sent.",
              "example": "102812444"
            },
            "example": "102812444"
          },
          {
            "name": "target_username",
            "in": "query",
            "required": false,
            "description": "Handle of the single target account, when the list is sources. Resolved to its numeric ID first; an unknown handle returns a 404 and nothing is billed.",
            "schema": {
              "type": "string",
              "description": "Handle of the single target account, when the list is sources. Resolved to its numeric ID first; an unknown handle returns a 404 and nothing is billed.",
              "example": "stripe"
            },
            "example": "stripe"
          },
          {
            "name": "source_usernames",
            "in": "query",
            "required": false,
            "description": "Comma-separated source handles, with or without the leading @, each checked against the single target. Send this or source_user_ids, never both, and never together with a target list. Between 1 and 100 distinct entries after duplicates are removed (handles compare case-insensitively). A malformed handle returns a 400 for the whole request.",
            "schema": {
              "type": "string",
              "description": "Comma-separated source handles, with or without the leading @, each checked against the single target. Send this or source_user_ids, never both, and never together with a target list. Between 1 and 100 distinct entries after duplicates are removed (handles compare case-insensitively). A malformed handle returns a 400 for the whole request.",
              "example": "nasa,openai"
            },
            "example": "nasa,openai"
          },
          {
            "name": "source_user_ids",
            "in": "query",
            "required": false,
            "description": "Comma-separated numeric source IDs, as an alternative to source_usernames. Same 1 to 100 limit. Leading zeros are ignored for duplicates (012 and 12 are one account); results echo each ID as you sent it.",
            "schema": {
              "type": "string",
              "description": "Comma-separated numeric source IDs, as an alternative to source_usernames. Same 1 to 100 limit. Leading zeros are ignored for duplicates (012 and 12 are one account); results echo each ID as you sent it.",
              "example": "11348282,4398626122"
            },
            "example": "11348282,4398626122"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/audience_summary": {
      "get": {
        "operationId": "user-audience-summary",
        "summary": "Audience Summary",
        "description": "Sample up to 100 of an account's followers, or of a tweet's retweeters, read each sampled account's About object, and return a country histogram of account_based_in with each country's share of the accounts whose country is known. The response also counts how many sampled accounts show each of seven documented profile signals and how many show three or more (likely_bot_count), a heuristic over profile fields rather than a verdict on any account. Cost: $0.0008 per billed item.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/audience_summary?username=stripe&sample=50\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/audience_summary\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"stripe\", \"sample\": 50},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/audience_summary\");\nurl.search = new URLSearchParams({ username: \"stripe\", sample: 50 }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Summarize a sample of an account's followers or a tweet's retweeters by country and likely-bot share.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": {
                      "type": "string",
                      "description": "The audience sampled: followers or retweeters."
                    },
                    "user_id": {
                      "type": "string",
                      "description": "Numeric ID of the account whose followers were sampled. Present when source is followers."
                    },
                    "tweet_id": {
                      "type": "string",
                      "description": "The tweet whose retweeters were sampled. Present when source is retweeters."
                    },
                    "sample_requested": {
                      "type": "integer",
                      "description": "The sample size you asked for (the sample parameter, default 50)."
                    },
                    "sample_size": {
                      "type": "integer",
                      "description": "Distinct accounts actually sampled. Lower than sample_requested when the audience is smaller or the pages ran out."
                    },
                    "about_answered": {
                      "type": "integer",
                      "description": "Sampled accounts X answered an About read for, found or not_found. Each is billed."
                    },
                    "countries": {
                      "type": "array",
                      "description": "Country histogram over the sampled accounts with a known account_based_in, most common first (ties in alphabetical order).",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "country": {
                            "type": "string",
                            "description": "The country, as X reports it in account_based_in."
                          },
                          "count": {
                            "type": "integer",
                            "description": "Sampled accounts based in this country."
                          },
                          "share": {
                            "type": "number",
                            "description": "count divided by country_known, rounded to three decimals. Shares are over accounts with a known country, not over the whole sample."
                          }
                        }
                      }
                    },
                    "country_known": {
                      "type": "integer",
                      "description": "Sampled accounts whose About read returned a country."
                    },
                    "country_unknown": {
                      "type": "integer",
                      "description": "sample_size minus country_known: accounts with no country on X, accounts answered not_found, and accounts whose About read failed."
                    },
                    "likely_bot_count": {
                      "type": "integer",
                      "description": "Sampled accounts showing 3 or more of the 7 bot signals. A heuristic over profile fields, not a verdict on any account."
                    },
                    "likely_bot_share": {
                      "type": "number",
                      "description": "likely_bot_count divided by sample_size, rounded to three decimals. 0 when nothing was sampled."
                    },
                    "bot_signal_counts": {
                      "type": "object",
                      "description": "How many sampled accounts show each signal, one key per signal. A field the profile does not carry never counts; the default image is read from default_profile_image, or from the profile image URL when X omits that flag.",
                      "additionalProperties": true,
                      "properties": {
                        "default_profile_image": {
                          "type": "integer",
                          "description": "Accounts that still have X's default profile image."
                        },
                        "empty_bio": {
                          "type": "integer",
                          "description": "Accounts with no bio."
                        },
                        "under_5_followers": {
                          "type": "integer",
                          "description": "Accounts with fewer than 5 followers."
                        },
                        "follow_ratio_over_20": {
                          "type": "integer",
                          "description": "Accounts that follow over 500 accounts and more than 20 times their follower count."
                        },
                        "no_posts": {
                          "type": "integer",
                          "description": "Accounts that have never posted."
                        },
                        "created_under_30_days": {
                          "type": "integer",
                          "description": "Accounts created in the last 30 days."
                        },
                        "digit_suffix_handle": {
                          "type": "integer",
                          "description": "Accounts whose handle ends in 6 or more digits (the auto-generated pattern)."
                        }
                      }
                    },
                    "bot_rule": {
                      "type": "string",
                      "description": "The likely-bot rule in plain words: the threshold and the 7 signals, exactly as applied to this response."
                    },
                    "pages_fetched": {
                      "type": "integer",
                      "description": "Sample pages that added at least one account, at most 3. Each is billed; an empty trailing page is not counted."
                    },
                    "billed_items": {
                      "type": "integer",
                      "description": "pages_fetched plus about_answered: the items this call was billed for. Multiply by $0.0008 for the charge."
                    }
                  }
                },
                "example": {
                  "source": "followers",
                  "user_id": "102812444",
                  "sample_requested": 50,
                  "sample_size": 50,
                  "about_answered": 48,
                  "countries": [
                    {
                      "country": "United States",
                      "count": 21,
                      "share": 0.477
                    },
                    {
                      "country": "India",
                      "count": 9,
                      "share": 0.205
                    },
                    {
                      "country": "United Kingdom",
                      "count": 6,
                      "share": 0.136
                    },
                    {
                      "country": "Germany",
                      "count": 5,
                      "share": 0.114
                    },
                    {
                      "country": "Brazil",
                      "count": 3,
                      "share": 0.068
                    }
                  ],
                  "country_known": 44,
                  "country_unknown": 6,
                  "likely_bot_count": 4,
                  "likely_bot_share": 0.08,
                  "bot_signal_counts": {
                    "default_profile_image": 7,
                    "empty_bio": 12,
                    "under_5_followers": 5,
                    "follow_ratio_over_20": 3,
                    "no_posts": 4,
                    "created_under_30_days": 2,
                    "digit_suffix_handle": 6
                  },
                  "bot_rule": "an account counts as likely automated when it shows 3 or more of: still has X's default profile image; no bio; fewer than 5 followers; follows over 500 accounts and more than 20 times its follower count; has never posted; account created in the last 30 days; handle ends in 6 or more digits (the auto-generated pattern)",
                  "pages_fetched": 2,
                  "billed_items": 50
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "bad_request",
                  "message": "`sample` must be a whole number from 10 to 100."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "unauthorized",
                  "message": "Missing or invalid x-api-key header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Not enough credits for 53 items. Top up, or send a smaller batch."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "not_found",
                  "message": "Could not resolve @no_such_handle."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "batch_in_progress",
                  "message": "One batch per API key at a time. Retry when the running batch returns. Not billed."
                }
              }
            }
          },
          "503": {
            "description": "HTTP 503",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "error",
                    "message",
                    "upstream_status"
                  ],
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "upstream_status": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "error": "upstream_unavailable",
                  "message": "The audience could not be sampled right now. Not billed; retry shortly.",
                  "upstream_status": 503
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": false,
            "description": "Handle whose followers are sampled, with or without the leading @. Send username, user_id, or tweet_id. An unknown handle returns a 404 and nothing is billed.",
            "schema": {
              "type": "string",
              "description": "Handle whose followers are sampled, with or without the leading @. Send username, user_id, or tweet_id. An unknown handle returns a 404 and nothing is billed.",
              "example": "stripe"
            },
            "example": "stripe"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID whose followers are sampled, as an alternative to username. Used as sent, with no lookup.",
            "schema": {
              "type": "string",
              "description": "Numeric ID whose followers are sampled, as an alternative to username. Used as sent, with no lookup.",
              "example": "102812444"
            },
            "example": "102812444"
          },
          {
            "name": "tweet_id",
            "in": "query",
            "required": false,
            "description": "Numeric tweet ID whose retweeters are sampled, instead of a user's followers. Cannot be combined with username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric tweet ID whose retweeters are sampled, instead of a user's followers. Cannot be combined with username or user_id.",
              "example": "1866512345678901234"
            },
            "example": "1866512345678901234"
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Optional confirmation of the audience: followers (with username or user_id) or retweeters (with tweet_id). When sent, it must agree with the identifier, or the request returns a 400.",
            "schema": {
              "type": "string",
              "description": "Optional confirmation of the audience: followers (with username or user_id) or retweeters (with tweet_id). When sent, it must agree with the identifier, or the request returns a 400.",
              "example": "followers"
            },
            "example": "followers"
          },
          {
            "name": "sample",
            "in": "query",
            "required": false,
            "description": "How many distinct accounts to sample, a whole number from 10 to 100. Default 50. Also sets the balance needed up front: sample plus 3 items.",
            "schema": {
              "type": "integer",
              "description": "How many distinct accounts to sample, a whole number from 10 to 100. Default 50. Also sets the balance needed up front: sample plus 3 items.",
              "example": "50"
            },
            "example": "50"
          }
        ]
      }
    },
    "/user/bookmarks": {
      "get": {
        "operationId": "user-bookmarks",
        "summary": "Bookmarks",
        "description": "Fetch the bookmarked tweets for the account behind your registered session, newest first. Each item is a full tweet object with author and engagement counts. Cursor-paginated. Requires a registered session. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/bookmarks?count=20\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/bookmarks\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"count\": 20},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmarks\");\nurl.search = new URLSearchParams({ count: \"20\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/bookmarks?cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/bookmarks\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmarks\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "List your registered account's bookmarked tweets, most recent first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Bookmarked tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "DAACCgAC...",
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "Bookmark this thread on cursor pagination.",
                      "created_at": "Tue Feb 20 14:02:11 +0000 2026",
                      "author": {
                        "id": "745273",
                        "username": "naval",
                        "name": "Naval"
                      },
                      "favorite_count": 4821,
                      "retweet_count": 612,
                      "view_count": 219340
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/bookmark_search": {
      "get": {
        "operationId": "user-bookmark-search",
        "summary": "Bookmark Search",
        "description": "Search the bookmarks of the account behind your registered session by keyword. Matches against bookmarked tweet text and returns full tweet objects. Cursor-paginated. Requires a registered session. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/bookmark_search?query=cursor%20pagination\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/bookmark_search\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"query\": \"cursor pagination\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmark_search\");\nurl.search = new URLSearchParams({ query: \"cursor pagination\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/bookmark_search?query=cursor&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/bookmark_search\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"query\": \"cursor\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { query: \"cursor\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmark_search\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Full-text search within your registered account's bookmarks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Matching bookmarked tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "DAACCgAC...",
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "The empty array is the universal stop signal for cursor pagination.",
                      "created_at": "Tue Feb 20 14:02:11 +0000 2026",
                      "author": {
                        "id": "745273",
                        "username": "naval",
                        "name": "Naval"
                      },
                      "favorite_count": 4821
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "Keyword(s) to match against your bookmarked tweets' text.",
            "schema": {
              "type": "string",
              "description": "Keyword(s) to match against your bookmarked tweets' text.",
              "example": "cursor pagination"
            },
            "example": "cursor pagination"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100."
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/bookmark_folders": {
      "get": {
        "operationId": "user-bookmark-folders",
        "summary": "Bookmark Folders",
        "description": "Fetch the caller's own bookmark folders. Each item carries the folder's id, name, and a cover image X auto-picks from its contents. Requires a registered session. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/bookmark_folders\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/bookmark_folders\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmark_folders\");\nurl.search = new URLSearchParams({}).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List your registered account's bookmark folders.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of folders returned."
                    },
                    "folders": {
                      "type": "array",
                      "description": "The caller's own bookmark folders: id, name, cover_media_url.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "folders": [
                    {
                      "id": "2073826456430592429",
                      "name": "Parasite SEO",
                      "cover_media_url": "https://pbs.twimg.com/media/Ex_fuubVEAA9gcg.png"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/bookmark_folder_timeline": {
      "get": {
        "operationId": "user-bookmark-folder-timeline",
        "summary": "Bookmark Folder Timeline",
        "description": "Fetch the tweets inside one of the caller's own bookmark folders, identified by folder_id (from Bookmark Folders). Cursor-paginated. Requires a registered session. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/bookmark_folder_timeline?folder_id=2073826456430592429\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/bookmark_folder_timeline\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"folder_id\": \"2073826456430592429\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmark_folder_timeline\");\nurl.search = new URLSearchParams({ folder_id: \"2073826456430592429\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/bookmark_folder_timeline?folder_id=2073826456430592429&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/bookmark_folder_timeline\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"folder_id\": \"2073826456430592429\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { folder_id: \"2073826456430592429\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/bookmark_folder_timeline\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Read the tweets inside one of your bookmark folders.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "folder_id": {
                      "type": "string",
                      "description": "Echo of the folder_id you queried."
                    },
                    "tweets": {
                      "type": "array",
                      "description": "Tweets saved inside this folder, for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "folder_id": "2073826456430592429",
                  "count": 1,
                  "next_cursor": "-1783273732069",
                  "tweets": [
                    {
                      "id": "2073438646657564825",
                      "text": "https://t.co/dYukCmrM45",
                      "created_at": "Sat Jul 04 16:07:50 +0000 2026",
                      "author": {
                        "id": "1451118635108478976",
                        "username": "natiakourdadze",
                        "name": "Natia Kurdadze"
                      },
                      "favorite_count": 41,
                      "retweet_count": 5,
                      "view_count": 6332
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "folder_id",
            "in": "query",
            "required": true,
            "description": "The bookmark folder's id, from user/bookmark_folders.",
            "schema": {
              "type": "string",
              "description": "The bookmark folder's id, from user/bookmark_folders.",
              "example": "2073826456430592429"
            },
            "example": "2073826456430592429"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/likes": {
      "get": {
        "operationId": "user-likes",
        "summary": "User Likes",
        "description": "Read the Likes tab of the account named by user_id, read through your registered session, most recent first. Returns full tweet objects, cursor-paginated. Returns an empty list when the account hides its likes. Requires a registered session and a numeric user_id. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/likes?user_id=44196397\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/likes\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"user_id\": \"44196397\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/likes\");\nurl.search = new URLSearchParams({ user_id: \"44196397\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/likes?user_id=44196397&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/likes\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"user_id\": \"44196397\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { user_id: \"44196397\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/likes\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch the tweets a target account has liked (its public Likes tab).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Liked tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "DAACCgAC...",
                  "tweets": [
                    {
                      "id": "1759123456789012345",
                      "text": "A tweet this account liked.",
                      "created_at": "Tue Feb 20 14:02:11 +0000 2026",
                      "author": {
                        "id": "745273",
                        "username": "naval",
                        "name": "Naval"
                      },
                      "favorite_count": 4821
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the account whose likes to read. Resolve a handle with GET /user/info first.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the account whose likes to read. Resolve a handle with GET /user/info first.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100."
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/home_timeline": {
      "get": {
        "operationId": "user-home-timeline",
        "summary": "Home Timeline",
        "description": "Read the home timeline for the account behind your registered session: the ranked feed shown when that account opens X, most recent first. Returns full tweet objects with author and engagement counts. Cursor-paginated. Requires a registered session. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/home_timeline?count=20\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/home_timeline\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"count\": 20},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/home_timeline\");\nurl.search = new URLSearchParams({ count: \"20\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/home_timeline?cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/home_timeline\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/home_timeline\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch your registered account's home timeline (the For You / Following feed).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Timeline tweets for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "DAABCgABHL4VFSR__9oKAAIA...",
                  "tweets": [
                    {
                      "id": "2070410316496678962",
                      "text": "Bitcoin closed the daily candle above the key support.",
                      "created_at": "Fri Jun 26 07:34:20 +0000 2026",
                      "lang": "en",
                      "author": {
                        "id": "3185716686",
                        "username": "AshCrypto",
                        "name": "Ash Crypto",
                        "verified": true,
                        "followers_count": 2168823
                      },
                      "reply_count": 264,
                      "retweet_count": 309,
                      "favorite_count": 1277,
                      "quote_count": 11,
                      "bookmark_count": 24,
                      "view_count": 130944
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/user/blocking": {
      "get": {
        "operationId": "user-blocking",
        "summary": "Blocked Accounts",
        "description": "Return the accounts blocked by the account behind your registered session, as full user objects, cursor-paginated. This reads your OWN block list. There is no user_id parameter because X exposes no way to read another account's blocks, so the endpoint does not pretend to offer one. Requires a registered session or per-call inline credentials. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/blocking?count=20\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/blocking\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"count\": 20},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/blocking\");\nurl.search = new URLSearchParams({ count: \"20\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/blocking?cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.users | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.users[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/blocking\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"users\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/blocking\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.users ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "List the accounts your registered account has blocked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Accounts you have blocked, for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "1353384573435056128|2071116068906074107",
                  "users": [
                    {
                      "id": "1353384573435056128",
                      "username": "cryptorover",
                      "name": "Crypto Rover",
                      "verified": true,
                      "followers_count": 812443,
                      "description": "Daily crypto analysis.",
                      "created_at": "Sun Jan 24 16:50:08 +0000 2021",
                      "profile_image_url": "https://pbs.twimg.com/profile_images/1891433835675475969/J-TloTb6_normal.png"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/muting": {
      "get": {
        "operationId": "user-muting",
        "summary": "Muted Accounts",
        "description": "Return the accounts muted by the account behind your registered session, as full user objects, cursor-paginated. Muting hides someone's posts from your timeline without blocking them, so this list is distinct from GET /user/blocking. This reads your OWN mute list; X exposes no way to read another account's, so there is no user_id parameter. Requires a registered session or per-call inline credentials. Cost: $0.0008 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/muting?count=20\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/muting\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"count\": 20},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/muting\");\nurl.search = new URLSearchParams({ count: \"20\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/muting?cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.users | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.users[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/muting\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"users\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/muting\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.users ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "List the accounts your registered account has muted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Accounts you have muted, for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "1353384573435056128|2071116068906074107",
                  "users": [
                    {
                      "id": "1353384573435056128",
                      "username": "cryptorover",
                      "name": "Crypto Rover",
                      "verified": true,
                      "followers_count": 812443,
                      "description": "Daily crypto analysis.",
                      "created_at": "Sun Jan 24 16:50:08 +0000 2021",
                      "profile_image_url": "https://pbs.twimg.com/profile_images/1891433835675475969/J-TloTb6_normal.png"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/tweets/complete": {
      "get": {
        "operationId": "user-tweets-complete",
        "summary": "Full Tweet History",
        "description": "Collect a user's tweet history in bulk, auto-paginating server-side across upstream pages. Unlike GET /user/tweets (one upstream page per call), this drives pagination for you and returns a large batch in one request. Each call is bounded by both `max` and a server-side time budget, so it always returns inside a normal client timeout. When more history remains the response carries a `next_cursor` — pass it back as `cursor` to continue, and repeat until `next_cursor` is null. A public read: no registered session required. Cost: $0.0024 per call.",
        "tags": [
          "User Reads"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0024,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/tweets/complete?user_id=44196397&max=200\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/tweets/complete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"user_id\": \"44196397\", \"max\": 200},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/tweets/complete\");\nurl.search = new URLSearchParams({ user_id: \"44196397\", max: \"200\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Auto-paginate a large batch of a user's tweet history per call, resuming with a cursor up to Twitter's ~3200 ceiling.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of tweets returned in the flat array."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Non-null means MORE HISTORY REMAINS and this call was truncated (by max, or by the server-side time budget): call again with cursor set to this value. Null means the history is genuinely exhausted. A client that ignores this field will silently receive only part of the history.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when more history remains: this page returned tweets and next_cursor is non-null. False once the history is exhausted. Equivalent to testing next_cursor, provided as a convenience loop-stop flag."
                    },
                    "tweets": {
                      "type": "array",
                      "description": "The collected tweets, newest first. Includes retweets (is_retweet true).",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    }
                  }
                },
                "example": {
                  "count": 201,
                  "next_cursor": "DAAHCgABHNqVL6L__zsLAAIAAAAT",
                  "tweets": [
                    {
                      "id": "2071092912000246106",
                      "text": "RT @XFreeze: xAI models now support Zero Data Retention (ZDR) on OpenRouter",
                      "created_at": "Sun Jun 28 04:46:43 +0000 2026",
                      "lang": "en",
                      "is_retweet": true,
                      "is_quote": false,
                      "author": {
                        "id": "44196397",
                        "username": "elonmusk",
                        "name": "Elon Musk",
                        "verified": true,
                        "followers_count": 240574388
                      },
                      "retweet_count": 208,
                      "view_count": 599857
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the target account. Resolve a handle with GET /user/info first.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the target account. Resolve a handle with GET /user/info first.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "max",
            "in": "query",
            "required": false,
            "description": "Target number of tweets to collect in this call. Defaults to 200. This is a MINIMUM target, not a hard cap: pages arrive in whole chunks, so a response may contain up to one page (<=100) more than requested. Twitter's ~3200-per-user history ceiling still applies overall.",
            "schema": {
              "type": "integer",
              "description": "Target number of tweets to collect in this call. Defaults to 200. This is a MINIMUM target, not a hard cap: pages arrive in whole chunks, so a response may contain up to one page (<=100) more than requested. Twitter's ~3200-per-user history ceiling still applies overall.",
              "example": "200"
            },
            "example": "200"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Resume point from a previous response's next_cursor. Omit on the first call. Pass it back to continue collecting where the last call stopped.",
            "schema": {
              "type": "string",
              "description": "Resume point from a previous response's next_cursor. Omit on the first call. Pass it back to continue collecting where the last call stopped.",
              "example": "DAAHCgABHNqVL6L__zs"
            },
            "example": "DAAHCgABHNqVL6L__zs"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/dm/send": {
      "post": {
        "operationId": "dm-send",
        "summary": "Send DM",
        "description": "Send a direct message to a user as the authenticated account. Requires a logged-in session for the acting account. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Direct Messages"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/dm/send\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{recipient_id=44196397&text=Hello%20from%20the%20TwitterAPIs%20DM%20API}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/dm/send\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"recipient_id\": \"44196397\", \"text\": \"Hello from the TwitterAPIs DM API\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/dm/send\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ recipient_id: \"44196397\", text: \"Hello from the TwitterAPIs DM API\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Send a direct message from your authenticated account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the message was sent."
                    },
                    "message_id": {
                      "type": "string",
                      "description": "ID of the sent message, or null if it failed.",
                      "nullable": true
                    },
                    "conversation_id": {
                      "type": "string",
                      "description": "ID of the conversation the message landed in, or null if the upstream response did not include it.",
                      "nullable": true
                    },
                    "recipient_id": {
                      "type": "string",
                      "description": "The recipient's numeric user ID."
                    },
                    "text": {
                      "type": "string",
                      "description": "The message body that was sent."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "message_id": "1899999999999999999",
                  "conversation_id": "44196397-11348282",
                  "recipient_id": "44196397",
                  "text": "Hello from the TwitterAPIs DM API"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "recipient_id": {
                    "type": "string",
                    "description": "Numeric Twitter user ID of the recipient.",
                    "example": "44196397"
                  },
                  "text": {
                    "type": "string",
                    "description": "The message body. Also accepted in a JSON request body.",
                    "example": "Hello from the TwitterAPIs DM API"
                  }
                },
                "required": [
                  "recipient_id",
                  "text"
                ]
              }
            }
          }
        }
      }
    },
    "/dm/list": {
      "get": {
        "operationId": "dm-list",
        "summary": "DM Inbox",
        "description": "List the DM conversations (inbox) for the account behind your session. Returns each conversation's ID, type, and participant user IDs. Pass a conversation_id to GET /dm/conversation to read its messages. Authenticate with a registered session (POST /customer/session) or per-call x-auth-token and x-ct0 headers, so one API key can poll the inboxes of many accounts. Read-only: this does not send DMs. It reads X's standard DM inbox, so conversations X has moved to end-to-end encrypted chat may not appear, and conversations still in the message-requests folder may be missing. Cost: $0.0016 per call.",
        "tags": [
          "Direct Messages"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/dm/list\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/dm/list\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/dm/list\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List the Direct Message conversations for your registered account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of conversations returned."
                    },
                    "conversations": {
                      "type": "array",
                      "description": "Conversation entries, each with conversation_id, type (for example ONE_TO_ONE or GROUP_DM, may be null), and participants (numeric user-ID strings).",
                      "items": {
                        "$ref": "#/components/schemas/DMConversation"
                      }
                    },
                    "inbox_timelines": {
                      "type": "object",
                      "description": "Per-timeline pagination metadata keyed by timeline name (for example trusted and untrusted), each an object with status (X's timeline status string, may be null) and cursor (the pagination cursor for that timeline, may be null). May be an empty object.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "count": 2,
                  "conversations": [
                    {
                      "conversation_id": "1749154312754794496-1972455697997824000",
                      "type": "ONE_TO_ONE",
                      "participants": [
                        "1749154312754794496",
                        "1972455697997824000"
                      ]
                    },
                    {
                      "conversation_id": "1796873533852692480-1972455697997824000",
                      "type": "ONE_TO_ONE",
                      "participants": [
                        "1796873533852692480",
                        "1972455697997824000"
                      ]
                    }
                  ],
                  "inbox_timelines": {
                    "trusted": {
                      "status": "HAS_MORE",
                      "cursor": "GRwmkMDXkuGjpbUXFoCAwMDX"
                    },
                    "untrusted": {
                      "status": "AT_END",
                      "cursor": null
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/dm/conversation": {
      "get": {
        "operationId": "dm-conversation",
        "summary": "DM Conversation",
        "description": "Fetch the messages inside a single DM conversation. Pass a conversation_id from GET /dm/list. Each message carries its ID, sender ID, timestamp, and text. Authenticate with a registered session (POST /customer/session) or per-call x-auth-token and x-ct0 headers. Read-only: this does not send DMs. Cost: $0.0016 per call.",
        "tags": [
          "Direct Messages"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/dm/conversation?conversation_id=1749154312754794496-1972455697997824000\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/dm/conversation\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"conversation_id\": \"1749154312754794496-1972455697997824000\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/dm/conversation\");\nurl.search = new URLSearchParams({ conversation_id: \"1749154312754794496-1972455697997824000\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read the message history of one DM conversation by conversation_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "conversation_id": {
                      "type": "string",
                      "description": "Echo of the conversation_id you requested."
                    },
                    "min_entry_id": {
                      "type": "string",
                      "description": "Oldest entry id on this page. Pass it as max_id to fetch the next older page; null when X sent no entries.",
                      "nullable": true
                    },
                    "max_entry_id": {
                      "type": "string",
                      "description": "Newest entry id on this page; null when X sent no entries.",
                      "nullable": true
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of messages returned."
                    },
                    "messages": {
                      "type": "array",
                      "description": "Messages, each with id, time (epoch milliseconds as a string, or null), sender_id (numeric user-ID string, or null), and text.",
                      "items": {
                        "$ref": "#/components/schemas/DMMessage"
                      }
                    }
                  }
                },
                "example": {
                  "conversation_id": "1749154312754794496-1972455697997824000",
                  "min_entry_id": "1972455697997824000",
                  "max_entry_id": "1972455842140631040",
                  "count": 1,
                  "messages": [
                    {
                      "id": "1988752174906749349",
                      "time": "1762990442000",
                      "sender_id": "1972455697997824000",
                      "text": "This isnt my main, chat to me here @baywilliams_12"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "conversation_id",
            "in": "query",
            "required": true,
            "description": "Conversation ID from a GET /dm/list entry.",
            "schema": {
              "type": "string",
              "description": "Conversation ID from a GET /dm/list entry.",
              "example": "1749154312754794496-1972455697997824000"
            },
            "example": "1749154312754794496-1972455697997824000"
          },
          {
            "name": "max_id",
            "in": "query",
            "required": false,
            "description": "Page backwards: return entries older than this entry id. Pass the previous page's min_entry_id to walk a thread back in time; omit for the newest page. Must be a numeric entry id; any other value returns 400.",
            "schema": {
              "type": "string",
              "description": "Page backwards: return entries older than this entry id. Pass the previous page's min_entry_id to walk a thread back in time; omit for the newest page. Must be a numeric entry id; any other value returns 400.",
              "example": "1972455697997824000"
            },
            "example": "1972455697997824000"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/followers_you_know": {
      "get": {
        "operationId": "user-followers-you-know",
        "summary": "Followers You Know",
        "description": "Return the followers of the account named by user_id that the account behind your registered session also follows: the mutual-connection overlap from your perspective. Returns full user objects, cursor-paginated. Requires a registered session and a numeric user_id. Cost: $0.0008 per call.",
        "tags": [
          "Follower Graph"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/followers_you_know?user_id=44196397\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/followers_you_know\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"user_id\": \"44196397\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/followers_you_know\");\nurl.search = new URLSearchParams({ user_id: \"44196397\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/followers_you_know?user_id=44196397&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.users | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.users[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/followers_you_know\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"user_id\": \"44196397\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"users\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { user_id: \"44196397\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/followers_you_know\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.users ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "The followers of a target account that your registered account also follows (mutual overlap).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Overlap accounts (followers of the target that you also follow) for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": "1353384573435056128|2071116068906074107",
                  "users": [
                    {
                      "id": "1353384573435056128",
                      "username": "cryptorover",
                      "name": "Crypto Rover",
                      "description": "#Bitcoin Crypto YouTuber",
                      "followers_count": 1596989,
                      "following_count": 555,
                      "verified": true,
                      "tweet_count": 70185,
                      "location": "Bitcoin",
                      "created_at": "Sun Jan 24 16:50:08 +0000 2021",
                      "profile_image_url": "https://pbs.twimg.com/profile_images/1891433835675475969/J-TloTb6_normal.png"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the target account to compute shared followers against.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the target account to compute shared followers against.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; documented cap 100. NOTE: X returns this list in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint, not an exact limit; paginate with the cursor for more.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; documented cap 100. NOTE: X returns this list in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint, not an exact limit; paginate with the cursor for more."
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/followers": {
      "get": {
        "operationId": "user-followers",
        "summary": "User Followers",
        "description": "Fetch a user's followers, cursor-paginated. Returns full user objects. For large accounts, page with next_cursor until the users array comes back empty (the follower graph keeps returning a non-null cursor even on the final page). Cost: $0.0008 per call.",
        "tags": [
          "Follower Graph"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/followers?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/followers\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/followers\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/user/followers?username=naval&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.users | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.users[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/user/followers\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"username\": \"naval\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"users\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { username: \"naval\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/user/followers\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.users ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through the accounts that follow a user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Follower user objects for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "9921",
                      "username": "devjane",
                      "name": "Jane",
                      "followers_count": 4200,
                      "verified": false
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/following": {
      "get": {
        "operationId": "user-following",
        "summary": "User Following",
        "description": "Fetch the accounts a user follows, cursor-paginated. Returns full user objects. Page with next_cursor until the users array comes back empty (the follower graph keeps returning a non-null cursor even on the final page). Cost: $0.0008 per call.",
        "tags": [
          "Follower Graph"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/following?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/following\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/following\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through the accounts a user follows.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Followed user objects for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "2178758961",
                      "username": "balajis",
                      "name": "Balaji",
                      "followers_count": 1000000,
                      "verified": true
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/followers_v2": {
      "get": {
        "operationId": "user-followers-v2",
        "summary": "User Followers (v2)",
        "description": "The v2 variant of the followers endpoint. Same data, with a more consistent cursor model and additional user fields. Prefer v2 for new integrations. Cost: $0.0008 per call.",
        "tags": [
          "Follower Graph"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/followers_v2?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/followers_v2\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/followers_v2\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Followers endpoint with the v2 response shape and richer cursoring.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Follower user objects (v2 shape) for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "9921",
                      "username": "devjane",
                      "name": "Jane",
                      "followers_count": 4200,
                      "verified": false,
                      "created_at": "Wed Jan 04 09:11:00 +0000 2023"
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/following_v2": {
      "get": {
        "operationId": "user-following-v2",
        "summary": "User Following (v2)",
        "description": "The v2 variant of the following endpoint. Same data as the v1 following call, with a more consistent cursor model and additional user fields. Prefer v2 for new integrations. Cost: $0.0008 per call.",
        "tags": [
          "Follower Graph"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/following_v2?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/following_v2\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/following_v2\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Following endpoint with the v2 response shape and richer cursoring.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Followed user objects (v2 shape) for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "2178758961",
                      "username": "balajis",
                      "name": "Balaji",
                      "followers_count": 1000000,
                      "verified": true,
                      "created_at": "Fri Nov 08 04:22:10 +0000 2013"
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; documented range 1-100. NOTE: on follower/following lists X returns pages in fixed chunks, so a small count may still return up to a full page (~100). Treat count as an upper-bound hint here, not an exact limit; paginate with the cursor for more.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/user/verified_followers": {
      "get": {
        "operationId": "user-verified-followers",
        "summary": "Verified Followers",
        "description": "Fetch only the Verified (Blue) accounts that follow a user, cursor-paginated. A fast way to filter a large follower base down to higher-signal accounts. Cost: $0.0008 per call.",
        "tags": [
          "Follower Graph"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/user/verified_followers?username=naval\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/user/verified_followers\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"username\": \"naval\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/verified_followers\");\nurl.search = new URLSearchParams({ username: \"naval\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through only the verified accounts that follow a user.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Verified follower user objects for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "2178758961",
                      "username": "balajis",
                      "name": "Balaji",
                      "verified": true,
                      "followers_count": 1000000
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "query",
            "required": true,
            "description": "Handle without the leading @.",
            "schema": {
              "type": "string",
              "description": "Handle without the leading @.",
              "example": "naval"
            },
            "example": "naval"
          },
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric user ID; provide either username or user_id.",
            "schema": {
              "type": "string",
              "description": "Numeric user ID; provide either username or user_id.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/list/members": {
      "get": {
        "operationId": "list-members",
        "summary": "List Members",
        "description": "Fetch the members of a public List by its numeric ID, cursor-paginated. Returns full user objects for every account in the List. Cost: $0.0008 per call.",
        "tags": [
          "List Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/list/members?list_id=1234567890123456789\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/list/members\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"list_id\": \"1234567890123456789\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/list/members\");\nurl.search = new URLSearchParams({ list_id: \"1234567890123456789\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through the members of a public Twitter/X List.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "List member user objects for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "745273",
                      "username": "naval",
                      "name": "Naval",
                      "verified": true
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "list_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the public List.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the public List.",
              "example": "1234567890123456789"
            },
            "example": "1234567890123456789"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/list/followers": {
      "get": {
        "operationId": "list-followers",
        "summary": "List Followers",
        "description": "Fetch a public List's followers by its numeric ID, cursor-paginated. Followers and members are different sets of people: members are the accounts the List owner added to it, followers are the accounts that subscribed to read it. A List with hundreds of members commonly has only a handful of followers, so a small count here is normal and is not a truncated page. next_cursor is null once X marks the roster complete. Cost: $0.0008 per call.",
        "tags": [
          "List Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/list/followers?list_id=1234567890123456789\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/list/followers\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"list_id\": \"1234567890123456789\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/list/followers\");\nurl.search = new URLSearchParams({ list_id: \"1234567890123456789\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through the accounts that follow a public Twitter/X List.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "description": "Follower user objects for this page.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "users": [
                    {
                      "id": "745273",
                      "username": "naval",
                      "name": "Naval",
                      "verified": true
                    }
                  ],
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "list_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the public List.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the public List.",
              "example": "1234567890123456789"
            },
            "example": "1234567890123456789"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/list/tweets": {
      "get": {
        "operationId": "list-tweets",
        "summary": "List Tweets",
        "description": "Fetch posts written by the members of a public List through X's search index. Supports since and until date bounds and an include_replies toggle. Does not include retweets. Cost: $0.0008 per call.",
        "tags": [
          "List Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/list/tweets?list_id=1234567890123456789&since=2026-08-01\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/list/tweets\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"list_id\": \"1234567890123456789\", \"since\": \"2026-08-01\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/list/tweets\");\nurl.search = new URLSearchParams({ list_id: \"1234567890123456789\", since: \"2026-08-01\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read a public List's posts, filterable by date range and replies.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Posts from this List's members for this page, newest first.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    },
                    "incomplete": {
                      "type": "boolean",
                      "description": "Present and true only when X soft-limited the search that served this page, so the page may be missing rows. Absent on every healthy page."
                    },
                    "incomplete_reason": {
                      "type": "string",
                      "description": "Why the page is incomplete: upstream_soft_limit. Present only with incomplete."
                    },
                    "upstream_limit": {
                      "type": "object",
                      "description": "X's own limit signal for this page (its error codes and message). Present only with incomplete.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1899887766554433221",
                      "text": "Shipping the thing we said we would ship.",
                      "created_at": "2026-08-14T09:12:44.000Z",
                      "author": {
                        "id": "745273",
                        "username": "naval"
                      }
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "list_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the public List.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the public List.",
              "example": "1234567890123456789"
            },
            "example": "1234567890123456789"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Only posts on or after this date, as YYYY-MM-DD.",
            "schema": {
              "type": "string",
              "description": "Only posts on or after this date, as YYYY-MM-DD.",
              "example": "2026-08-01"
            },
            "example": "2026-08-01"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Only posts before this date, as YYYY-MM-DD. Exclusive, matching X's until: operator.",
            "schema": {
              "type": "string",
              "description": "Only posts before this date, as YYYY-MM-DD. Exclusive, matching X's until: operator.",
              "example": "2026-08-15"
            },
            "example": "2026-08-15"
          },
          {
            "name": "include_replies",
            "in": "query",
            "required": false,
            "description": "Whether to include replies written by List members. Default true.",
            "schema": {
              "type": "boolean",
              "description": "Whether to include replies written by List members. Default true.",
              "example": "false"
            },
            "example": "false"
          },
          {
            "name": "product",
            "in": "query",
            "required": false,
            "description": "Which search ranking to read: Latest or Top. Default Latest, and any unrecognised value falls back to Latest.",
            "schema": {
              "type": "string",
              "description": "Which search ranking to read: Latest or Top. Default Latest, and any unrecognised value falls back to Latest.",
              "example": "Top"
            },
            "example": "Top"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/list/timeline": {
      "get": {
        "operationId": "list-timeline",
        "summary": "List Timeline",
        "description": "Fetch a public List's feed as X itself serves it, using the native List timeline. Includes members' retweets and X's own ordering. Paged only, with no date or reply filters. Cost: $0.0008 per call.",
        "tags": [
          "List Data"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/list/timeline?list_id=1234567890123456789\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/list/timeline\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"list_id\": \"1234567890123456789\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/list/timeline\");\nurl.search = new URLSearchParams({ list_id: \"1234567890123456789\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read a public List's native X timeline, retweets included.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tweets": {
                      "type": "array",
                      "description": "Posts from X's native List timeline for this page.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when another page is available: this page returned items and carried a usable next_cursor. False on the final page. Follower-graph endpoints keep sending a non-null next_cursor past the end, but has_more still flips to false once the item array comes back empty, so it is the reliable loop-stop signal."
                    }
                  }
                },
                "example": {
                  "tweets": [
                    {
                      "id": "1899887766554433222",
                      "text": "Reposting this because it deserves a second look.",
                      "created_at": "2026-08-14T10:03:19.000Z",
                      "author": {
                        "id": "745273",
                        "username": "naval"
                      }
                    }
                  ],
                  "next_cursor": "DAABCgABF..."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "list_id",
            "in": "query",
            "required": true,
            "description": "Numeric ID of the public List.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the public List.",
              "example": "1234567890123456789"
            },
            "example": "1234567890123456789"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Max items to return for this page. Default 20; clamped to 1-100.",
            "schema": {
              "type": "integer",
              "description": "Max items to return for this page. Default 20; clamped to 1-100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/trends": {
      "get": {
        "operationId": "trends",
        "summary": "Trends",
        "description": "Fetch the current top trends for one location. Ask for it by country name, ISO code, or numeric WOEID; with no location parameter you get Worldwide. X returns roughly 50 trends per location, ranked. Pass category instead: trending, news, sports, entertainment or for_you reads that X Explore tab, and business_and_finance keeps only the ranked trends X labels Business and finance on its Trending and News tabs. Cost: $0.0008 per call.",
        "tags": [
          "Trends"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/trends?country=US\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/trends\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"country\": \"US\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/trends\");\nurl.search = new URLSearchParams({ country: \"US\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Read an Explore tab",
            "source": "curl \"https://api.twitterapis.com/twitter/trends?category=news\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python: Read an Explore tab",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/trends\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"category\": \"news\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Read an Explore tab",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/trends\");\nurl.search = new URLSearchParams({ category: \"news\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read the current trending topics for a location, an Explore tab or a trend label.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "category": {
                      "type": "string",
                      "description": "The category you asked for, lowercased: trending, news, sports, entertainment, for_you or business_and_finance. Present only when the call sent category; a location call has no category key."
                    },
                    "location": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/TrendServedLocation"
                        }
                      ],
                      "description": "The location X actually served, as { name, woeid }, echoed back so you know what you got. Null on a category call.",
                      "nullable": true
                    },
                    "as_of": {
                      "type": "string",
                      "description": "ISO 8601 timestamp of when X computed this trend list."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp X reports for the trend window. Null on a category call, where X reports no trend window.",
                      "nullable": true
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of trends in this response, after any count truncation."
                    },
                    "trends": {
                      "type": "array",
                      "description": "Ranked trend objects: name, url, query, promoted_content, tweet_volume, is_hashtag, rank, meta_description. On a category call each also carries is_ai_story. On an Explore tab story items follow the ranked trends; business_and_finance returns ranked trends only, re-ranked from 1.",
                      "items": {
                        "$ref": "#/components/schemas/Trend"
                      }
                    }
                  }
                },
                "example": {
                  "location": {
                    "name": "United States",
                    "woeid": 23424977
                  },
                  "as_of": "2026-07-20T06:15:13Z",
                  "created_at": "2026-07-18T15:25:54Z",
                  "count": 2,
                  "trends": [
                    {
                      "name": "Spain",
                      "url": "http://twitter.com/search?q=Spain",
                      "query": "Spain",
                      "promoted_content": null,
                      "tweet_volume": null,
                      "is_hashtag": false,
                      "rank": 1
                    },
                    {
                      "name": "#HOTD",
                      "url": "http://twitter.com/search?q=%23HOTD",
                      "query": "%23HOTD",
                      "promoted_content": null,
                      "tweet_volume": null,
                      "is_hashtag": true,
                      "rank": 2
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Country name or ISO code, e.g. \"US\" or \"Japan\". Resolved against the trends locations list, country-level entries only.",
            "schema": {
              "type": "string",
              "description": "Country name or ISO code, e.g. \"US\" or \"Japan\". Resolved against the trends locations list, country-level entries only.",
              "example": "US"
            },
            "example": "US"
          },
          {
            "name": "woeid",
            "in": "query",
            "required": false,
            "description": "Numeric WOEID from /twitter/trends/locations. Takes precedence over country when both are sent.",
            "schema": {
              "type": "integer",
              "description": "Numeric WOEID from /twitter/trends/locations. Takes precedence over country when both are sent.",
              "example": "23424977"
            },
            "example": "23424977"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Read a category instead of a location. trending, news, sports, entertainment and for_you each read that X Explore tab. business_and_finance is not a tab but a filter: it reads the Trending and News tabs and keeps only the ranked trends X labels \"Business and finance\", with no story items. Case-insensitive. Results reflect the Explore view of the X account the API reads with, not yours. Cannot be combined with country or woeid (400 bad_request). An unknown value returns 400 bad_request, and the message lists the six values.",
            "schema": {
              "type": "string",
              "description": "Read a category instead of a location. trending, news, sports, entertainment and for_you each read that X Explore tab. business_and_finance is not a tab but a filter: it reads the Trending and News tabs and keeps only the ranked trends X labels \"Business and finance\", with no story items. Case-insensitive. Results reflect the Explore view of the X account the API reads with, not yours. Cannot be combined with country or woeid (400 bad_request). An unknown value returns 400 bad_request, and the message lists the six values.",
              "example": "news"
            },
            "example": "news"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Truncate the returned list to this many trends. X has no count of its own; it always returns its full set (about 50 for a location).",
            "schema": {
              "type": "integer",
              "description": "Truncate the returned list to this many trends. X has no count of its own; it always returns its full set (about 50 for a location).",
              "example": "10"
            },
            "example": "10"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/trends/locations": {
      "get": {
        "operationId": "trends-locations",
        "summary": "Trend Locations",
        "description": "Fetch the full set of locations X serves trends for, each with the WOEID to pass back to the Trends endpoint. Takes no parameters and returns the complete list. Cost: $0.0008 per call.",
        "tags": [
          "Trends"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/trends/locations\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/trends/locations\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/trends/locations\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List every location Twitter/X has trends available for.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of locations returned."
                    },
                    "locations": {
                      "type": "array",
                      "description": "Location objects: name, woeid, country, country_code, parentid, place_type, url. The deprecated camelCase countryCode/placeType are still returned alongside for a migration window; prefer the snake_case country_code/place_type.",
                      "items": {
                        "$ref": "#/components/schemas/TrendLocation"
                      }
                    }
                  }
                },
                "example": {
                  "count": 467,
                  "locations": [
                    {
                      "name": "Worldwide",
                      "woeid": 1,
                      "country": "",
                      "country_code": null,
                      "countryCode": null,
                      "parentid": 0,
                      "place_type": {
                        "code": 19,
                        "name": "Supername"
                      },
                      "placeType": {
                        "code": 19,
                        "name": "Supername"
                      },
                      "url": "http://where.yahooapis.com/v1/place/1"
                    },
                    {
                      "name": "United States",
                      "woeid": 23424977,
                      "country": "United States",
                      "country_code": "US",
                      "countryCode": "US",
                      "parentid": 1,
                      "place_type": {
                        "code": 12,
                        "name": "Country"
                      },
                      "placeType": {
                        "code": 12,
                        "name": "Country"
                      },
                      "url": "http://where.yahooapis.com/v1/place/23424977"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/spaces/info": {
      "get": {
        "operationId": "spaces-info",
        "summary": "Space Info",
        "description": "Look up a single X Space by its id and get back its title, lifecycle state, host, topics, timing, audience counts and its admin, speaker and listener roster. Works for a Space that is scheduled, running or already ended. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Spaces"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/spaces/info?id=1RKZzjkoYRAKB\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/spaces/info\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1RKZzjkoYRAKB\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/spaces/info\");\nurl.search = new URLSearchParams({ id: \"1RKZzjkoYRAKB\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata and participant roster for one X Space, live or ended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "space": {
                      "type": "object",
                      "description": "The Space, or null with a 404 when the id resolves to nothing.",
                      "additionalProperties": true,
                      "nullable": true,
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "The Space id, echoed back."
                        },
                        "title": {
                          "type": "string",
                          "description": "The Space title as set by the host."
                        },
                        "state": {
                          "type": "string",
                          "description": "X's lifecycle value: Scheduled, NotStarted, Running or Ended."
                        },
                        "content_type": {
                          "type": "string",
                          "description": "audio for an audio-only Space, visual_audio when the host enabled video."
                        },
                        "media_key": {
                          "type": "string",
                          "description": "X's internal media key for the Space recording."
                        },
                        "created_at": {
                          "type": "number",
                          "description": "Millisecond epoch. Every timestamp on this object is a number, including ended_at, which X itself sends as a string."
                        },
                        "scheduled_start": {
                          "type": "number",
                          "description": "Millisecond epoch the host scheduled the Space to begin. 0 when absent."
                        },
                        "started_at": {
                          "type": "number",
                          "description": "Millisecond epoch the Space actually began. 0 when it has not started."
                        },
                        "ended_at": {
                          "type": "number",
                          "description": "Millisecond epoch the Space ended. 0 while it is still running."
                        },
                        "total_live_listeners": {
                          "type": "number",
                          "description": "Peak concurrent listeners while the Space was live."
                        },
                        "total_replay_watched": {
                          "type": "number",
                          "description": "Cumulative replay views after the Space ended."
                        },
                        "is_space_available_for_replay": {
                          "type": "boolean",
                          "description": "Whether a replay is available."
                        },
                        "is_space_available_for_clipping": {
                          "type": "boolean",
                          "description": "Whether clipping is permitted."
                        },
                        "topics": {
                          "type": "array",
                          "description": "Topics the host tagged, each { topic_id, name }.",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        },
                        "creator": {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/User"
                            }
                          ],
                          "description": "The host's full user profile."
                        },
                        "tweet": {
                          "allOf": [
                            {
                              "$ref": "#/components/schemas/Tweet"
                            }
                          ],
                          "description": "The wrapper tweet X mints so the Space can be shared, or null.",
                          "nullable": true
                        },
                        "community_id": {
                          "type": "string",
                          "description": "Set when the Space is hosted inside a Community, otherwise null.",
                          "nullable": true
                        },
                        "mentioned_user_ids": {
                          "type": "array",
                          "description": "User ids X lists as mentioned by the Space. Ids only, not profiles.",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        },
                        "admins": {
                          "type": "array",
                          "description": "Hosts and co-hosts, each { user_id, screen_name, display_name, avatar_url, periscope_user_id, is_verified, is_muted_by_admin, is_muted_by_guest, community_role, start }.",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        },
                        "speakers": {
                          "type": "array",
                          "description": "Speakers, same shape as admins.",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        },
                        "listeners": {
                          "type": "array",
                          "description": "Listeners, same shape as admins. Empty for an ended Space: X drops this roster once a Space finishes, while the audience counts above survive.",
                          "items": {
                            "type": "object",
                            "additionalProperties": true
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "space": {
                    "id": "1RKZzjkoYRAKB",
                    "title": "TIME TO BUILD!",
                    "state": "Ended",
                    "content_type": "visual_audio",
                    "media_key": "28_2042268179733643265",
                    "created_at": 1775749652198,
                    "scheduled_start": 1775840400000,
                    "started_at": 1775840398722,
                    "ended_at": 1775842790853,
                    "updated_at": 1775842791870,
                    "total_live_listeners": 264,
                    "total_replay_watched": 6290,
                    "is_space_available_for_replay": true,
                    "is_space_available_for_clipping": true,
                    "is_locked": false,
                    "is_muted": false,
                    "is_employee_only": false,
                    "no_incognito": false,
                    "disallow_join": false,
                    "is_subscribed": false,
                    "max_admin_capacity": 3,
                    "max_guest_sessions": 10,
                    "narrow_cast_space_type": 0,
                    "conversation_controls": 0,
                    "topics": [
                      {
                        "topic_id": "848920371311001600",
                        "name": "Technology"
                      },
                      {
                        "topic_id": "857879302733418496",
                        "name": "Entrepreneurship"
                      }
                    ],
                    "creator": {
                      "id": "825531272621654016",
                      "username": "TheBestOfAdam",
                      "name": "Adam Soccolich"
                    },
                    "tweet": {
                      "id": "2042648800989233184",
                      "text": "https://t.co/TARX17sERY"
                    },
                    "community_id": "1471580197908586507",
                    "mentioned_user_ids": [
                      "1254214946751049729"
                    ],
                    "admins": [
                      {
                        "user_id": "825531272621654016",
                        "screen_name": "TheBestOfAdam",
                        "display_name": "Adam Soccolich",
                        "avatar_url": "https://pbs.twimg.com/profile_images/...",
                        "periscope_user_id": "1WLERGNWdqRQb",
                        "is_verified": true,
                        "is_muted_by_admin": false,
                        "is_muted_by_guest": false,
                        "community_role": "Moderator",
                        "start": 1775840398860
                      }
                    ],
                    "speakers": [],
                    "listeners": []
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "The Space id, the trailing token in a x.com/i/spaces/<id> URL. 5-32 alphanumeric characters.",
            "schema": {
              "type": "string",
              "description": "The Space id, the trailing token in a x.com/i/spaces/<id> URL. 5-32 alphanumeric characters.",
              "example": "1RKZzjkoYRAKB"
            },
            "example": "1RKZzjkoYRAKB"
          },
          {
            "name": "with_listeners",
            "in": "query",
            "required": false,
            "description": "Include the listener roster. Defaults to true. X does not retain this roster after a Space ends, so it comes back empty for an ended Space regardless of this flag.",
            "schema": {
              "type": "boolean",
              "description": "Include the listener roster. Defaults to true. X does not retain this roster after a Space ends, so it comes back empty for an ended Space regardless of this flag.",
              "example": "true"
            },
            "example": "true"
          },
          {
            "name": "with_replays",
            "in": "query",
            "required": false,
            "description": "Include replay availability and related metadata. Defaults to true.",
            "schema": {
              "type": "boolean",
              "description": "Include replay availability and related metadata. Defaults to true.",
              "example": "true"
            },
            "example": "true"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/community/info": {
      "get": {
        "operationId": "community-info",
        "summary": "Community Info",
        "description": "Look up a single X Community by its numeric id and get back its name, description, member count, join policy, primary topic, posted rules and both banners. This endpoint returns the REDUCED form of the Community object: eight of its 24 fields come back empty here and are populated by Community Memberships instead, which the response table marks field by field. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/info?community_id=1493446837214187523\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/info\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"community_id\": \"1493446837214187523\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/info\");\nurl.search = new URLSearchParams({ community_id: \"1493446837214187523\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata, rules and banners for one X Community.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "community": {
                      "allOf": [
                        {
                          "$ref": "#/components/schemas/Community"
                        }
                      ],
                      "description": "The community, or null with a 404 when the id resolves to nothing. This is the shared Community object, and this endpoint returns the REDUCED form of it: admin, invites_policy, question, search_tags and members_facepile_ids come back empty here, moderator_count comes back 0, and creator comes back with id and name null. Community Memberships returns the same 24 keys populated. Each field's own row says which endpoint fills it.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "community": {
                    "id": "1828843041869713562",
                    "name": "Build In Public - SaaS",
                    "description": "Founders shipping in the open.",
                    "created_at": 1724865134102,
                    "member_count": 392,
                    "moderator_count": 0,
                    "join_policy": "RestrictedJoinRequestsRequireModeratorApproval",
                    "invites_policy": null,
                    "is_nsfw": false,
                    "question": null,
                    "primary_topic": {
                      "topic_id": null,
                      "name": "Software"
                    },
                    "search_tags": [],
                    "rules": [
                      {
                        "id": "1828843041869713570",
                        "name": "Be useful, not promotional",
                        "description": "Ship updates and ask real questions. Link drops with no context get removed."
                      },
                      {
                        "id": "1828843041869713571",
                        "name": "No paid promotion",
                        "description": null
                      }
                    ],
                    "banner_url": "https://pbs.twimg.com/community_banner_img/...",
                    "custom_banner": {
                      "url": "https://pbs.twimg.com/community_banner_img/...",
                      "width": 1500,
                      "height": 500
                    },
                    "default_banner": {
                      "url": "https://pbs.twimg.com/semantic_core_img/...",
                      "width": 1500,
                      "height": 500
                    },
                    "permalink": null,
                    "admin": null,
                    "creator": {
                      "id": null,
                      "username": "pizzaboy",
                      "name": null,
                      "verified": false,
                      "is_blue_verified": true
                    },
                    "members_facepile_ids": [],
                    "role": null,
                    "can_join": null,
                    "is_pinned": null,
                    "viewer_relationship_type": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "community_id",
            "in": "query",
            "required": true,
            "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL. Digits only, no leading zero.",
            "schema": {
              "type": "string",
              "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL. Digits only, no leading zero.",
              "example": "1493446837214187523"
            },
            "example": "1493446837214187523"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/community/members": {
      "get": {
        "operationId": "community-members",
        "summary": "Community Members",
        "description": "Fetch the member roster of an X Community, cursor-paginated, with each row carrying that member's own role in the community: Admin, Moderator or Member. Admins and moderators appear in this list alongside ordinary members and are not grouped, so do not derive a moderator list by filtering the first page. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/members?community_id=1493446837214187523\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/members\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"community_id\": \"1493446837214187523\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/members\");\nurl.search = new URLSearchParams({ community_id: \"1493446837214187523\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/community/members?community_id=1493446837214187523&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.members | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.members[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/community/members\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"community_id\": \"1493446837214187523\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"members\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { community_id: \"1493446837214187523\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/community/members\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.members ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through a community's member roster, each row carrying that member's role.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "description": "Roster rows for this page, each { user, role }.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "user": {
                            "type": "object",
                            "description": "A REDUCED user profile: id, username, name, profile_image_url, is_blue_verified, verified, is_protected. It is smaller than the object User Info returns, on purpose, because X's roster operation sends no bio, no follower or following counts, no location, no website and no created_at. Those keys are ABSENT rather than null, so you can never mistake not-asked-for for zero.",
                            "additionalProperties": true,
                            "properties": {
                              "id": {
                                "type": "string",
                                "description": "Numeric user id as a string."
                              },
                              "username": {
                                "type": "string",
                                "description": "Handle without the leading @."
                              },
                              "name": {
                                "type": "string",
                                "description": "Display name."
                              },
                              "profile_image_url": {
                                "type": "string",
                                "description": "Avatar URL. X sends the _normal size on this operation and it is passed through unchanged rather than rewritten to a larger variant that X did not send."
                              },
                              "is_blue_verified": {
                                "type": "boolean",
                                "description": "Blue (paid) verification."
                              },
                              "verified": {
                                "type": "boolean",
                                "description": "Legacy (official or notable) verification. A different thing from is_blue_verified; never conflate them."
                              },
                              "is_protected": {
                                "type": "boolean",
                                "description": "Whether the account is protected (locked)."
                              }
                            }
                          },
                          "role": {
                            "type": "string",
                            "description": "THAT MEMBER's role in this community: Admin, Moderator or Member. This one is NOT caller-relative, unlike the role field on the community object itself, and it is the reason this endpoint exists. Null when X did not label the row, which is not the same as Member: a roster we cannot role-label has unknown roles, and reading null as Member would deny moderators.",
                            "nullable": true
                          }
                        }
                      }
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page, or null when X sent none. Absence of this cursor is the only end-of-list signal X gives on this operation.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when this page returned rows and carried a usable next_cursor. Computed here; X sends no has_more of its own on this operation."
                    }
                  }
                },
                "example": {
                  "members": [
                    {
                      "user": {
                        "id": "1281109705495130113",
                        "username": "pizzaboy",
                        "name": "Dan Holdsworth",
                        "profile_image_url": "https://pbs.twimg.com/profile_images/..._normal.png",
                        "is_blue_verified": true,
                        "verified": false,
                        "is_protected": false
                      },
                      "role": "Admin"
                    },
                    {
                      "user": {
                        "id": "44196397",
                        "username": "devjane",
                        "name": "Jane",
                        "profile_image_url": "https://pbs.twimg.com/profile_images/..._normal.png",
                        "is_blue_verified": false,
                        "verified": false,
                        "is_protected": false
                      },
                      "role": "Member"
                    }
                  ],
                  "next_cursor": "RG9uZUZvck5vd0N1cnNvcg==",
                  "has_more": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "community_id",
            "in": "query",
            "required": true,
            "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL.",
            "schema": {
              "type": "string",
              "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL.",
              "example": "1493446837214187523"
            },
            "example": "1493446837214187523"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Page size. Defaults to 20 and is clamped to 1-100, so count=500 returns 100 rather than erroring. A non-numeric value is a 400.",
            "schema": {
              "type": "integer",
              "description": "Page size. Defaults to 20 and is clamped to 1-100, so count=500 returns 100 rather than erroring. A non-numeric value is a 400.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/community/moderators": {
      "get": {
        "operationId": "community-moderators",
        "summary": "Community Moderators",
        "description": "Fetch the moderators and admins of an X Community, cursor-paginated, in the same row shape Community Members returns. This is a separate upstream operation rather than a filter over the member roster, because moderators are interleaved through that roster at arbitrary positions. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/moderators?community_id=1493446837214187523\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/moderators\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"community_id\": \"1493446837214187523\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/moderators\");\nurl.search = new URLSearchParams({ community_id: \"1493446837214187523\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/community/moderators?community_id=1493446837214187523&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.members | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.members[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/community/moderators\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"community_id\": \"1493446837214187523\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"members\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { community_id: \"1493446837214187523\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/community/moderators\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.members ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through a community's moderators and admins.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "description": "Moderator rows for this page, each { user, role }. The key is members, not moderators: the row shape is identical to Community Members on purpose, so one type serves both endpoints and the two cannot drift.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "user": {
                            "type": "object",
                            "description": "The same REDUCED user profile Community Members returns: id, username, name, profile_image_url, is_blue_verified, verified, is_protected. No bio, no follower counts, no created_at, because X's roster operation does not send them.",
                            "additionalProperties": true
                          },
                          "role": {
                            "type": "string",
                            "description": "That account's role in this community, expected to be Moderator or Admin here. Like the role on a Community Members row, this one is NOT caller-relative and is returned in full: it describes that account, is identical for every caller, and is the content of the endpoint. It is returned rather than assumed constant, so a moderator roster that starts carrying a mixed role set surfaces instead of being silently flattened. Null when X did not label the row, which is not the same as Member.",
                            "nullable": true
                          }
                        }
                      }
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page, or null when X sent none.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when this page returned rows and carried a usable next_cursor. Computed here; X sends no has_more of its own."
                    }
                  }
                },
                "example": {
                  "members": [
                    {
                      "user": {
                        "id": "1281109705495130113",
                        "username": "pizzaboy",
                        "name": "Dan Holdsworth",
                        "profile_image_url": "https://pbs.twimg.com/profile_images/..._normal.png",
                        "is_blue_verified": true,
                        "verified": false,
                        "is_protected": false
                      },
                      "role": "Admin"
                    },
                    {
                      "user": {
                        "id": "3310215544",
                        "username": "buildlogs",
                        "name": "Build Logs",
                        "profile_image_url": "https://pbs.twimg.com/profile_images/..._normal.png",
                        "is_blue_verified": true,
                        "verified": false,
                        "is_protected": false
                      },
                      "role": "Moderator"
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "community_id",
            "in": "query",
            "required": true,
            "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL.",
            "schema": {
              "type": "string",
              "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL.",
              "example": "1493446837214187523"
            },
            "example": "1493446837214187523"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Page size. Defaults to 20 and is clamped to 1-100. A non-numeric value is a 400.",
            "schema": {
              "type": "integer",
              "description": "Page size. Defaults to 20 and is clamped to 1-100. A non-numeric value is a 400.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/community/tweets": {
      "get": {
        "operationId": "community-tweets",
        "summary": "Community Tweets",
        "description": "Fetch the post timeline of an X Community, cursor-paginated as full tweet objects, with optional ordering control. The community's pinned post is returned as its own field rather than mixed into the feed, because X delivers it under a different timeline instruction and does not repeat it in the feed. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/tweets?community_id=1493446837214187523\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/tweets\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"community_id\": \"1493446837214187523\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/tweets\");\nurl.search = new URLSearchParams({ community_id: \"1493446837214187523\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/community/tweets?community_id=1493446837214187523&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.tweets | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.tweets[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/community/tweets\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"community_id\": \"1493446837214187523\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"tweets\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { community_id: \"1493446837214187523\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/community/tweets\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.tweets ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Page through a community's post timeline, with the pinned post returned separately.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pinned": {
                      "type": "object",
                      "description": "The community's PINNED post as a full tweet object, or null when the community has none. It is its own field and is NOT included in tweets: X delivers it under a separate timeline instruction and does not repeat it in the feed, so a parser that reads only the feed drops it without a trace. In one large community we sampled it was the rules post, which is usually the single most useful item in the response. A client that wants one flat list should read pinned first, then tweets.",
                      "additionalProperties": true,
                      "nullable": true
                    },
                    "tweets": {
                      "type": "array",
                      "description": "The community's posts for this page, as full tweet objects. The pinned post is excluded, so a flat list is pinned followed by tweets with no duplicate. X attaches a caller-relative community moderation state to each tweet upstream; it is never extracted, because on a public read it would not describe you.",
                      "items": {
                        "$ref": "#/components/schemas/Tweet"
                      }
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page, or null when there is none. Pass it back as ?cursor=.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when this page returned tweets and carried a usable next_cursor. False on the final page."
                    }
                  }
                },
                "example": {
                  "pinned": {
                    "id": "1926022758195921145",
                    "text": "Community rules: be useful, no unsolicited DMs, no engagement bait.",
                    "created_at": "Fri May 23 09:14:02 +0000 2026",
                    "author": {
                      "id": "1281109705495130113",
                      "username": "pizzaboy",
                      "name": "Dan Holdsworth"
                    },
                    "favorite_count": 118
                  },
                  "tweets": [
                    {
                      "id": "1926104411223344556",
                      "text": "Shipped the billing rewrite this morning. Numbers in the thread.",
                      "created_at": "Fri May 23 14:41:19 +0000 2026",
                      "author": {
                        "id": "44196397",
                        "username": "devjane",
                        "name": "Jane"
                      },
                      "favorite_count": 26,
                      "reply_count": 4
                    }
                  ],
                  "next_cursor": "DAABCgABF...",
                  "has_more": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "community_id",
            "in": "query",
            "required": true,
            "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL.",
            "schema": {
              "type": "string",
              "description": "The numeric community id, the digits in a x.com/i/communities/<id> URL.",
              "example": "1493446837214187523"
            },
            "example": "1493446837214187523"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Page size. Defaults to 20 and is clamped to 1-100. A non-numeric value is a 400.",
            "schema": {
              "type": "integer",
              "description": "Page size. Defaults to 20 and is clamped to 1-100. A non-numeric value is a 400.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "ranking_mode",
            "in": "query",
            "required": false,
            "description": "Ordering, sent to X as a real upstream parameter rather than applied as a local sort. Recency is the default. Relevance is also accepted, matching the two orderings X's community tab offers, but Recency is the one to depend on. Any other value is a 400.",
            "schema": {
              "type": "string",
              "description": "Ordering, sent to X as a real upstream parameter rather than applied as a local sort. Recency is the default. Relevance is also accepted, matching the two orderings X's community tab offers, but Recency is the one to depend on. Any other value is a 400.",
              "example": "Recency"
            },
            "example": "Recency"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          },
          {
            "$ref": "#/components/parameters/paid_promotion"
          }
        ]
      }
    },
    "/community/memberships": {
      "get": {
        "operationId": "community-memberships",
        "summary": "Community Memberships",
        "description": "The inverse relation: given a numeric X user id, list the communities that account belongs to, cursor-paginated. Each row is the FULL community object, and it is the most populated form of it this API returns: admin, invites_policy, question, search_tags, members_facepile_ids and a real moderator_count all arrive here and do not on Community Info. Profiling an account's community footprint takes one call per page rather than a follow-up lookup per community. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/memberships?user_id=1281109705495130113\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/memberships\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"user_id\": \"1281109705495130113\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/memberships\");\nurl.search = new URLSearchParams({ user_id: \"1281109705495130113\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/community/memberships?user_id=1281109705495130113&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.communities | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.communities[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/community/memberships\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"user_id\": \"1281109705495130113\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"communities\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { user_id: \"1281109705495130113\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/community/memberships\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.communities ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "List every community a given account belongs to.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "communities": {
                      "type": "array",
                      "description": "The communities this account belongs to, for this page. Each entry is the shared Community object, the same 24 keys Community Info returns, so a client that renders one can render the other. It is also the MORE POPULATED of the two: admin, invites_policy, question, search_tags, members_facepile_ids, a real moderator_count and a full creator profile all come back here and do not on Community Info. Deduplicated by id.",
                      "items": {
                        "$ref": "#/components/schemas/Community"
                      }
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page, or null when there is none.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when this page returned communities and carried a usable next_cursor. False on the final page."
                    }
                  }
                },
                "example": {
                  "communities": [
                    {
                      "id": "1828843041869713562",
                      "name": "Build In Public - SaaS",
                      "description": "Founders shipping in the open.",
                      "created_at": 1724865134102,
                      "member_count": 392,
                      "moderator_count": 1,
                      "join_policy": "RestrictedJoinRequestsRequireModeratorApproval",
                      "invites_policy": "MemberInvitesAllowed",
                      "is_nsfw": false,
                      "question": "What are you currently building?",
                      "primary_topic": {
                        "topic_id": "303",
                        "name": "Software"
                      },
                      "search_tags": [
                        "saas",
                        "buildinpublic"
                      ],
                      "rules": [
                        {
                          "id": "1828843041869713570",
                          "name": "Be useful, not promotional",
                          "description": null
                        }
                      ],
                      "banner_url": "https://pbs.twimg.com/community_banner_img/...",
                      "permalink": null,
                      "admin": {
                        "id": "1281109705495130113",
                        "username": "pizzaboy",
                        "name": "Dan Holdsworth"
                      },
                      "creator": {
                        "id": "1281109705495130113",
                        "username": "pizzaboy",
                        "name": "Dan Holdsworth"
                      },
                      "members_facepile_ids": [
                        "1281109705495130113"
                      ],
                      "role": null,
                      "can_join": null,
                      "is_pinned": null,
                      "viewer_relationship_type": null
                    }
                  ],
                  "next_cursor": null,
                  "has_more": false
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": true,
            "description": "The numeric X user id, NOT a handle and NOT a community id. Resolve a @handle to an id with User Info first; doing that resolution silently here would turn one billed read into two.",
            "schema": {
              "type": "string",
              "description": "The numeric X user id, NOT a handle and NOT a community id. Resolve a @handle to an id with User Info first; doing that resolution silently here would turn one billed read into two.",
              "example": "1281109705495130113"
            },
            "example": "1281109705495130113"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call."
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Page size. Defaults to 20 and is clamped to 1-100. A non-numeric value is a 400.",
            "schema": {
              "type": "integer",
              "description": "Page size. Defaults to 20 and is clamped to 1-100. A non-numeric value is a 400.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/community/about": {
      "get": {
        "operationId": "community-about",
        "summary": "Community About",
        "description": "The About tab for one community: its moderators, and a preview of its members, both returned as FULL user profiles with bio, follower and following counts, tweet counts, location, website, banner and join date. Community Members and Community Moderators return a reduced row instead, so this is the endpoint that answers who runs a community in one call rather than one call plus a profile lookup per person. It is not paginated, because the upstream operation is not. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/about?community_id=1493446837214187523\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/about\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"community_id\": \"1493446837214187523\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/about\");\nurl.search = new URLSearchParams({ community_id: \"1493446837214187523\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "A community's moderators and a members preview, as full profiles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "moderators": {
                      "type": "array",
                      "description": "The community's moderators, as full user profiles. Same object User Info returns.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "members": {
                      "type": "array",
                      "description": "A preview of the community's members, as full user profiles. X caps this at 10 rows on the underlying tab, so treat it as a sample and not a roster.",
                      "items": {
                        "$ref": "#/components/schemas/User"
                      }
                    },
                    "moderators_truncated": {
                      "type": "boolean",
                      "description": "True when X indicated there are more moderators than it sent. Read off X's own show-more marker, not inferred from the row count, so a community with exactly as many moderators as fit is reported correctly."
                    },
                    "members_truncated": {
                      "type": "boolean",
                      "description": "Same, for the members preview. True in practice for any community with more than 10 members. Page the full list with Community Members."
                    },
                    "other_sections": {
                      "type": "array",
                      "description": "Any section of the About tab this API does not yet model, each carrying id, title, users and more_url. Empty on every community observed so far. It exists so a section X adds later reaches you rather than being silently dropped.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                },
                "example": {
                  "moderators": [
                    {
                      "id": "88403351",
                      "username": "iuditg",
                      "name": "Udit Goenka",
                      "description": "Building in public.",
                      "followers_count": 60868,
                      "following_count": 372,
                      "tweet_count": 46535,
                      "location": "India",
                      "url": "https://example.com",
                      "created_at": "Sun Nov 08 11:49:55 +0000 2009",
                      "profile_image_url": "https://pbs.twimg.com/profile_images/.../photo_normal.jpg",
                      "is_blue_verified": true
                    }
                  ],
                  "members": [
                    {
                      "id": "2535083002",
                      "username": "sachikantaraul",
                      "name": "Sachikanta Raul",
                      "description": "Indie hacker.",
                      "followers_count": 41,
                      "following_count": 300,
                      "tweet_count": 1204,
                      "location": "India",
                      "url": null,
                      "created_at": "Thu May 08 13:15:44 +0000 2014",
                      "profile_image_url": "https://pbs.twimg.com/profile_images/.../photo_normal.jpg",
                      "is_blue_verified": true
                    }
                  ],
                  "moderators_truncated": false,
                  "members_truncated": true,
                  "other_sections": []
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "community_id",
            "in": "query",
            "required": true,
            "description": "The numeric X community id, the digits in x.com/i/communities/<id>.",
            "schema": {
              "type": "string",
              "description": "The numeric X community id, the digits in x.com/i/communities/<id>.",
              "example": "1493446837214187523"
            },
            "example": "1493446837214187523"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/community/search": {
      "get": {
        "operationId": "community-search",
        "summary": "Community Search",
        "description": "Find communities by keyword, cursor-paginated. This is the discovery step the rest of this family assumes: every other community endpoint starts from a community id, and this is the one that produces one. Each hit is a compact record, id, name, member count, nsfw flag, topic name, banners and the facepile avatars, which is exactly what X's search operation sends and nothing more. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Communities"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/community/search?query=build%20in%20public\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/community/search\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"query\": \"build in public\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/community/search\");\nurl.search = new URLSearchParams({ query: \"build in public\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/community/search?query=build%20in%20public&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.communities | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.communities[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/community/search\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"query\": \"build in public\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"communities\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { query: \"build in public\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/community/search\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.communities ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "Search X Communities by keyword.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "communities": {
                      "type": "array",
                      "description": "The matching communities for this page. A COMPACT record, not the full Community object Community Info returns: id, name, member_count, is_nsfw, primary_topic, banner_url, custom_banner, default_banner and member_avatar_urls. Take an id from here and call Community Info for the rest.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page, or null when there is none.",
                      "nullable": true
                    },
                    "has_more": {
                      "type": "boolean",
                      "description": "True when this page returned communities and carried a usable next_cursor."
                    }
                  }
                },
                "example": {
                  "communities": [
                    {
                      "id": "1493446837214187523",
                      "name": "Build in Public",
                      "member_count": 265158,
                      "is_nsfw": false,
                      "primary_topic": {
                        "topic_id": null,
                        "name": "Entrepreneurship"
                      },
                      "banner_url": "https://pbs.twimg.com/community_banner_img/...",
                      "custom_banner": {
                        "url": "https://pbs.twimg.com/community_banner_img/...",
                        "width": 805,
                        "height": 322
                      },
                      "default_banner": {
                        "url": "https://pbs.twimg.com/media/....jpg",
                        "width": 1200,
                        "height": 480
                      },
                      "member_avatar_urls": [
                        "https://pbs.twimg.com/profile_images/.../photo_normal.jpg"
                      ]
                    }
                  ],
                  "next_cursor": "WzM1Mi4xMzgzLDE5NDM4NDIyMDQwNzU4NjgyMzhd",
                  "has_more": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": true,
            "description": "The keyword to search for. 1 to 500 characters.",
            "schema": {
              "type": "string",
              "description": "The keyword to search for. 1 to 500 characters.",
              "example": "build in public"
            },
            "example": "build in public"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor. Omit on the first call."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/media/upload": {
      "post": {
        "operationId": "media-upload",
        "summary": "Upload Media",
        "description": "Upload a base64-encoded image as the authenticated account and receive a media_id you can attach when creating a tweet. Runs as your own logged-in account. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/media/upload\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"media_data\": \"iVBORw0KGgoAAAANSUhEUgAA...\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/media/upload\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"media_data\": \"iVBORw0KGgoAAAANSUhEUgAA...\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/media/upload\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ media_data: \"iVBORw0KGgoAAAANSUhEUgAA...\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Upload an image and get a media_id to attach to a tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the upload succeeded (media_id is present)."
                    },
                    "media_id": {
                      "type": "string",
                      "description": "The uploaded media's ID; pass it to tweet/create to attach the image."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "media_id": "1899999999999999999"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "media_data": {
                    "type": "string",
                    "description": "Base64-encoded image bytes, sent in the JSON request body.",
                    "example": "iVBORw0KGgoAAAANSUhEUgAA..."
                  }
                },
                "required": [
                  "media_data"
                ]
              }
            }
          }
        }
      }
    },
    "/media/status": {
      "get": {
        "operationId": "media-status",
        "summary": "Media Status",
        "description": "Return the async processing state of a media_id from Upload Media, so a caller can verify readiness before attaching a video, GIF, or large-media id to a tweet. Runs as your own logged-in account. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/media/status?media_id=1899999999999999999\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/media/status\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"media_id\": \"1899999999999999999\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/media/status\");\nurl.search = new URLSearchParams({ media_id: \"1899999999999999999\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Check the async processing state of an uploaded media_id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "media_id": {
                      "type": "string",
                      "description": "Echo of the media_id you queried."
                    },
                    "state": {
                      "type": "string",
                      "description": "Processing state: pending, in_progress, succeeded, or failed."
                    },
                    "check_after_secs": {
                      "type": "integer",
                      "description": "Seconds to wait before polling again while the state is pending or in_progress; 0 once processing has finished."
                    },
                    "progress_percent": {
                      "type": "integer",
                      "description": "Percentage of processing completed, from 0 to 100."
                    },
                    "error": {
                      "type": "string",
                      "description": "Failure reason, present only when state is failed; omitted otherwise."
                    }
                  }
                },
                "example": {
                  "media_id": "1899999999999999999",
                  "state": "succeeded",
                  "check_after_secs": 0,
                  "progress_percent": 100
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "media_id",
            "in": "query",
            "required": true,
            "description": "Numeric media ID (as a string) returned by media/upload.",
            "schema": {
              "type": "string",
              "description": "Numeric media ID (as a string) returned by media/upload.",
              "example": "1899999999999999999"
            },
            "example": "1899999999999999999"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/list/add_member": {
      "post": {
        "operationId": "list-add-member",
        "summary": "Add List Member",
        "description": "Add an account to a List owned by your registered X session. Returns the List's member_count as proof the membership change landed. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/list/add_member\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{{\"list_id\": \"1234567890123456789\", \"user_id\": \"745273\"}}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/list/add_member\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"list_id\": \"1234567890123456789\", \"user_id\": \"745273\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/list/add_member\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ list_id: \"1234567890123456789\", user_id: \"745273\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Add one account to a Twitter/X List you own.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the membership change applied."
                    },
                    "action": {
                      "type": "string",
                      "description": "The membership action performed."
                    },
                    "list_id": {
                      "type": "string",
                      "description": "The List the write targeted."
                    },
                    "user_id": {
                      "type": "string",
                      "description": "The account the write targeted."
                    },
                    "member_count": {
                      "type": "integer",
                      "description": "The List's member count after the write, read back from X as proof. Null when X returned no list object, which is the not-applied signal.",
                      "nullable": true
                    },
                    "list": {
                      "type": "object",
                      "description": "The List object X returned after the write.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "action": "add_member",
                  "list_id": "1234567890123456789",
                  "user_id": "745273",
                  "member_count": 42,
                  "list": {
                    "id": "1234567890123456789",
                    "name": "Founders",
                    "member_count": 42
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "string",
                    "description": "Numeric ID of the List you own.",
                    "example": "1234567890123456789"
                  },
                  "user_id": {
                    "type": "string",
                    "description": "Numeric ID of the account to add.",
                    "example": "745273"
                  }
                },
                "required": [
                  "list_id",
                  "user_id"
                ]
              }
            }
          }
        }
      }
    },
    "/list/remove_member": {
      "post": {
        "operationId": "list-remove-member",
        "summary": "Remove List Member",
        "description": "Remove an account from a List owned by your registered X session. Returns the List's member_count as proof the membership change landed. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/list/remove_member\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{{\"list_id\": \"1234567890123456789\", \"user_id\": \"745273\"}}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/list/remove_member\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"list_id\": \"1234567890123456789\", \"user_id\": \"745273\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/list/remove_member\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ list_id: \"1234567890123456789\", user_id: \"745273\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Remove one account from a Twitter/X List you own.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the membership change applied."
                    },
                    "action": {
                      "type": "string",
                      "description": "The membership action performed."
                    },
                    "list_id": {
                      "type": "string",
                      "description": "The List the write targeted."
                    },
                    "user_id": {
                      "type": "string",
                      "description": "The account the write targeted."
                    },
                    "member_count": {
                      "type": "integer",
                      "description": "The List's member count after the write, read back from X as proof. Null when X returned no list object, which is the not-applied signal.",
                      "nullable": true
                    },
                    "list": {
                      "type": "object",
                      "description": "The List object X returned after the write.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "action": "remove_member",
                  "list_id": "1234567890123456789",
                  "user_id": "745273",
                  "member_count": 41,
                  "list": {
                    "id": "1234567890123456789",
                    "name": "Founders",
                    "member_count": 41
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "string",
                    "description": "Numeric ID of the List you own.",
                    "example": "1234567890123456789"
                  },
                  "user_id": {
                    "type": "string",
                    "description": "Numeric ID of the account to remove.",
                    "example": "745273"
                  }
                },
                "required": [
                  "list_id",
                  "user_id"
                ]
              }
            }
          }
        }
      }
    },
    "/list/create": {
      "post": {
        "operationId": "list-create",
        "summary": "Create List",
        "description": "Create a List owned by your registered X session, with a name and an optional description and privacy flag. Populate it afterwards with Add List Member. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/list/create\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{{\"name\": \"Founders\"}}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/list/create\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"name\": \"Founders\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/list/create\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ name: \"Founders\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Create a new Twitter/X List owned by your session.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the List was created."
                    },
                    "list": {
                      "type": "object",
                      "description": "The List object X returned, including its new numeric id.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "list": {
                    "id": "1234567890123456789",
                    "name": "Founders",
                    "description": "People building in public.",
                    "member_count": 0
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name for the new List.",
                    "example": "Founders"
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional description shown on the List.",
                    "example": "People building in public."
                  },
                  "is_private": {
                    "type": "boolean",
                    "description": "Whether the List is private. Private Lists are not readable by the public List read endpoints.",
                    "example": "false"
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        }
      }
    },
    "/tweet/favorite": {
      "post": {
        "operationId": "tweet-favorite",
        "summary": "Like Tweet",
        "description": "Like a tweet as the authenticated account. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/favorite?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/favorite\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"id\": \"1759123456789012345\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/favorite\");\nurl.search = new URLSearchParams({ \"id\": \"1759123456789012345\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Like (favorite) a tweet on behalf of an authenticated account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the like is recorded."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to like. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to like. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet to like. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet to like. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/tweet/unfavorite": {
      "post": {
        "operationId": "tweet-unfavorite",
        "summary": "Unlike Tweet",
        "description": "Remove a previously recorded like from a tweet as the authenticated account. Requires a logged-in session. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/unfavorite?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/unfavorite\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"id\": \"1759123456789012345\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/unfavorite\");\nurl.search = new URLSearchParams({ \"id\": \"1759123456789012345\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Remove a like (unfavorite) from a tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the like is removed."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to unlike. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to unlike. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet to unlike. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet to unlike. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/tweet/retweet": {
      "post": {
        "operationId": "tweet-retweet",
        "summary": "Retweet",
        "description": "Retweet a tweet as the authenticated account. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/retweet?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/retweet\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"id\": \"1759123456789012345\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/retweet\");\nurl.search = new URLSearchParams({ \"id\": \"1759123456789012345\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Retweet a tweet on behalf of an authenticated account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the retweet is recorded."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to retweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to retweet. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet to retweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet to retweet. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/tweet/unretweet": {
      "post": {
        "operationId": "tweet-unretweet",
        "summary": "Undo Retweet",
        "description": "Undo a previously recorded retweet as the authenticated account. Requires a logged-in session. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/unretweet?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/unretweet\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"id\": \"1759123456789012345\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/unretweet\");\nurl.search = new URLSearchParams({ \"id\": \"1759123456789012345\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Remove a retweet from a tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the retweet is removed."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to un-retweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to un-retweet. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet to un-retweet. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet to un-retweet. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/tweet/bookmark": {
      "post": {
        "operationId": "tweet-bookmark",
        "summary": "Bookmark Tweet",
        "description": "Bookmark a tweet as the authenticated account. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/bookmark?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/bookmark\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"id\": \"1759123456789012345\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/bookmark\");\nurl.search = new URLSearchParams({ \"id\": \"1759123456789012345\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Add a tweet to the authenticated account's bookmarks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the bookmark is recorded."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to bookmark. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to bookmark. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet to bookmark. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet to bookmark. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/tweet/unbookmark": {
      "post": {
        "operationId": "tweet-unbookmark",
        "summary": "Remove Bookmark",
        "description": "Remove a previously saved bookmark as the authenticated account. Requires a logged-in session. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/unbookmark?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/unbookmark\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"id\": \"1759123456789012345\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/unbookmark\");\nurl.search = new URLSearchParams({ \"id\": \"1759123456789012345\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Remove a tweet from the authenticated account's bookmarks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the bookmark is removed."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to un-bookmark. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to un-bookmark. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Full status URL of the tweet to un-bookmark. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Full status URL of the tweet to un-bookmark. Provide either id or url.",
              "example": "https://x.com/naval/status/1759123456789012345"
            },
            "example": "https://x.com/naval/status/1759123456789012345"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/user/follow": {
      "post": {
        "operationId": "user-follow",
        "summary": "Follow User",
        "description": "Follow a user as the authenticated account. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/user/follow?user_id=44196397\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/user/follow\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"user_id\": \"44196397\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/follow\");\nurl.search = new URLSearchParams({ \"user_id\": \"44196397\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Follow a user on behalf of an authenticated account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the follow is recorded."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the user to follow. Send this or username; user_id wins when both are present.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the user to follow. Send this or username; user_id wins when both are present.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "username",
            "in": "query",
            "required": false,
            "description": "Handle of the user to follow, with or without the leading @. Resolved to its numeric ID for you through the same cached lookup as Check Follow Relationship; an unknown handle returns 404 and no follow is issued.",
            "schema": {
              "type": "string",
              "description": "Handle of the user to follow, with or without the leading @. Resolved to its numeric ID for you through the same cached lookup as Check Follow Relationship; an unknown handle returns 404 and no follow is issued.",
              "example": "elonmusk"
            },
            "example": "elonmusk"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/user/unfollow": {
      "post": {
        "operationId": "user-unfollow",
        "summary": "Unfollow User",
        "description": "Unfollow a user as the authenticated account. Requires a logged-in session for the acting account. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/user/unfollow?user_id=44196397\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\"\n# Add &proxy=http://user:pass@host:port to route through your own clean IP."
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/user/unfollow\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={ \"user_id\": \"44196397\" },  # add \"proxy\": \"http://user:pass@host:port\" to use your own IP\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/user/unfollow\");\nurl.search = new URLSearchParams({ \"user_id\": \"44196397\" }).toString();\n// Add proxy: \"http://user:pass@host:port\" above to route through your own clean IP.\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Unfollow a user on behalf of an authenticated account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the unfollow is recorded."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "user_id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the user to unfollow. Send this or username; user_id wins when both are present.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the user to unfollow. Send this or username; user_id wins when both are present.",
              "example": "44196397"
            },
            "example": "44196397"
          },
          {
            "name": "username",
            "in": "query",
            "required": false,
            "description": "Handle of the user to unfollow, with or without the leading @. Resolved to its numeric ID for you through the same cached lookup as Check Follow Relationship; an unknown handle returns 404 and no unfollow is issued.",
            "schema": {
              "type": "string",
              "description": "Handle of the user to unfollow, with or without the leading @. Resolved to its numeric ID for you through the same cached lookup as Check Follow Relationship; an unknown handle returns 404 and no unfollow is issued.",
              "example": "elonmusk"
            },
            "example": "elonmusk"
          },
          {
            "name": "proxy",
            "in": "query",
            "required": false,
            "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default.",
            "schema": {
              "type": "string",
              "description": "Optional. Pass your own proxy (http(s)/socks URL) to egress the write through your clean IP for best success; if omitted, we use the session's proxy / our default."
            }
          }
        ]
      }
    },
    "/tweet/create": {
      "post": {
        "operationId": "tweet-create",
        "summary": "Create Tweet",
        "description": "Post a new tweet as the account behind your registered session. Supports plain text, up to 4 image media_ids (from a prior media/upload), a reply (reply_to), and a quote (quote). Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/create\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"text\": \"Shipping cursor-paginated bookmarks today.\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/create\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"text\": \"Shipping cursor-paginated bookmarks today.\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/tweet/create\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ text: \"Shipping cursor-paginated bookmarks today.\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Post a tweet as your registered account: text, media, reply, or quote.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the tweet was posted."
                    },
                    "tweet_id": {
                      "type": "string",
                      "description": "Numeric ID of the created tweet, or null if the ID could not be resolved.",
                      "nullable": true
                    },
                    "url": {
                      "type": "string",
                      "description": "Canonical x.com URL of the created tweet, or null.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "tweet_id": "1759123456789012345",
                  "url": "https://x.com/i/status/1759123456789012345"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The tweet body.",
                    "example": "Shipping cursor-paginated bookmarks today."
                  },
                  "media_ids": {
                    "type": "string",
                    "description": "Up to 4 media IDs from media/upload, as a comma-separated string or JSON array. Omit for a text-only tweet.",
                    "example": "1899999999999999999"
                  },
                  "reply_to": {
                    "type": "string",
                    "description": "ID of the tweet to reply to (send it as a string; X IDs are 19 digits). Omit for a top-level tweet.",
                    "example": "2080297101888733302"
                  },
                  "quote": {
                    "type": "string",
                    "description": "ID of the tweet to quote (send it as a string; X IDs are 19 digits).",
                    "example": "1900000000000000000"
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        }
      }
    },
    "/tweet/delete": {
      "post": {
        "operationId": "tweet-delete",
        "summary": "Delete Tweet",
        "description": "Delete a tweet owned by the account behind your registered session. Identify it by id or url (read from the query string). Requires a registered session. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/tweet/delete?id=1759123456789012345\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/tweet/delete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"1759123456789012345\"},\n)\nresp.raise_for_status()\nprint(resp.json())"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/tweet/delete\");\nurl.search = new URLSearchParams({ id: \"1759123456789012345\" }).toString();\nconst resp = await fetch(url, {\n  method: \"POST\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconsole.log(await resp.json());"
          }
        ],
        "responses": {
          "200": {
            "description": "Delete one of your registered account's tweets by ID or status URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the delete succeeded (mirrors deleted)."
                    },
                    "deleted": {
                      "type": "boolean",
                      "description": "True when X confirmed the tweet was deleted."
                    },
                    "tweet_id": {
                      "type": "string",
                      "description": "The numeric ID that was deleted."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": true,
                  "tweet_id": "1759123456789012345"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Numeric ID of the tweet to delete. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Numeric ID of the tweet to delete. Provide either id or url.",
              "example": "1759123456789012345"
            },
            "example": "1759123456789012345"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "Status URL of the tweet to delete, for example https://x.com/you/status/1759123456789012345. Provide either id or url.",
            "schema": {
              "type": "string",
              "description": "Status URL of the tweet to delete, for example https://x.com/you/status/1759123456789012345. Provide either id or url."
            }
          }
        ]
      }
    },
    "/user/update_profile": {
      "post": {
        "operationId": "user-update-profile",
        "summary": "Update Profile",
        "description": "Update the profile of the account behind your registered session. Send only the fields you want to change: this is a genuine PARTIAL update, and anything you omit is left exactly as it was rather than being blanked. At least one of name, description, location or url is required. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/user/update_profile\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"name\": \"Acme Research\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/user/update_profile\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"name\": \"Acme Research\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/user/update_profile\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ name: \"Acme Research\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Change your own display name, bio, location or link. A PARTIAL update.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when X accepted the update."
                    },
                    "updated_fields": {
                      "type": "array",
                      "description": "The field names you sent on this call, echoed back. It reports what was SUBMITTED, not a diff against your previous profile, so a field you set to the value it already had still appears here.",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "updated_fields": [
                    "name"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "New display name, up to 50 characters. Omit to leave it unchanged.",
                    "example": "Acme Research"
                  },
                  "description": {
                    "type": "string",
                    "description": "New bio. Send an EMPTY STRING to clear it; omitting the field entirely leaves it alone. Those are two different things.",
                    "example": "Building things people can check."
                  },
                  "location": {
                    "type": "string",
                    "description": "New location text. Same rule: an empty string clears it, omitting the field leaves it alone."
                  },
                  "url": {
                    "type": "string",
                    "description": "New profile link.",
                    "example": "https://www.twitterapis.com"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/user/update_avatar": {
      "post": {
        "operationId": "user-update-avatar",
        "summary": "Update Avatar",
        "description": "Replace the profile picture on the account behind your registered session. Send the image base64-encoded in the request body; there is no URL-fetch form and no multipart form. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/user/update_avatar\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"image\": \"iVBORw0KGgoAAAANSUhEUgAA...\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/user/update_avatar\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"image\": \"iVBORw0KGgoAAAANSUhEUgAA...\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/user/update_avatar\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ image: \"iVBORw0KGgoAAAANSUhEUgAA...\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Replace your own profile picture with a base64-encoded image.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when X accepted the upload. A payload X cannot decode is refused upstream and surfaces as an error rather than as ok: false. On a rare 200 that applies nothing, the avatar route answers 422 with ok: false and a reason, because its check reads the account X returns; the banner route has no equivalent check and would report ok, which is why the read-back below is the confirmation rather than this field."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "description": "Base64-encoded image bytes, sent in the JSON request body. Not a URL and not multipart. `banner` and `data` are accepted as aliases for the same field.",
                    "example": "iVBORw0KGgoAAAANSUhEUgAA..."
                  }
                },
                "required": [
                  "image"
                ]
              }
            }
          }
        }
      }
    },
    "/user/update_banner": {
      "post": {
        "operationId": "user-update-banner",
        "summary": "Update Banner",
        "description": "Replace the wide header image on the account behind your registered session. Send the image base64-encoded in the request body; there is no URL-fetch form and no multipart form. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/user/update_banner\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"banner\": \"iVBORw0KGgoAAAANSUhEUgAA...\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/user/update_banner\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"banner\": \"iVBORw0KGgoAAAANSUhEUgAA...\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/user/update_banner\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ banner: \"iVBORw0KGgoAAAANSUhEUgAA...\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Replace your own profile header image with a base64-encoded image.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when X accepted the upload. A payload X cannot decode is refused upstream and surfaces as an error rather than as ok: false. On a rare 200 that applies nothing, the avatar route answers 422 with ok: false and a reason, because its check reads the account X returns; the banner route has no equivalent check and would report ok, which is why the read-back below is the confirmation rather than this field."
                    }
                  }
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "banner": {
                    "type": "string",
                    "description": "Base64-encoded image bytes, sent in the JSON request body. Not a URL and not multipart. `image` and `data` are accepted as aliases for the same field.",
                    "example": "iVBORw0KGgoAAAANSUhEUgAA..."
                  }
                },
                "required": [
                  "banner"
                ]
              }
            }
          }
        }
      }
    },
    "/draft/create": {
      "post": {
        "operationId": "draft-create",
        "summary": "Create Draft Tweet",
        "description": "Save a draft tweet on the account behind your registered session. A draft is private to that account and is never published: it appears in X's own composer under Drafts until you post or delete it. Accepts text, up to 4 media_ids, a reply_to and a quote, exactly like tweet/create. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/draft/create\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"text\": \"Draft: our Q1 changelog is nearly done.\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/draft/create\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"text\": \"Draft: our Q1 changelog is nearly done.\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/draft/create\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ text: \"Draft: our Q1 changelog is nearly done.\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Save a private draft on your own account. Nothing is posted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when X returned an id for the new draft."
                    },
                    "draft_tweet_id": {
                      "type": "string",
                      "description": "Numeric ID of the saved draft, or null when X refused the create. A null here answers 422 and is not billed.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "draft_tweet_id": "2086650228950683648"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The draft body. A draft with no text is refused with 400.",
                    "example": "Draft: our Q1 changelog is nearly done."
                  },
                  "media_ids": {
                    "type": "string",
                    "description": "Up to 4 media IDs from media/upload, as a comma-separated string or a JSON array. Omit for a text-only draft.",
                    "example": "1899999999999999999"
                  },
                  "reply_to": {
                    "type": "string",
                    "description": "ID of the tweet this draft replies to (send it as a string; X IDs are 19 digits).",
                    "example": "2080297101888733302"
                  },
                  "quote": {
                    "type": "string",
                    "description": "ID of the tweet this draft quotes (send it as a string; X IDs are 19 digits).",
                    "example": "1900000000000000000"
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        }
      }
    },
    "/draft/edit": {
      "post": {
        "operationId": "draft-edit",
        "summary": "Edit Draft Tweet",
        "description": "Replace an existing draft's contents on the account behind your registered session. The fields you send become the draft in full: text is required, and media_ids, reply_to and quote are re-applied rather than merged, so send everything the draft should keep. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/draft/edit\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"2086650228950683648\", \"text\": \"Draft v2: the Q1 changelog ships Thursday.\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/draft/edit\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"2086650228950683648\", \"text\": \"Draft v2: the Q1 changelog ships Thursday.\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/draft/edit\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"2086650228950683648\", text: \"Draft v2: the Q1 changelog ships Thursday.\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Replace the contents of an existing draft on your own account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the edit call reached X and X answered success. The response body is not re-read, so this is transport-level success rather than a re-read of the stored draft."
                    },
                    "draft_tweet_id": {
                      "type": "string",
                      "description": "The draft ID you edited, echoed back."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "draft_tweet_id": "2086650228950683648"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "ID of the draft to edit, from draft/list. Also accepted as draft_tweet_id.",
                    "example": "2086650228950683648"
                  },
                  "text": {
                    "type": "string",
                    "description": "The replacement draft body. Required: an edit with no text is refused with 400.",
                    "example": "Draft v2: the Q1 changelog ships Thursday."
                  },
                  "media_ids": {
                    "type": "string",
                    "description": "Up to 4 media IDs from media/upload, as a comma-separated string or a JSON array. Omitting it drops the media the draft had; it is not merged.",
                    "example": "1899999999999999999"
                  },
                  "reply_to": {
                    "type": "string",
                    "description": "ID of the tweet this draft replies to (send it as a string).",
                    "example": "2080297101888733302"
                  },
                  "quote": {
                    "type": "string",
                    "description": "ID of the tweet this draft quotes (send it as a string).",
                    "example": "1900000000000000000"
                  }
                },
                "required": [
                  "id",
                  "text"
                ]
              }
            }
          }
        }
      }
    },
    "/draft/delete": {
      "post": {
        "operationId": "draft-delete",
        "summary": "Delete Draft Tweet",
        "description": "Delete a draft owned by the account behind your registered session, identified by its id. The draft is removed from X's composer. Nothing was ever public, so this publishes nothing and retracts nothing. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/draft/delete\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"2086650228950683648\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/draft/delete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"2086650228950683648\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/draft/delete\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"2086650228950683648\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Delete a draft from your own account by ID.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the delete call reached X and X answered success (mirrors deleted)."
                    },
                    "deleted": {
                      "type": "boolean",
                      "description": "True when the delete call reached X and X answered success. X answers this operation with a confirmation rather than an id, so the body is not parsed for a per-row field: this is transport-level success, not a re-read of your drafts."
                    },
                    "draft_tweet_id": {
                      "type": "string",
                      "description": "The draft ID you asked to delete, echoed back."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": true,
                  "draft_tweet_id": "2086650228950683648"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "ID of the draft to delete, from draft/list. Also accepted as draft_tweet_id.",
                    "example": "2086650228950683648"
                  }
                },
                "required": [
                  "id"
                ]
              }
            }
          }
        }
      }
    },
    "/draft/list": {
      "get": {
        "operationId": "draft-list",
        "summary": "List Draft Tweets",
        "description": "List every draft on the account behind your registered session. Each row carries the draft id, its text, and thread_truncated, which is true when the draft is a thread and the text you get is only its first tweet. Ordering is X's: pass ascending=true to ask for the oldest first, omit it for X's default. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/draft/list\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/draft/list\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/draft/list\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List the drafts saved on your own account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "drafts": {
                      "type": "array",
                      "description": "The drafts on this account. An empty array with no partial flag is an honest empty list.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "draft_tweet_id": {
                            "type": "string",
                            "description": "Numeric ID of the draft. This is the id to pass to draft/edit and draft/delete."
                          },
                          "text": {
                            "type": "string",
                            "description": "The draft body. Null when that row's text could not be read, which also sets partial on the response.",
                            "nullable": true
                          },
                          "thread_truncated": {
                            "type": "boolean",
                            "description": "True when the draft is a THREAD and text is only its first tweet. The parse succeeded; the feature is narrower than the data. False for an ordinary single-tweet draft."
                          }
                        }
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of rows in drafts."
                    },
                    "partial": {
                      "type": "boolean",
                      "description": "Present and true only when the answer was read but not fully understood. ANY ONE of these sets it: a row was dropped, a row's text could not be read, a row's thread shape could not be read, or the envelope itself could not be read. ABSENT on a clean read, including a clean empty list, so an empty drafts array with no partial flag means you have no drafts rather than that we could not tell."
                    }
                  }
                },
                "example": {
                  "drafts": [
                    {
                      "draft_tweet_id": "2086650228950683648",
                      "text": "Draft: our Q1 changelog is nearly done.",
                      "thread_truncated": false
                    }
                  ],
                  "count": 1
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "ascending",
            "in": "query",
            "required": false,
            "description": "Pass true to ask X for the oldest draft first. Anything else, including omitting it, sends ascending=false, which is what X's own composer sends. The resulting order is X's and is not re-sorted here.",
            "schema": {
              "type": "boolean",
              "description": "Pass true to ask X for the oldest draft first. Anything else, including omitting it, sends ascending=false, which is what X's own composer sends. The resulting order is X's and is not re-sorted here.",
              "example": "false"
            },
            "example": "false"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/scheduled/create": {
      "post": {
        "operationId": "scheduled-create",
        "summary": "Schedule Tweet",
        "description": "Schedule a tweet from the account behind your registered session for a future instant. Unlike a draft, this WILL post publicly at execute_at unless you delete it first. execute_at is epoch SECONDS and must be in the future; a millisecond value is refused by name rather than scheduled tens of thousands of years out. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/scheduled/create\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"text\": \"The Q1 changelog is live.\", \"execute_at\": 1829752200}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/scheduled/create\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"text\": \"The Q1 changelog is live.\", \"execute_at\": 1829752200},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/scheduled/create\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ text: \"The Q1 changelog is live.\", execute_at: 1829752200 }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule a tweet to post publicly at a future instant.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when X returned an id for the scheduled post."
                    },
                    "scheduled_tweet_id": {
                      "type": "string",
                      "description": "Numeric ID of the scheduled post, or null when X refused it. A null here answers 422 and is not billed.",
                      "nullable": true
                    },
                    "execute_at": {
                      "type": "integer",
                      "description": "The instant you scheduled, echoed back in epoch SECONDS, the same unit you sent."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "scheduled_tweet_id": "2086650228950683649",
                  "execute_at": 1829752200
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "The tweet body. Required: a scheduled post with no text is refused with 400.",
                    "example": "The Q1 changelog is live."
                  },
                  "execute_at": {
                    "type": "integer",
                    "description": "When to post, as epoch SECONDS in the future. A value at or above 1000000000000 is rejected as milliseconds, with a message saying so, rather than accepted. Also accepted as schedule_at.",
                    "example": "1829752200"
                  },
                  "media_ids": {
                    "type": "string",
                    "description": "Up to 4 media IDs from media/upload, as a comma-separated string or a JSON array.",
                    "example": "1899999999999999999"
                  },
                  "reply_to": {
                    "type": "string",
                    "description": "ID of the tweet this post replies to (send it as a string).",
                    "example": "2080297101888733302"
                  },
                  "quote": {
                    "type": "string",
                    "description": "ID of the tweet this post quotes (send it as a string).",
                    "example": "1900000000000000000"
                  }
                },
                "required": [
                  "text",
                  "execute_at"
                ]
              }
            }
          }
        }
      }
    },
    "/scheduled/delete": {
      "post": {
        "operationId": "scheduled-delete",
        "summary": "Cancel Scheduled Tweet",
        "description": "Cancel a scheduled tweet on the account behind your registered session, identified by its id, so it never posts. Do this before execute_at: once the post has gone out it is an ordinary tweet and tweet/delete is what removes it. Billed at $0.0008 per call, the same as a standard read. Cost: $0.0008 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/scheduled/delete\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"2086650228950683649\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/scheduled/delete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"2086650228950683649\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/scheduled/delete\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"2086650228950683649\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Cancel a scheduled tweet before it posts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the cancel call reached X and X answered success (mirrors deleted)."
                    },
                    "deleted": {
                      "type": "boolean",
                      "description": "True when the cancel call reached X and X answered success. X answers this operation with a confirmation rather than an id, so the body is not parsed for a per-row field: this is transport-level success, not a re-read of your queue."
                    },
                    "scheduled_tweet_id": {
                      "type": "string",
                      "description": "The scheduled-tweet ID you asked to cancel, echoed back."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": true,
                  "scheduled_tweet_id": "2086650228950683649"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "ID of the scheduled tweet to cancel, from scheduled/list. Also accepted as scheduled_tweet_id.",
                    "example": "2086650228950683649"
                  }
                },
                "required": [
                  "id"
                ]
              }
            }
          }
        }
      }
    },
    "/scheduled/list": {
      "get": {
        "operationId": "scheduled-list",
        "summary": "List Scheduled Tweets",
        "description": "List every pending scheduled post on the account behind your registered session. Each row carries the id, its text, its execute_at in epoch SECONDS, X's own state label, and thread_truncated for a thread whose text is only its first tweet. Ordering is X's: pass ascending=true to ask for the oldest first. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Write Actions"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/scheduled/list\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/scheduled/list\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/scheduled/list\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List the posts queued to publish on your own account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scheduled": {
                      "type": "array",
                      "description": "The pending scheduled posts on this account. An empty array with no partial flag is an honest empty queue.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true,
                        "properties": {
                          "scheduled_tweet_id": {
                            "type": "string",
                            "description": "Numeric ID of the scheduled post. This is the id to pass to scheduled/delete."
                          },
                          "text": {
                            "type": "string",
                            "description": "The post body. Null when that row's text could not be read.",
                            "nullable": true
                          },
                          "thread_truncated": {
                            "type": "boolean",
                            "description": "True when the row is a THREAD and text is only its first tweet. False for an ordinary single-tweet post."
                          },
                          "execute_at": {
                            "type": "integer",
                            "description": "When the post publishes, in epoch SECONDS. X answers this operation in MILLISECONDS and the value is converted here, so one unit is spoken on both sides of the API and a value read here can be sent straight back to scheduled/create. Null when the instant could not be read.",
                            "nullable": true
                          },
                          "state": {
                            "type": "string",
                            "description": "X's own scheduling state for the row, for example \"Scheduled\", passed through verbatim. Null when X sent none.",
                            "nullable": true
                          }
                        }
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of rows in scheduled."
                    },
                    "partial": {
                      "type": "boolean",
                      "description": "Present and true only when the answer was read but not fully understood. ANY ONE of these sets it: a row was dropped, a row's text could not be read, a row's instant could not be read, a row's thread shape could not be read, or the envelope itself could not be read. ABSENT on a clean read, including a clean empty queue, so an empty scheduled array with no partial flag means nothing is queued rather than that we could not tell."
                    }
                  }
                },
                "example": {
                  "scheduled": [
                    {
                      "scheduled_tweet_id": "2086650228950683649",
                      "text": "The Q1 changelog is live.",
                      "thread_truncated": false,
                      "execute_at": 1829752200,
                      "state": "Scheduled"
                    }
                  ],
                  "count": 1
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "ascending",
            "in": "query",
            "required": false,
            "description": "Pass true to ask X for the oldest row first. Anything else, including omitting it, sends ascending=false, which is what X's own composer sends. The resulting order is X's and is not re-sorted here.",
            "schema": {
              "type": "boolean",
              "description": "Pass true to ask X for the oldest row first. Anything else, including omitting it, sends ascending=false, which is what X's own composer sends. The resulting order is X's and is not re-sorted here.",
              "example": "false"
            },
            "example": "false"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/article/create": {
      "post": {
        "operationId": "article-create",
        "summary": "Create Article",
        "description": "Start a new draft Article as the account behind your registered session, and return its entity id, ready for Update Title / Update Content. The draft is empty until you call those. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/create\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/create\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/create\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({}),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Start a new draft article. No request body required.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the draft was created."
                    },
                    "article": {
                      "type": "object",
                      "description": "The new draft article: id (base64 entity id, pass this to every other article/* call), rest_id (numeric string), title (null until set), preview_text, lifecycle (Draft), content_state ({ blocks: [], entityMap: [] }, empty until Update Content), cover_media (null), media_entities ([]), author (user profile object), created_at_secs, modified_at_secs, first_published_at_secs (null), visibility_setting (null), tweet_id (null until published), and public_url (null until published).",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": null,
                    "preview_text": "",
                    "lifecycle": "Draft",
                    "content_state": {
                      "blocks": [],
                      "entityMap": []
                    },
                    "cover_media": null,
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400000,
                    "first_published_at_secs": null,
                    "visibility_setting": null,
                    "tweet_id": null,
                    "public_url": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      }
    },
    "/article/update_title": {
      "post": {
        "operationId": "article-update-title",
        "summary": "Update Article Title",
        "description": "Set the title of an article you own, identified by its entity id. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/update_title\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", \"title\": \"Why we rebuilt our onboarding from scratch\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/update_title\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", \"title\": \"Why we rebuilt our onboarding from scratch\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/update_title\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", title: \"Why we rebuilt our onboarding from scratch\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Set the title on a draft or published article.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the title was updated."
                    },
                    "article": {
                      "type": "object",
                      "description": "The updated article, full shape: id, rest_id, title, preview_text, lifecycle, content_state, cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs, visibility_setting, tweet_id, public_url.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": "Why we rebuilt our onboarding from scratch",
                    "preview_text": "",
                    "lifecycle": "Draft",
                    "content_state": {
                      "blocks": [],
                      "entityMap": []
                    },
                    "cover_media": null,
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400120,
                    "first_published_at_secs": null,
                    "visibility_setting": null,
                    "tweet_id": null,
                    "public_url": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The article's base64 entity id, returned by article/create or article/list (the id field, not rest_id).",
                    "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                  },
                  "title": {
                    "type": "string",
                    "description": "The new title text.",
                    "example": "Why we rebuilt our onboarding from scratch"
                  }
                },
                "required": [
                  "id",
                  "title"
                ]
              }
            }
          }
        }
      }
    },
    "/article/update_cover_media": {
      "post": {
        "operationId": "article-update-cover-media",
        "summary": "Update Article Cover Image",
        "description": "Set the cover image on an article you own, identified by its entity id. This attaches media you have already uploaded; it does not upload anything itself, so call media/upload first and pass the media_id it returns. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/update_cover_media\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", \"media_id\": \"2088949698573090816\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/update_cover_media\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", \"media_id\": \"2088949698573090816\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/update_cover_media\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", media_id: \"2088949698573090816\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Attach an uploaded image as an article's cover.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the cover image was attached."
                    },
                    "article": {
                      "type": "object",
                      "description": "The updated article, full shape, with cover_media now populated: id, rest_id, title, preview_text, lifecycle, content_state, cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs, visibility_setting, tweet_id, public_url.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": "Why we rebuilt our onboarding from scratch",
                    "preview_text": "",
                    "lifecycle": "Draft",
                    "content_state": {
                      "blocks": [],
                      "entityMap": []
                    },
                    "cover_media": {
                      "id": "QXBpTWVkaWE6...",
                      "media_id": "2088949698573090816",
                      "media_key": "3_2088949698573090816",
                      "original_img_url": "https://pbs.twimg.com/media/....jpg",
                      "original_img_width": 1600,
                      "original_img_height": 900,
                      "color_palette": []
                    },
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400300,
                    "first_published_at_secs": null,
                    "visibility_setting": null,
                    "tweet_id": null,
                    "public_url": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The article's base64 entity id, returned by article/create or article/list (the id field, not rest_id).",
                    "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                  },
                  "media_id": {
                    "type": "string",
                    "description": "The media id returned by media/upload for the image you want to use as the cover.",
                    "example": "2088949698573090816"
                  },
                  "media_category": {
                    "type": "string",
                    "description": "X's media category for the upload. Defaults to DraftTweetImage, which is what the X article editor itself sends. Only override this if you know X expects a different category for your media.",
                    "example": "DraftTweetImage"
                  }
                },
                "required": [
                  "id",
                  "media_id"
                ]
              }
            }
          }
        }
      }
    },
    "/article/update_content": {
      "post": {
        "operationId": "article-update-content",
        "summary": "Update Article Content",
        "description": "Replace the body of an article you own with a new content_state, identified by its entity id. content_state is Draft.js editor-state JSON ({ blocks: [...], entityMap: [...] }) that you build client-side; in the shape the X Article editor produces. Blocks are forwarded with only key, text, type, data, entityRanges and inlineStyleRanges; X's schema rejects any other block field (depth included). Block types: unstyled, header-two, unordered-list-item, ordered-list-item, blockquote and atomic (a one-space block that carries an entity through entityRanges). entityMap is an ARRAY of { key, value: { type, mutability, data } }; entity data is snake_case on input and comes back camelCase: TWEET (an embedded post) { tweet_id }, MEDIA (an inline image) { caption, entity_key, media_items: [{ local_media_id, media_category: \"DraftTweetImage\", media_id }] } with media_id from media/upload, DIVIDER {}, LINK { url } over a text range, MARKDOWN { markdown } for tables. A field X does not know is refused with 422, reason validation_failed and the offending path in detail. Measured live 2026-09-18. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/update_content\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", \"content_state\": {\"blocks\":[{\"key\":\"a1b2c\",\"text\":\"Opening paragraph.\",\"type\":\"unstyled\",\"inlineStyleRanges\":[],\"entityRanges\":[]}],\"entityMap\":[]}}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/update_content\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", \"content_state\": {\"blocks\": [{\"key\": \"a1b2c\", \"text\": \"Opening paragraph.\", \"type\": \"unstyled\", \"inlineStyleRanges\": [], \"entityRanges\": []}], \"entityMap\": []}},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/update_content\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\", content_state: { blocks: [{ key: \"a1b2c\", text: \"Opening paragraph.\", type: \"unstyled\", inlineStyleRanges: [], entityRanges: [] }], entityMap: [] } }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Replace an article's body with a new Draft.js content_state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the content was updated."
                    },
                    "article": {
                      "type": "object",
                      "description": "The updated article, full shape: id, rest_id, title, preview_text, lifecycle, content_state (your new blocks/entityMap, echoed back), cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs, visibility_setting, tweet_id, public_url.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": "Why we rebuilt our onboarding from scratch",
                    "preview_text": "Opening paragraph.",
                    "lifecycle": "Draft",
                    "content_state": {
                      "blocks": [
                        {
                          "key": "a1b2c",
                          "text": "Opening paragraph.",
                          "type": "unstyled",
                          "inlineStyleRanges": [],
                          "entityRanges": []
                        }
                      ],
                      "entityMap": []
                    },
                    "cover_media": null,
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400240,
                    "first_published_at_secs": null,
                    "visibility_setting": null,
                    "tweet_id": null,
                    "public_url": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The article's base64 entity id, returned by article/create or article/list (the id field, not rest_id).",
                    "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                  },
                  "content_state": {
                    "type": "string",
                    "description": "The article body as a Draft.js content-state JSON object: { blocks: [...], entityMap: [...] }, sent as-is in the JSON request body, not as a string field. Blocks carry key, text, type, data, entityRanges, inlineStyleRanges only. entityMap is an array of { key, value: { type, mutability, data } } with snake_case data keys on input (tweet_id, media_items, local_media_id, media_category, media_id, entity_key, url, markdown).",
                    "example": "{\"blocks\":[{\"key\":\"a1b2c\",\"text\":\"Opening paragraph.\",\"type\":\"unstyled\",\"inlineStyleRanges\":[],\"entityRanges\":[]},{\"key\":\"em1\",\"text\":\" \",\"type\":\"atomic\",\"inlineStyleRanges\":[],\"entityRanges\":[{\"key\":0,\"offset\":0,\"length\":1}]},{\"key\":\"im1\",\"text\":\" \",\"type\":\"atomic\",\"inlineStyleRanges\":[],\"entityRanges\":[{\"key\":1,\"offset\":0,\"length\":1}]}],\"entityMap\":[{\"key\":\"0\",\"value\":{\"type\":\"TWEET\",\"mutability\":\"Immutable\",\"data\":{\"tweet_id\":\"2077572855194157402\"}}},{\"key\":\"1\",\"value\":{\"type\":\"MEDIA\",\"mutability\":\"Immutable\",\"data\":{\"caption\":\"\",\"entity_key\":\"img-1\",\"media_items\":[{\"local_media_id\":\"1\",\"media_category\":\"DraftTweetImage\",\"media_id\":\"2101008406014312448\"}]}}}]}"
                  }
                },
                "required": [
                  "id",
                  "content_state"
                ]
              }
            }
          }
        }
      }
    },
    "/article/publish": {
      "post": {
        "operationId": "article-publish",
        "summary": "Publish Article",
        "description": "Publish a draft article as the account behind your registered session, transitioning it from Draft to Published. WARNING: publishing posts a real, public announcement tweet on the account's timeline. This is not a preview or a private action, and it cannot be undone by re-editing the article: once published, the only way back is Delete Article, which unpublishes the article AND removes the announcement tweet. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/publish\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/publish\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/publish\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Publish a draft article. This posts a real, public announcement tweet.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the article was published."
                    },
                    "article": {
                      "type": "object",
                      "description": "The published article, full shape: id, rest_id, title, preview_text, lifecycle (now Published), content_state, cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs (now set), visibility_setting (now Public), tweet_id (the new announcement tweet's id), public_url (https://x.com/i/article/<rest_id>).",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": "Why we rebuilt our onboarding from scratch",
                    "preview_text": "Opening paragraph.",
                    "lifecycle": "Published",
                    "content_state": {
                      "blocks": [
                        {
                          "key": "a1b2c",
                          "text": "Opening paragraph.",
                          "type": "unstyled",
                          "inlineStyleRanges": [],
                          "entityRanges": []
                        }
                      ],
                      "entityMap": []
                    },
                    "cover_media": null,
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400400,
                    "first_published_at_secs": 1786400400,
                    "visibility_setting": "Public",
                    "tweet_id": "2086650300012345678",
                    "public_url": "https://x.com/i/article/2086650228950683648"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The article's base64 entity id, returned by article/create or article/list (the id field, not rest_id).",
                    "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                  },
                  "audience": {
                    "type": "string",
                    "description": "Who can read the published article. Defaults to \"Everyone\" (X's own dialog default) when omitted.",
                    "example": "Everyone"
                  },
                  "reply_control": {
                    "type": "string",
                    "description": "Who can reply to the announcement tweet. Defaults to \"Everyone\" (X's own dialog default) when omitted.",
                    "example": "Everyone"
                  },
                  "caption": {
                    "type": "string",
                    "description": "Optional caption text for the announcement tweet, up to 256 characters.",
                    "example": "New post: why we rebuilt our onboarding from scratch."
                  }
                },
                "required": [
                  "id"
                ]
              }
            }
          }
        }
      }
    },
    "/article/unpublish": {
      "post": {
        "operationId": "article-unpublish",
        "summary": "Unpublish Article",
        "description": "Revert a Published article back to Draft, identified by its entity id. The announcement tweet the original publish posted is left in place; use Delete Article to remove it too. X server-validates this transition and returns a 422 (invalid_lifecycle) if the article is not currently Published. Requires a registered session. Billed at $0.0016 per call. Cost: $0.0016 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0016,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/unpublish\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/unpublish\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/unpublish\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Revert a published article back to Draft. The announcement tweet is left in place.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when the article was reverted to Draft."
                    },
                    "article": {
                      "type": "object",
                      "description": "The reverted article, full shape: id, rest_id, title, preview_text, lifecycle (back to Draft), content_state, cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs, visibility_setting, tweet_id, public_url.",
                      "additionalProperties": true
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": "Why we rebuilt our onboarding from scratch",
                    "preview_text": "Opening paragraph.",
                    "lifecycle": "Draft",
                    "content_state": {
                      "blocks": [
                        {
                          "key": "a1b2c",
                          "text": "Opening paragraph.",
                          "type": "unstyled",
                          "inlineStyleRanges": [],
                          "entityRanges": []
                        }
                      ],
                      "entityMap": []
                    },
                    "cover_media": null,
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400500,
                    "first_published_at_secs": 1786400400,
                    "visibility_setting": null,
                    "tweet_id": "2086650300012345678",
                    "public_url": null
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The article's base64 entity id, returned by article/create or article/list (the id field, not rest_id).",
                    "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                  }
                },
                "required": [
                  "id"
                ]
              }
            }
          }
        }
      }
    },
    "/article/get": {
      "get": {
        "operationId": "article-get",
        "summary": "Get Article",
        "description": "Read an article's full content. Two mutually exclusive forms: id or url (the announcement tweet id or status URL) for a public read that needs no session, works for Published articles only. Or article_id (the article's own entity id, from Article Create or Article List) for an owner-only read that requires a registered session and also works for your own Drafts. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/article/get?id=2086650300012345678\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/article/get\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"id\": \"2086650300012345678\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/article/get\");\nurl.search = new URLSearchParams({ id: \"2086650300012345678\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Read an article via its announcement tweet, or your own via its entity id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "Echo of the announcement tweet id that was resolved from your id/url."
                    },
                    "article": {
                      "type": "object",
                      "description": "The published article, or null if no article was found at that tweet id/URL. Full shape when present: id, rest_id, title, preview_text, lifecycle (Published), content_state, cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs, visibility_setting (Public), tweet_id, public_url.",
                      "additionalProperties": true,
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "id": "2086650300012345678",
                  "article": {
                    "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                    "rest_id": "2086650228950683648",
                    "title": "Why we rebuilt our onboarding from scratch",
                    "preview_text": "Opening paragraph.",
                    "lifecycle": "Published",
                    "content_state": {
                      "blocks": [
                        {
                          "key": "a1b2c",
                          "text": "Opening paragraph.",
                          "type": "unstyled",
                          "inlineStyleRanges": [],
                          "entityRanges": []
                        }
                      ],
                      "entityMap": []
                    },
                    "cover_media": null,
                    "media_entities": [],
                    "author": {
                      "id": "44196397",
                      "username": "elonmusk",
                      "name": "Elon Musk"
                    },
                    "created_at_secs": 1786400000,
                    "modified_at_secs": 1786400400,
                    "first_published_at_secs": 1786400400,
                    "visibility_setting": "Public",
                    "tweet_id": "2086650300012345678",
                    "public_url": "https://x.com/i/article/2086650228950683648"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "PUBLIC form. The article's announcement tweet id, or its status URL. Provide exactly one of id, url, or article_id.",
            "schema": {
              "type": "string",
              "description": "PUBLIC form. The article's announcement tweet id, or its status URL. Provide exactly one of id, url, or article_id.",
              "example": "2086650300012345678"
            },
            "example": "2086650300012345678"
          },
          {
            "name": "url",
            "in": "query",
            "required": false,
            "description": "PUBLIC form. Status URL of the article's announcement tweet, for example https://x.com/i/status/2086650300012345678. Provide exactly one of id, url, or article_id.",
            "schema": {
              "type": "string",
              "description": "PUBLIC form. Status URL of the article's announcement tweet, for example https://x.com/i/status/2086650300012345678. Provide exactly one of id, url, or article_id.",
              "example": "https://x.com/i/status/2086650300012345678"
            },
            "example": "https://x.com/i/status/2086650300012345678"
          },
          {
            "name": "article_id",
            "in": "query",
            "required": false,
            "description": "OWNER-ONLY form. The article's own entity id, from Article Create or Article List. Requires a registered session. Provide exactly one of id, url, or article_id.",
            "schema": {
              "type": "string",
              "description": "OWNER-ONLY form. The article's own entity id, from Article Create or Article List. Requires a registered session. Provide exactly one of id, url, or article_id.",
              "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
            },
            "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/article/list": {
      "get": {
        "operationId": "article-list",
        "summary": "List Articles",
        "description": "List the caller's own articles at one lifecycle at a time: Draft or Published (default Draft). X exposes no combined view across both, so call it twice, once per lifecycle, to see everything. Cursor-paginated. Requires a registered session. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/article/list?lifecycle=draft&count=20\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/article/list\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={\"lifecycle\": \"draft\", \"count\": 20},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/article/list\");\nurl.search = new URLSearchParams({ lifecycle: \"draft\", count: \"20\" }).toString();\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Paginate all pages",
            "source": "# Walk every page until the collection array comes back empty.\ncursor=\"\"\nwhile : ; do\n  resp=$(curl -s \"https://api.twitterapis.com/twitter/article/list?lifecycle=draft&cursor=$cursor\" \\\n    -H \"Authorization: Bearer $TWITTERAPIS_KEY\")\n  count=$(echo \"$resp\" | jq '.articles | length')\n  [ \"$count\" -eq 0 ] && break\n  echo \"$resp\" | jq '.articles[]'\n  cursor=$(echo \"$resp\" | jq -r '.next_cursor // \"\"')\n  [ -z \"$cursor\" ] || [ \"$cursor\" = \"null\" ] && break\ndone"
          },
          {
            "lang": "python",
            "label": "Python: Paginate all pages",
            "source": "import os\nimport requests\n\ndef paginate():\n    cursor = \"\"\n    while True:\n        resp = requests.get(\n            \"https://api.twitterapis.com/twitter/article/list\",\n            headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n            params={\"lifecycle\": \"draft\", \"cursor\": cursor},\n        )\n        resp.raise_for_status()\n        data = resp.json()\n        items = data.get(\"articles\", [])\n        if not items:\n            break\n        for item in items:\n            yield item\n        cursor = data.get(\"next_cursor\")\n        if not cursor:\n            break\n\nfor item in paginate():\n    print(item)"
          },
          {
            "lang": "js",
            "label": "JavaScript: Paginate all pages",
            "source": "const params = { lifecycle: \"draft\", cursor: \"\" };\n\nwhile (true) {\n  const url = new URL(\"https://api.twitterapis.com/twitter/article/list\");\n  url.search = new URLSearchParams(params).toString();\n  const resp = await fetch(url, {\n    headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n  });\n  const data = await resp.json();\n  const items = data.articles ?? [];\n  if (items.length === 0) break;\n  for (const item of items) console.log(item);\n  if (!data.next_cursor) break;\n  params.cursor = data.next_cursor;\n}"
          }
        ],
        "responses": {
          "200": {
            "description": "List your own articles, filtered by lifecycle (draft or published).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Number of articles returned in this page."
                    },
                    "next_cursor": {
                      "type": "string",
                      "description": "Opaque cursor for the next page, or null when the list ends.",
                      "nullable": true
                    },
                    "articles": {
                      "type": "array",
                      "description": "Articles at the requested lifecycle, for this page. Each item: id, rest_id, title, preview_text, lifecycle, content_state, cover_media, media_entities, author, created_at_secs, modified_at_secs, first_published_at_secs, visibility_setting, tweet_id, public_url.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                },
                "example": {
                  "count": 1,
                  "next_cursor": null,
                  "articles": [
                    {
                      "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4",
                      "rest_id": "2086650228950683648",
                      "title": "Why we rebuilt our onboarding from scratch",
                      "preview_text": "",
                      "lifecycle": "Draft",
                      "content_state": {
                        "blocks": [],
                        "entityMap": []
                      },
                      "cover_media": null,
                      "media_entities": [],
                      "author": {
                        "id": "44196397",
                        "username": "elonmusk",
                        "name": "Elon Musk"
                      },
                      "created_at_secs": 1786400000,
                      "modified_at_secs": 1786400120,
                      "first_published_at_secs": null,
                      "visibility_setting": null,
                      "tweet_id": null,
                      "public_url": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "lifecycle",
            "in": "query",
            "required": false,
            "description": "Which set of articles to list: \"draft\" or \"published\". Defaults to \"draft\".",
            "schema": {
              "type": "string",
              "description": "Which set of articles to list: \"draft\" or \"published\". Defaults to \"draft\".",
              "example": "draft"
            },
            "example": "draft"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Items per page. Defaults to 20; capped at 100.",
            "schema": {
              "type": "integer",
              "description": "Items per page. Defaults to 20; capped at 100.",
              "example": "20"
            },
            "example": "20"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Pagination cursor from a previous response's next_cursor.",
            "schema": {
              "type": "string",
              "description": "Pagination cursor from a previous response's next_cursor."
            }
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/article/delete": {
      "post": {
        "operationId": "article-delete",
        "summary": "Delete Article",
        "description": "Delete an article you own, identified by its entity id. A Draft is hard-deleted directly. A Published article is unpublished first (reverting it to Draft) and then its announcement tweet is deleted, which is what makes it stop being publicly reachable, a two-step reversal for Publish Article. Pass lifecycle and tweet_id as optional fast-path hints when you already know them (from a prior list/create response); omitted, the server resolves them itself by scanning your Draft then Published lists, costing a couple of extra round trips. Requires a registered session. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Articles"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/article/delete\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/article/delete\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id\": \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/article/delete\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id: \"QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Delete an article. A draft is hard-deleted; a published article is unpublished, then its announcement tweet is removed too.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "Mirrors deleted."
                    },
                    "deleted": {
                      "type": "boolean",
                      "description": "True when the delete completed: the draft was hard-deleted, or the published article was unpublished and its announcement tweet removed."
                    },
                    "id": {
                      "type": "string",
                      "description": "Echo of the article id you deleted."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": true,
                  "id": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id": {
                    "type": "string",
                    "description": "The article's base64 entity id, returned by article/create or article/list (the id field, not rest_id).",
                    "example": "QXJ0aWNsZUVudGl0eToyMDg2NjUwMjI4OTUwNjgzNjQ4"
                  },
                  "lifecycle": {
                    "type": "string",
                    "description": "Fast-path hint: \"draft\" or \"published\". When you already know the article's lifecycle (e.g. from a prior article/list or article/create response), pass it to skip a lookup. Omit it and the server resolves it by scanning your own Draft then Published lists.",
                    "example": "draft"
                  },
                  "tweet_id": {
                    "type": "string",
                    "description": "Fast-path hint: the announcement tweet id, for a PUBLISHED article only. Omit it and the server resolves it from the article's own metadata when lifecycle resolves to published.",
                    "example": "2086650300012345678"
                  }
                },
                "required": [
                  "id"
                ]
              }
            }
          }
        }
      }
    },
    "/grok/chat": {
      "post": {
        "operationId": "grok-chat",
        "summary": "Grok Chat",
        "description": "Send a prompt to X's in-app Grok as the account behind your session and get back one complete JSON document: the answer text, the web pages Grok cited while writing it, and the searches it ran to find them. Grok reads X in real time, so it answers about posts and accounts a general-purpose model has never seen. Send a bare post URL as the message and you get a structured summary of that post instead, including what Grok reads out of its attached images. Billed at $0.0040 per answer. Cost: $0.0040 per call.",
        "tags": [
          "Grok"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.004,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/grok/chat\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"message\": \"What are people on X saying about the WWDC keynote today?\", \"mode\": \"auto\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/grok/chat\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"message\": \"What are people on X saying about the WWDC keynote today?\", \"mode\": \"auto\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/grok/chat\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ message: \"What are people on X saying about the WWDC keynote today?\", mode: \"auto\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          },
          {
            "lang": "bash",
            "label": "cURL: Continue a conversation",
            "source": "# We store nothing, so turn 2 replays turn 1 and passes the conversation id back.\ncurl -X POST \"https://api.twitterapis.com/twitter/grok/chat\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"conversation_id\": \"2088999211077345534\",\n    \"messages\": [\n      { \"role\": \"user\", \"content\": \"What are people on X saying about the WWDC keynote today?\" },\n      { \"role\": \"assistant\", \"content\": \"Reaction is running positive on the on-device model work.\" }\n    ],\n    \"message\": \"Which developer accounts are driving that?\"\n  }'"
          },
          {
            "lang": "python",
            "label": "Python: Continue a conversation",
            "source": "import os\nimport requests\n\nKEY = os.environ[\"TWITTERAPIS_KEY\"]\nURL = \"https://api.twitterapis.com/twitter/grok/chat\"\nHEADERS = {\"Authorization\": f\"Bearer {KEY}\"}\n\nfirst = requests.post(\n    URL,\n    headers=HEADERS,\n    json={\"message\": \"What are people on X saying about the WWDC keynote today?\"},\n)\nfirst.raise_for_status()\nturn1 = first.json()\n\n# Nothing is stored on our side, so you carry the history forward yourself.\nsecond = requests.post(\n    URL,\n    headers=HEADERS,\n    json={\n        \"conversation_id\": turn1[\"conversation_id\"],\n        \"messages\": [\n            {\"role\": \"user\", \"content\": \"What are people on X saying about the WWDC keynote today?\"},\n            {\n                \"role\": \"assistant\",\n                \"content\": turn1[\"answer\"],\n                \"response_id\": turn1[\"response_id\"],\n                \"parent_response_id\": turn1[\"user_response_id\"],\n            },\n        ],\n        \"message\": \"Which developer accounts are driving that?\",\n    },\n)\nsecond.raise_for_status()\nprint(second.json()[\"answer\"])"
          },
          {
            "lang": "js",
            "label": "JavaScript: Continue a conversation",
            "source": "const URL = \"https://api.twitterapis.com/twitter/grok/chat\";\nconst headers = {\n  Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n  \"Content-Type\": \"application/json\",\n};\n\nconst first = await (\n  await fetch(URL, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify({ message: \"What are people on X saying about the WWDC keynote today?\" }),\n  })\n).json();\n\n// Nothing is stored on our side, so you carry the history forward yourself.\nconst second = await (\n  await fetch(URL, {\n    method: \"POST\",\n    headers,\n    body: JSON.stringify({\n      conversation_id: first.conversation_id,\n      messages: [\n        { role: \"user\", content: \"What are people on X saying about the WWDC keynote today?\" },\n        {\n          role: \"assistant\",\n          content: first.answer,\n          response_id: first.response_id,\n          parent_response_id: first.user_response_id,\n        },\n      ],\n      message: \"Which developer accounts are driving that?\",\n    }),\n  })\n).json();\n\nconsole.log(second.answer);"
          }
        ],
        "responses": {
          "200": {
            "description": "Ask X's Grok a question and get the answer plus the pages it cited.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "description": "True when Grok returned answer text. A call that produced no readable answer does not reach you as ok: false, it returns 422 and is not billed."
                    },
                    "conversation_id": {
                      "type": "string",
                      "description": "The conversation this turn belongs to, whether you supplied it or we opened it. Pass it back on the next call to continue. Null only if X returned no id.",
                      "nullable": true
                    },
                    "response_id": {
                      "type": "string",
                      "description": "The id of GROK's turn (X's agentChatItemId). Pass it back as response_id on that turn inside messages[] to thread the next request exactly."
                    },
                    "user_response_id": {
                      "type": "string",
                      "description": "The id of the turn YOU just sent (X's userChatItemId). Its counterpart to response_id when you replay history."
                    },
                    "answer": {
                      "type": "string",
                      "description": "Grok's answer as one complete string. Reasoning and tool chatter are stripped out; this is the reply a person would read."
                    },
                    "citations": {
                      "type": "array",
                      "description": "The pages Grok read while answering, each { url, domain, title, snippet }. domain is derived from url on our side; X does not send it. title is NOT always present and comes back null when X omits it, so do not filter on it. One answer can cite results from several searches: they are merged in the order they arrived and de-duplicated by url, so you get every distinct source once.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "citation_count": {
                      "type": "integer",
                      "description": "Length of citations, after de-duplication. Convenient for the common case of checking whether a domain appeared at all."
                    },
                    "tool_calls": {
                      "type": "array",
                      "description": "What Grok actually ran to answer, each { id, tool, args }. The observed tool is web_search, whose args carry the query string and the number of results asked for. This is the search Grok chose, not the prompt you sent.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "requested_model": {
                      "type": "string",
                      "description": "The model id we asked X for, derived from your mode: grok-4-auto, grok-3-latest, or grok-4."
                    },
                    "model": {
                      "type": "string",
                      "description": "The model that ACTUALLY answered. auto resolves on X's side, so asking for grok-4-auto commonly comes back as grok-4. Read this one when you care which model produced the text."
                    },
                    "mode": {
                      "type": "string",
                      "description": "The mode this call ran in: auto, fast, or expert. Echoed back so an unrecognised mode value is visible rather than silent."
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "conversation_id": "2088999211077345534",
                  "response_id": "2089001859230978049",
                  "user_response_id": "2089001859230978048",
                  "answer": "Reaction on X is running positive on the on-device model work and negative on the pricing. The liveblog thread and several developer accounts flag the new background-execution API as the change most people expect to ship against first.",
                  "citations": [
                    {
                      "url": "https://x.com/verge/status/2089000000000000001",
                      "domain": "x.com",
                      "title": "The Verge on X",
                      "snippet": "Everything announced in the keynote, in order."
                    },
                    {
                      "url": "https://www.theverge.com/wwdc-keynote-liveblog",
                      "domain": "theverge.com",
                      "title": "WWDC keynote liveblog",
                      "snippet": "Live updates as the keynote runs."
                    },
                    {
                      "url": "https://news.ycombinator.com/item?id=41234567",
                      "domain": "news.ycombinator.com",
                      "title": null,
                      "snippet": "Developer discussion of the background-execution API."
                    }
                  ],
                  "citation_count": 3,
                  "tool_calls": [
                    {
                      "id": "5f2b8c1a-9d34-4c77-b0e2-6a1f7c3d8e90",
                      "tool": "web_search",
                      "args": {
                        "query": "WWDC keynote reaction developers",
                        "num_results": "15"
                      }
                    }
                  ],
                  "requested_model": "grok-4-auto",
                  "model": "grok-4",
                  "mode": "auto"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "The prompt. A question, an instruction, or a bare post URL (https://x.com/<user>/status/<id>), which returns a summary of that post. Required unless you send messages[] whose last entry is a user turn. Maximum 20,000 characters; longer prompts are rejected with 400 before any Grok call is made, so an over-length prompt never costs you anything.",
                    "example": "What are people on X saying about the WWDC keynote today?"
                  },
                  "messages": {
                    "type": "string",
                    "description": "JSON array of prior turns, oldest first, sent in the request body. Each entry takes either { role: \"user\" | \"assistant\", content } or X's own { sender: 1 | 2, message }, where 1 is you and 2 is Grok, plus the optional response_id and parent_response_id we returned on earlier replies. Anything not explicitly marked as Grok is treated as a user turn. If you omit message, the last entry must be a user turn and becomes the prompt. Maximum 100 prior turns.",
                    "example": "[{\"role\":\"user\",\"content\":\"Who won the game?\"},{\"role\":\"assistant\",\"content\":\"The Celtics, 112-108.\"}]"
                  },
                  "mode": {
                    "type": "string",
                    "description": "auto, fast, or expert. auto lets X pick the model, fast is grok-3-latest, expert is grok-4 and thinks for longer. The raw model ids grok-3-latest and grok-4 are accepted as aliases. Anything unrecognised falls back to auto, which is also the default.",
                    "example": "auto"
                  },
                  "conversation_id": {
                    "type": "string",
                    "description": "Continue an existing conversation, using the conversation_id from an earlier reply. Omit it and we open a fresh conversation for you and return its id.",
                    "example": "2088999211077345534"
                  },
                  "image_count": {
                    "type": "integer",
                    "description": "How many images Grok may generate if the prompt calls for it. Clamped to 0 through 4; the default is 4, which is X's own. Set it to 0 for a text-only answer.",
                    "example": "4"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/grok/config": {
      "get": {
        "operationId": "grok-config",
        "summary": "Grok Config",
        "description": "Read the Grok settings for the account behind your session: whether X has enabled Grok for it, the reasons if not, and the model options it is allowed to choose between. Grok eligibility belongs to the X account rather than to us, so this runs as your own session. Call it once before your first chat request. Billed at $0.0008 per call. Cost: $0.0008 per call.",
        "tags": [
          "Grok"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0.0008,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/grok/config\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/grok/config\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/grok/config\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Check whether your account can use Grok, and which models it may pick.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "eligible": {
                      "type": "boolean",
                      "description": "True when X has Grok enabled for the account behind your session. Read it together with ineligible_reasons: false with an empty reasons array means we could not read the config, not that X refused."
                    },
                    "ineligible_reasons": {
                      "type": "array",
                      "description": "X's own reason strings, passed through unchanged because we cannot improve on X's reason for refusing its own feature. Empty when the account is eligible, and also empty in the could-not-read case above.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "free_access_enabled": {
                      "type": "boolean",
                      "description": "True when X is currently granting this account Grok access without a paid tier."
                    },
                    "default_mode": {
                      "type": "string",
                      "description": "The mode X has set as this account's default, in X's own spelling, for example Normal. This is X's label, not one of the auto/fast/expert values Grok Chat takes."
                    },
                    "default_model_option_id": {
                      "type": "string",
                      "description": "The model id X defaults this account to, for example grok-4-auto."
                    },
                    "grok_version": {
                      "type": "string",
                      "description": "The Grok version string X reports for this account."
                    },
                    "modes": {
                      "type": "object",
                      "description": "The map Grok Chat's mode parameter uses: { auto: grok-4-auto, fast: grok-3-latest, expert: grok-4 }. Constant, returned here so you do not have to keep the mapping table in your own code.",
                      "additionalProperties": true
                    },
                    "model_options": {
                      "type": "array",
                      "description": "One entry per model X offers this account: id, name (Auto, Fast, Expert), description, mode (MODEL_MODE_AUTO, MODEL_MODE_FAST or MODEL_MODE_EXPERT), is_enabled, is_analyze_enabled, is_enhance_enabled. Empty when the config could not be read.",
                      "items": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                },
                "example": {
                  "eligible": true,
                  "ineligible_reasons": [],
                  "free_access_enabled": false,
                  "default_mode": "Normal",
                  "default_model_option_id": "grok-4-auto",
                  "grok_version": "grok-4-auto",
                  "modes": {
                    "auto": "grok-4-auto",
                    "fast": "grok-3-latest",
                    "expert": "grok-4"
                  },
                  "model_options": [
                    {
                      "id": "grok-4-auto",
                      "name": "Auto",
                      "description": "Picks the model that suits the question.",
                      "mode": "MODEL_MODE_AUTO",
                      "is_enabled": true,
                      "is_analyze_enabled": false,
                      "is_enhance_enabled": false
                    },
                    {
                      "id": "grok-3-latest",
                      "name": "Fast",
                      "description": "Answers quickly.",
                      "mode": "MODEL_MODE_FAST",
                      "is_enabled": true,
                      "is_analyze_enabled": true,
                      "is_enhance_enabled": true
                    },
                    {
                      "id": "grok-4",
                      "name": "Expert",
                      "description": "Thinks for longer before answering.",
                      "mode": "MODEL_MODE_EXPERT",
                      "is_enabled": true,
                      "is_analyze_enabled": false,
                      "is_enhance_enabled": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "insufficient_credits",
                  "message": "Your balance is exhausted. Top up your credits to continue."
                }
              }
            }
          },
          "403": {
            "description": "Forbidden",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "forbidden",
                  "message": "X refused this resource for the acting account: on a read, the account is not a participant in the DM thread, the target is protected or has blocked it, or the session was attestation-blocked for calling from a datacenter or rotating IP; on a write, the account is not authorized for the action or has no logged-in session. The credentials are still valid, so do not re-register."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/monitor": {
      "post": {
        "operationId": "monitor-post",
        "summary": "Create Monitor",
        "description": "Start watching an X account. Every new post from that account is delivered, HMAC-signed, to your registered webhook(s) on a shared poll interval. Free: monitor creation is account administration, not a metered read. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/monitor\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"handle\": \"elonmusk\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/monitor\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"handle\": \"elonmusk\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/monitor\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ handle: \"elonmusk\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "201": {
            "description": "Watch an X account for new posts and push them to your webhook(s).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The new monitor's id, used in the update/delete/health routes below."
                    },
                    "handle": {
                      "type": "string",
                      "description": "The normalized (lowercased, @ stripped) handle being watched."
                    },
                    "subject": {
                      "type": "string",
                      "description": "Internal query expression for this monitor, currently always from:<handle>."
                    },
                    "kind": {
                      "type": "string",
                      "description": "Monitor type. Currently always \"account\"."
                    },
                    "status": {
                      "type": "string",
                      "description": "\"active\" or \"paused\"."
                    },
                    "webhook_ids": {
                      "type": "array",
                      "description": "The restriction set passed at create, or null for the default (deliver to all).",
                      "items": {
                        "type": "string"
                      },
                      "nullable": true
                    },
                    "domain_filter": {
                      "type": "string",
                      "description": "The normalized domain filter passed at create, or null if none was set (deliver every new post).",
                      "nullable": true
                    },
                    "include_replies": {
                      "type": "boolean",
                      "description": "Whether replies are delivered as well as top-level posts. Echoed back from what was actually stored, not from what was requested, so the caller can see the applied value."
                    },
                    "tier": {
                      "type": "string",
                      "description": "The wire-facing poll tier the monitor was created on: `standard` or `fast`. Defaults to `standard` when the create body omits it."
                    },
                    "poll_interval_ms": {
                      "type": "integer",
                      "description": "Current poll interval in milliseconds. Not yet a published SLA; subject to change."
                    },
                    "poll_interval_note": {
                      "type": "string",
                      "description": "Caveat text returned alongside the interval: it is NOT a published SLA and is subject to change."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 creation timestamp."
                    }
                  }
                },
                "example": {
                  "id": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11",
                  "handle": "elonmusk",
                  "subject": "from:elonmusk",
                  "kind": "account",
                  "status": "active",
                  "webhook_ids": null,
                  "domain_filter": null,
                  "include_replies": true,
                  "tier": "standard",
                  "poll_interval_ms": 120000,
                  "poll_interval_note": "NOT a published SLA yet, subject to change.",
                  "created_at": "2026-08-13T10:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "The X username to watch, without the @.",
                    "example": "elonmusk"
                  },
                  "webhook_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of webhook ids (from POST /twitter/webhook) to restrict delivery to. Omit to deliver to every active webhook on the account, the default.",
                    "example": []
                  },
                  "domain_filter": {
                    "type": "string",
                    "description": "Optional. A bare hostname (`example.com`) or a full URL (`https://example.com/blog`) to restrict delivery to posts that link to that host or a subdomain of it. Normalized server-side: lowercased, scheme/path/query/fragment/leading www./trailing :port stripped. Omit for no filter (deliver every new post, the default). Rejected with 400 if what remains after normalization is not a valid hostname shape.",
                    "example": "example.com"
                  },
                  "include_replies": {
                    "type": "boolean",
                    "description": "Optional. `true` to deliver the account's replies as well as its own posts, which is the default and what every monitor has always done; `false` to hold replies back and deliver only the account's own posts. Must be a real boolean if provided: the string `\"false\"` and the number `0` are rejected with a 400 rather than coerced, because coercing them would quietly give you the opposite of what you typed and the wrong answer here is invisible, it looks exactly like the account not having posted. `null` is a 400 too; there is no clear-it state, since `true` already is the unrestricted value.",
                    "example": "false"
                  }
                },
                "required": [
                  "handle"
                ]
              }
            }
          }
        }
      },
      "get": {
        "operationId": "monitor-get",
        "summary": "List Monitors",
        "description": "Returns every non-deleted monitor on your account, most recently created first. Each entry includes its id, subject, status, and delivery configuration, so you can enumerate what already exists before creating, updating, or deleting a specific monitor. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/monitor\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/monitor\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/monitor\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List every monitor on your account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "monitors": {
                      "type": "string",
                      "description": "Array of monitor objects: id, subject, kind, status, degraded, events_possibly_missed, webhook_ids, domain_filter, created_at."
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of monitors returned."
                    }
                  }
                },
                "example": {
                  "monitors": [
                    {
                      "id": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11",
                      "subject": "from:elonmusk",
                      "kind": "account",
                      "status": "active",
                      "degraded": false,
                      "events_possibly_missed": 0,
                      "webhook_ids": null,
                      "domain_filter": null,
                      "created_at": "2026-08-13T10:00:00.000Z"
                    }
                  ],
                  "count": 1
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      }
    },
    "/monitor/{id}": {
      "post": {
        "operationId": "monitor-id-post",
        "summary": "Update Monitor",
        "description": "Partial update of an existing monitor. Send status to pause or resume it, webhook_ids to change which webhooks receive its events, or both in the same call (applied atomically). Resuming a paused monitor re-runs the same capacity and per-account cap checks as creating a new one, since it adds load back to monitoring capacity. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/monitor/{id}\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"status\": \"paused\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/monitor/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"status\": \"paused\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/monitor/{id}\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ status: \"paused\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Pause, resume, or change which webhooks a monitor delivers to.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The monitor's id."
                    },
                    "subject": {
                      "type": "string",
                      "description": "The monitor's query expression, e.g. from:elonmusk."
                    },
                    "kind": {
                      "type": "string",
                      "description": "Monitor type."
                    },
                    "status": {
                      "type": "string",
                      "description": "\"active\" or \"paused\" after the update."
                    },
                    "degraded": {
                      "type": "boolean",
                      "description": "Whether monitoring is currently serving this monitor slower than the published interval."
                    },
                    "events_possibly_missed": {
                      "type": "integer",
                      "description": "Running count of possibly-missed events, never reset by an update."
                    },
                    "webhook_ids": {
                      "type": "array",
                      "description": "The current restriction set, or null for the default (deliver to all).",
                      "items": {
                        "type": "string"
                      },
                      "nullable": true
                    },
                    "domain_filter": {
                      "type": "string",
                      "description": "The current normalized domain filter after this update, or null if none is set (deliver every new post).",
                      "nullable": true
                    },
                    "updated_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp of this update."
                    }
                  }
                },
                "example": {
                  "id": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11",
                  "subject": "from:elonmusk",
                  "kind": "account",
                  "status": "paused",
                  "degraded": false,
                  "events_possibly_missed": 0,
                  "webhook_ids": null,
                  "domain_filter": null,
                  "updated_at": "2026-08-13T11:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "description": "\"active\" to resume, \"paused\" to pause. Omit to leave status unchanged.",
                    "example": "paused"
                  },
                  "webhook_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of webhook ids to restrict delivery to. Send an empty array to clear the restriction back to \"deliver to every active webhook\". Omit the field entirely to leave it unchanged.",
                    "example": []
                  },
                  "domain_filter": {
                    "type": "string",
                    "description": "A bare hostname or full URL to restrict delivery to. Send null or an empty string to clear an existing filter (deliver every new post again). Omit the field entirely to leave it unchanged. Same normalization and hostname-shape validation as Create Monitor.",
                    "example": "example.com"
                  },
                  "include_replies": {
                    "type": "boolean",
                    "description": "`true` to deliver the account's replies as well as its own posts, `false` to hold replies back. Omit the field entirely to leave it unchanged. Same boolean-only validation as Create Monitor: a non-boolean is a 400 rather than a coercion.",
                    "example": "false"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "delete": {
        "operationId": "monitor-id-delete",
        "summary": "Delete Monitor",
        "description": "Soft-deletes the monitor: it stops polling immediately and disappears from List Monitors, but its delivery history is retained rather than cascade-deleted. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.twitterapis.com/twitter/monitor/{id}\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.delete(\n    \"https://api.twitterapis.com/twitter/monitor/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/monitor/{id}\", {\n  method: \"DELETE\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Stop watching an account and remove the monitor.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "description": "True on success."
                    },
                    "id": {
                      "type": "string",
                      "description": "The deleted monitor's id."
                    }
                  }
                },
                "example": {
                  "deleted": true,
                  "id": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/monitor/{id}/health": {
      "get": {
        "operationId": "monitor-id-health",
        "summary": "Monitor Health",
        "description": "Returns a single monitor's current status, degradation flag, and cursor position, for building your own health dashboard. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/monitor/{id}/health\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/monitor/{id}/health\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/monitor/{id}/health\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Check one monitor's poll status and last-seen tweet id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The monitor's id."
                    },
                    "status": {
                      "type": "string",
                      "description": "\"active\" or \"paused\"."
                    },
                    "degraded": {
                      "type": "boolean",
                      "description": "Whether monitoring is currently serving this monitor slower than the published interval."
                    },
                    "poll_interval_ms": {
                      "type": "integer",
                      "description": "Current poll interval in milliseconds."
                    },
                    "events_possibly_missed": {
                      "type": "integer",
                      "description": "Running count of possibly-missed events."
                    },
                    "last_tweet_id": {
                      "type": "string",
                      "description": "The most recent tweet id this monitor has delivered, or null before its first poll.",
                      "nullable": true
                    },
                    "last_poll_at": {
                      "type": "string",
                      "description": "ISO 8601 timestamp of the most recent poll, or null before the first one.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "id": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11",
                  "status": "active",
                  "degraded": false,
                  "poll_interval_ms": 120000,
                  "events_possibly_missed": 0,
                  "last_tweet_id": "1899999999999999999",
                  "last_poll_at": "2026-08-13T11:58:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/monitor/health": {
      "get": {
        "operationId": "monitor-health",
        "summary": "Account Monitor Health",
        "description": "Returns a single-call summary of your entire monitoring setup: overall status, how many of your monitors are active vs paused, and how many delivery attempts in the last 24 hours were pending, delivered, or failed. Distinct from Monitor Health above, which reports one monitor's cursor state, not your whole account's. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/monitor/health\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/monitor/health\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/monitor/health\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Account-wide monitoring rollup: service status, active/paused counts, 24h delivery outcomes, in one call.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "\"operational\", or \"degraded\" if any of your ACTIVE monitors is currently being served slower than the published poll interval. A degraded paused monitor never flips this, since nothing is polling it."
                    },
                    "monitors": {
                      "type": "string",
                      "description": "Counts across every non-deleted monitor you own: active, paused, and total."
                    },
                    "deliveries_24h": {
                      "type": "string",
                      "description": "Counts across every delivery attempt created in the last 24 hours: pending (still queued or retrying), delivered (succeeded), and failed (dead-lettered after retries were exhausted)."
                    }
                  }
                },
                "example": {
                  "status": "operational",
                  "monitors": {
                    "active": 3,
                    "paused": 1,
                    "total": 4
                  },
                  "deliveries_24h": {
                    "pending": 2,
                    "delivered": 150,
                    "failed": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      }
    },
    "/monitor/deliveries": {
      "get": {
        "operationId": "monitor-deliveries",
        "summary": "Monitor Deliveries",
        "description": "Returns your most recent monitor delivery events, most recent first, each carrying the actual measured lag: detected_lag_ms is X's own post timestamp subtracted from the moment our scheduler enqueued the delivery (i.e. real detection latency, bound by the current poll interval), and delivery_lag_ms is the separate queue-to-webhook-POST time. Either can be null for an older event whose payload predates this field. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/monitor/deliveries\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/monitor/deliveries\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/monitor/deliveries\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Recent delivery events across every monitor, with real detection and delivery latency.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deliveries": {
                      "type": "string",
                      "description": "Array of delivery events: id, monitor_id, tweet_id, status, tweet_created_at, detected_at, delivered_at, detected_lag_ms, delivery_lag_ms, total_lag_ms, attempts, last_status_code, last_error."
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of events returned."
                    }
                  }
                },
                "example": {
                  "deliveries": [
                    {
                      "id": "79a94efd-8b6c-46f7-afa5-1fecdf1250a1",
                      "monitor_id": "bd964ae0-7763-4dd6-9295-233d9badf6f9",
                      "tweet_id": "2087910515246784773",
                      "status": "delivered",
                      "tweet_created_at": "Thu Aug 13 14:33:52 +0000 2026",
                      "detected_at": "2026-08-13T14:34:25.984Z",
                      "delivered_at": "2026-08-13T14:34:29.580Z",
                      "detected_lag_ms": 33984,
                      "delivery_lag_ms": 3596,
                      "total_lag_ms": 37580,
                      "attempts": 1,
                      "last_status_code": 204,
                      "last_error": null
                    },
                    {
                      "id": "9a0f6041-2c7e-4f4a-9c2d-0b1e6d3a4672",
                      "monitor_id": "bd964ae0-7763-4dd6-9295-233d9badf6f9",
                      "tweet_id": "2087910515246784774",
                      "status": "dead",
                      "tweet_created_at": "Thu Aug 13 14:33:52 +0000 2026",
                      "detected_at": "2026-08-13T14:34:25.984Z",
                      "delivered_at": null,
                      "detected_lag_ms": 33984,
                      "delivery_lag_ms": null,
                      "total_lag_ms": null,
                      "attempts": 8,
                      "last_status_code": 400,
                      "last_error": "non-2xx status 400"
                    }
                  ],
                  "count": 2
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max events to return, 1-200. Defaults to 50.",
            "schema": {
              "type": "integer",
              "description": "Max events to return, 1-200. Defaults to 50.",
              "example": "50"
            },
            "example": "50"
          },
          {
            "$ref": "#/components/parameters/fields"
          },
          {
            "$ref": "#/components/parameters/compact"
          }
        ]
      }
    },
    "/oapi/x_user_stream/add_user_to_monitor_tweet": {
      "post": {
        "operationId": "oapi-x-user-stream-add-user-to-monitor-tweet",
        "summary": "Compat: Add User to Tweet Monitoring",
        "description": "An x_user_stream-shaped request/response envelope, translated onto the exact same underlying monitor system as POST /twitter/monitor -- not a second capability, one system with two request shapes in front of it. Migrating an integration already built against that shape? Point it at this path instead of rewriting it against /twitter/monitor. Free: account administration, not a metered read, billed identically to /twitter/monitor. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/oapi/x_user_stream/add_user_to_monitor_tweet\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"x_user_name\": \"elonmusk\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/oapi/x_user_stream/add_user_to_monitor_tweet\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"x_user_name\": \"elonmusk\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/oapi/x_user_stream/add_user_to_monitor_tweet\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ x_user_name: \"elonmusk\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "x_user_stream-shaped drop-in for Create Monitor.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "\"success\" or \"error\"."
                    },
                    "msg": {
                      "type": "string",
                      "description": "Human-readable result, e.g. \"User added to tweet monitoring.\""
                    }
                  }
                },
                "example": {
                  "status": "success",
                  "msg": "User added to tweet monitoring."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "x_user_name": {
                    "type": "string",
                    "description": "The X username to watch, without the @.",
                    "example": "elonmusk"
                  }
                },
                "required": [
                  "x_user_name"
                ]
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ]
    },
    "/oapi/x_user_stream/remove_user_to_monitor_tweet": {
      "post": {
        "operationId": "oapi-x-user-stream-remove-user-to-monitor-tweet",
        "summary": "Compat: Remove User from Tweet Monitoring",
        "description": "An x_user_stream-shaped request/response envelope for removing a monitored user, translated onto DELETE /twitter/monitor/{id}. id_for_user is exactly our monitor id -- get it from get_user_to_monitor_tweet, i.e. it is an opaque handle from that list response, which is what our id already is. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/oapi/x_user_stream/remove_user_to_monitor_tweet\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"id_for_user\": \"b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/oapi/x_user_stream/remove_user_to_monitor_tweet\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"id_for_user\": \"b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/oapi/x_user_stream/remove_user_to_monitor_tweet\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ id_for_user: \"b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "x_user_stream-shaped drop-in for Delete Monitor.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "\"success\" or \"error\"."
                    },
                    "msg": {
                      "type": "string",
                      "description": "Human-readable result, e.g. \"User removed from tweet monitoring.\""
                    }
                  }
                },
                "example": {
                  "status": "success",
                  "msg": "User removed from tweet monitoring."
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id_for_user": {
                    "type": "string",
                    "description": "The monitor id, from GET /oapi/x_user_stream/get_user_to_monitor_tweet.",
                    "example": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11"
                  }
                },
                "required": [
                  "id_for_user"
                ]
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ]
    },
    "/oapi/x_user_stream/get_user_to_monitor_tweet": {
      "get": {
        "operationId": "oapi-x-user-stream-get-user-to-monitor-tweet",
        "summary": "Compat: List Tweet-Monitored Users",
        "description": "An x_user_stream-shaped response envelope for listing monitored users, backed by the same monitor rows GET /twitter/monitor returns. Honest field mapping, not fabricated: our monitors table stores no numeric Twitter user id and no separate display name, so x_user_id is always null and x_user_name/x_user_screen_name both carry the handle we actually store. is_monitor_profile (profile-change monitoring) is not a capability this API has -- always 0, never reported as on. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/oapi/x_user_stream/get_user_to_monitor_tweet\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/oapi/x_user_stream/get_user_to_monitor_tweet\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/oapi/x_user_stream/get_user_to_monitor_tweet\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "x_user_stream-shaped drop-in for List Monitors.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "description": "\"success\" or \"error\"."
                    },
                    "msg": {
                      "type": "string",
                      "description": "Human-readable count summary, e.g. \"1 monitored user(s).\""
                    },
                    "data": {
                      "type": "string",
                      "description": "Array of monitored-user objects: id_for_user, x_user_id (always null), x_user_name, x_user_screen_name, is_monitor_tweet, is_monitor_profile (always 0), monitor_tweet_config_status, monitor_profile_config_status, created_at."
                    }
                  }
                },
                "example": {
                  "status": "success",
                  "msg": "1 monitored user(s).",
                  "data": [
                    {
                      "id_for_user": "b6f2c1a4-9e3d-4c11-8a2f-7d5e6c9b0a11",
                      "x_user_id": null,
                      "x_user_name": "elonmusk",
                      "x_user_screen_name": "elonmusk",
                      "is_monitor_tweet": 1,
                      "is_monitor_profile": 0,
                      "monitor_tweet_config_status": 1,
                      "monitor_profile_config_status": 0,
                      "created_at": "2026-08-13T10:00:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      },
      "servers": [
        {
          "url": "https://api.twitterapis.com"
        }
      ]
    },
    "/webhook": {
      "post": {
        "operationId": "webhook-post",
        "summary": "Create Webhook",
        "description": "Register your HTTPS endpoint to receive signed monitor events. The signing secret is returned exactly once in this response; store it immediately, it cannot be retrieved again. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/webhook\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.com/webhooks/twitterapis\"}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/webhook\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={\"url\": \"https://example.com/webhooks/twitterapis\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/webhook\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({ url: \"https://example.com/webhooks/twitterapis\" }),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "201": {
            "description": "Register a URL to receive monitor events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The new webhook's id."
                    },
                    "url": {
                      "type": "string",
                      "description": "The registered delivery URL."
                    },
                    "status": {
                      "type": "string",
                      "description": "\"active\" (delivers) or \"disabled\" (a 410 Gone response from your endpoint sets this; re-register to reactivate)."
                    },
                    "secret": {
                      "type": "string",
                      "description": "The HMAC signing secret, shown ONLY in this response. Use it to verify the X-TwitterAPIs-Signature header on every delivery."
                    },
                    "created_at": {
                      "type": "string",
                      "description": "ISO 8601 creation timestamp."
                    }
                  }
                },
                "example": {
                  "id": "e4a1f9c2-3b7d-4a88-9f1e-2c6d8b4a5e10",
                  "url": "https://example.com/webhooks/twitterapis",
                  "status": "active",
                  "secret": "whsec_<shown once, in this response only>",
                  "created_at": "2026-08-13T10:00:00.000Z"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Your https delivery endpoint. Private, loopback, link-local, and metadata IPs are refused, re-checked at every delivery, not just at creation.",
                    "example": "https://example.com/webhooks/twitterapis"
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        }
      },
      "get": {
        "operationId": "webhook-get",
        "summary": "List Webhooks",
        "description": "Returns every non-deleted webhook on your account. Never returns the signing secret; that is shown once, at creation. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl \"https://api.twitterapis.com/twitter/webhook\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.get(\n    \"https://api.twitterapis.com/twitter/webhook\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    params={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const url = new URL(\"https://api.twitterapis.com/twitter/webhook\");\nconst resp = await fetch(url, {\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "List every webhook on your account.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhooks": {
                      "type": "string",
                      "description": "Array of webhook objects: id, url, status, created_at."
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of webhooks returned."
                    }
                  }
                },
                "example": {
                  "webhooks": [
                    {
                      "id": "e4a1f9c2-3b7d-4a88-9f1e-2c6d8b4a5e10",
                      "url": "https://example.com/webhooks/twitterapis",
                      "status": "active",
                      "created_at": "2026-08-13T10:00:00.000Z"
                    }
                  ],
                  "count": 1
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        }
      }
    },
    "/webhook/{id}/test": {
      "post": {
        "operationId": "webhook-id-test",
        "summary": "Test Webhook",
        "description": "Sends a single HMAC-signed test event to this webhook's URL right now and returns the outcome synchronously. Unlike a real monitor event, a test send is never queued, retried, or dead-lettered: it is a one-shot diagnostic so you can confirm your endpoint and signature verification both work before relying on the webhook. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/webhook/{id}/test\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/webhook/{id}/test\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/webhook/{id}/test\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({}),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Fire one real signed test delivery and see the result immediately.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The webhook's id."
                    },
                    "delivered": {
                      "type": "boolean",
                      "description": "True if your endpoint returned a 2xx within the delivery timeout."
                    },
                    "status_code": {
                      "type": "integer",
                      "description": "The HTTP status your endpoint returned, or null if the request failed before a response was received (timeout, connection refused, DNS failure, or an egress-safety refusal).",
                      "nullable": true
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable failure reason when delivered is false, or null on success.",
                      "nullable": true
                    }
                  }
                },
                "example": {
                  "id": "e4a1f9c2-3b7d-4a88-9f1e-2c6d8b4a5e10",
                  "delivered": true,
                  "status_code": 200,
                  "error": null
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/webhook/{id}/redrive": {
      "post": {
        "operationId": "webhook-id-redrive",
        "summary": "Replay Dead Deliveries",
        "description": "Re-queues this webhook's dead-lettered deliveries so the normal delivery loop sends them again, signed exactly like a live event and with a full retry budget. A delivery is dead-lettered after it fails all 8 attempts over 21 minutes, which is what happens when your endpoint is down longer than that window; until you call this, it is never sent again. Deliveries that died for a permanent reason (a 410 Gone, or a webhook you deleted) are deliberately not replayed, because they would fail identically, and are reported as skipped_permanent instead. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X POST \"https://api.twitterapis.com/twitter/webhook/{id}/redrive\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{}'"
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.post(\n    \"https://api.twitterapis.com/twitter/webhook/{id}/redrive\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n    json={},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/webhook/{id}/redrive\", {\n  method: \"POST\",\n  headers: {\n    Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}`,\n    \"Content-Type\": \"application/json\",\n  },\n  body: JSON.stringify({}),\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Re-send deliveries that were dead-lettered while your endpoint was down.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "The webhook's id."
                    },
                    "requeued": {
                      "type": "integer",
                      "description": "How many dead deliveries were put back in the queue. The next delivery pass sends them."
                    },
                    "skipped_permanent": {
                      "type": "integer",
                      "description": "How many dead deliveries were deliberately not replayed because they failed for a permanent reason."
                    },
                    "max_age_hours": {
                      "type": "integer",
                      "description": "The window actually applied, after clamping."
                    },
                    "limit": {
                      "type": "integer",
                      "description": "The cap actually applied, after clamping."
                    }
                  }
                },
                "example": {
                  "id": "e4a1f9c2-3b7d-4a88-9f1e-2c6d8b4a5e10",
                  "requeued": 2,
                  "skipped_permanent": 0,
                  "max_age_hours": 24,
                  "limit": 100
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "max_age_hours": {
                    "type": "integer",
                    "description": "Only replay deliveries that died within this many hours. Default 24, minimum 1, maximum 168.",
                    "example": "24"
                  },
                  "limit": {
                    "type": "integer",
                    "description": "Cap how many deliveries this call replays, oldest first. Default 100, minimum 1, maximum 1000.",
                    "example": "100"
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/webhook/{id}": {
      "delete": {
        "operationId": "webhook-id",
        "summary": "Delete Webhook",
        "description": "Soft-deletes the webhook: it stops receiving deliveries immediately and disappears from List Webhooks, but delivery history referencing it is retained rather than cascade-deleted. Cost: Free per call.",
        "tags": [
          "Monitoring"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "x-cost-usd": 0,
        "x-codeSamples": [
          {
            "lang": "bash",
            "label": "cURL",
            "source": "curl -X DELETE \"https://api.twitterapis.com/twitter/webhook/{id}\" \\\n  -H \"Authorization: Bearer $TWITTERAPIS_KEY\""
          },
          {
            "lang": "python",
            "label": "Python",
            "source": "import os\nimport requests\n\nresp = requests.delete(\n    \"https://api.twitterapis.com/twitter/webhook/{id}\",\n    headers={\"Authorization\": f\"Bearer {os.environ['TWITTERAPIS_KEY']}\"},\n)\nresp.raise_for_status()\ndata = resp.json()\nprint(data)"
          },
          {
            "lang": "js",
            "label": "JavaScript",
            "source": "const resp = await fetch(\"https://api.twitterapis.com/twitter/webhook/{id}\", {\n  method: \"DELETE\",\n  headers: { Authorization: `Bearer ${process.env.TWITTERAPIS_KEY}` },\n});\nconst data = await resp.json();\nconsole.log(data);"
          }
        ],
        "responses": {
          "200": {
            "description": "Remove a webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "description": "True on success."
                    },
                    "id": {
                      "type": "string",
                      "description": "The deleted webhook's id."
                    }
                  }
                },
                "example": {
                  "deleted": true,
                  "id": "e4a1f9c2-3b7d-4a88-9f1e-2c6d8b4a5e10"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "bad_request",
                  "message": "Missing or malformed parameter. Fix the request before retrying."
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "unauthorized",
                  "message": "The API key is missing, malformed, or revoked. Check the Authorization header."
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "not_found",
                  "message": "The resource does not exist, for example a deleted tweet or a private account."
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "rate_limited",
                  "message": "Too many requests. Back off and retry with exponential backoff."
                }
              }
            }
          },
          "5XX": {
            "description": "Server error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                "example": {
                  "error": "server_error",
                  "message": "Something failed on our side. Retry with backoff; if it persists, contact support."
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The id segment of the path, as returned by the endpoint that created the resource.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "Tweet": {
        "type": "object",
        "description": "A single tweet with its author and engagement counts.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Numeric tweet ID as a string (avoids JS number precision loss)."
          },
          "text": {
            "type": "string",
            "description": "Full tweet text, including expanded URLs."
          },
          "created_at": {
            "type": "string",
            "description": "Tweet creation timestamp in Twitter date format."
          },
          "author": {
            "allOf": [
              {
                "$ref": "#/components/schemas/User"
              }
            ],
            "description": "The account that posted the tweet."
          },
          "favorite_count": {
            "type": "integer",
            "description": "Number of likes (favorites) at fetch time."
          },
          "retweet_count": {
            "type": "integer",
            "description": "Number of retweets at fetch time."
          },
          "reply_count": {
            "type": "integer",
            "description": "Number of replies at fetch time."
          },
          "quote_count": {
            "type": "integer",
            "description": "Number of quote tweets at fetch time."
          },
          "bookmark_count": {
            "type": "integer",
            "description": "Number of bookmarks at fetch time."
          },
          "view_count": {
            "type": "integer",
            "nullable": true,
            "description": "Number of views (impressions). May be null on older tweets posted before public view counts existed."
          },
          "url": {
            "type": "string",
            "description": "Canonical x.com status URL."
          },
          "lang": {
            "type": "string",
            "description": "BCP-47 language code Twitter detected."
          },
          "is_retweet": {
            "type": "boolean",
            "description": "True when the tweet is a retweet."
          },
          "is_quote": {
            "type": "boolean",
            "description": "True when the tweet quotes another tweet."
          },
          "is_reply": {
            "type": "boolean",
            "description": "True when the tweet is a reply to another tweet."
          },
          "has_video": {
            "type": "boolean",
            "description": "True when the tweet carries at least one native video or animated-GIF media item (a one-field filter for video content, including video quote-retweets)."
          },
          "is_paid_promotion": {
            "type": "boolean",
            "description": "True when X shows its own \"Paid partnership\" label on the post (X's branded-content disclosure). False when X shows no label."
          },
          "has_community_note": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the post carries a Community Note; null when X does not say."
          },
          "is_edited": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the post has been edited since it was first posted; null when X sends no edit information."
          },
          "edit_history_ids": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            },
            "description": "The ids of every version of the post, oldest first and including the original; null when X sends no edit information."
          },
          "quoted_status_id": {
            "type": "string",
            "nullable": true,
            "description": "The id of the post this one quotes, present even when the quoted post is not expanded; null when it quotes nothing."
          },
          "source": {
            "type": "string",
            "nullable": true,
            "description": "Posting client/source label; frequently null."
          },
          "conversation_id": {
            "type": "string",
            "description": "ID of the root tweet of the conversation thread this tweet belongs to."
          },
          "in_reply_to_status_id": {
            "type": "string",
            "nullable": true,
            "description": "ID of the tweet being replied to; null when the tweet is not a reply."
          },
          "in_reply_to_user_id": {
            "type": "string",
            "nullable": true,
            "description": "Numeric ID of the user being replied to; null when not a reply."
          },
          "in_reply_to_username": {
            "type": "string",
            "nullable": true,
            "description": "Handle of the user being replied to; null when not a reply."
          },
          "display_text_range": {
            "type": "array",
            "nullable": true,
            "description": "The UTF-16 character span [start, end) of the display text inside text. It marks the region a client should render, leaving out the leading @mentions on a reply and the trailing t.co link of attached media or a quoted tweet. Always a pair, for example [0, 144] on a plain tweet and [22, 285] on a reply. Null when X sends no range, or sends one whose members are not finite numbers, so a partial range is never passed off as a complete one.",
            "items": {
              "type": "integer",
              "description": "A UTF-16 character offset into text."
            }
          },
          "is_limited_reply": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether replying to this tweet is restricted. True when X names a reply limitation, false when X names a limitation that is not about replies, and null when X names no limitation at all. Null is what every tweet sampled so far returns. The flag is relative to the account that read the tweet, and these public reads do not run as your account, so a value here would not describe you. It is a different question from the author's own who-can-reply setting, which this field does not report."
          },
          "entities": {
            "type": "object",
            "description": "Parsed tweet entities. Always present; the arrays are empty when the tweet has none.",
            "properties": {
              "hashtags": {
                "type": "array",
                "description": "Hashtag entities in the tweet text.",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string",
                      "description": "The hashtag text without the leading #."
                    },
                    "indices": {
                      "type": "array",
                      "description": "Start/end character offsets in the tweet text.",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "symbols": {
                "type": "array",
                "description": "Cashtag entities ($TSLA-style) in the tweet text.",
                "items": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string",
                      "description": "The cashtag text without the leading $."
                    },
                    "indices": {
                      "type": "array",
                      "description": "Start/end character offsets in the tweet text.",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "timestamps": {
                "type": "array",
                "description": "Date/time entities X extracts from the tweet text. Forwarded verbatim from X rather than remapped, so the member shape is whatever X sends and may gain fields without notice. Treat it as opaque unless you have verified the shape yourself.",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "urls": {
                "type": "array",
                "description": "Link entities in the tweet text.",
                "items": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "description": "The t.co short URL as it appears in the text."
                    },
                    "expanded_url": {
                      "type": "string",
                      "description": "The resolved destination URL."
                    },
                    "display_url": {
                      "type": "string",
                      "description": "The human-readable display URL."
                    },
                    "indices": {
                      "type": "array",
                      "description": "Start/end character offsets in the tweet text.",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                }
              },
              "user_mentions": {
                "type": "array",
                "description": "@-mention entities in the tweet text.",
                "items": {
                  "type": "object",
                  "properties": {
                    "id_str": {
                      "type": "string",
                      "description": "Numeric ID of the mentioned user as a string."
                    },
                    "screen_name": {
                      "type": "string",
                      "description": "Handle of the mentioned user."
                    },
                    "name": {
                      "type": "string",
                      "description": "Display name of the mentioned user."
                    },
                    "indices": {
                      "type": "array",
                      "description": "Start/end character offsets in the tweet text.",
                      "items": {
                        "type": "integer"
                      }
                    }
                  }
                }
              }
            }
          },
          "retweeted_tweet": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Tweet"
              }
            ],
            "description": "The original tweet, present only when is_retweet is true."
          },
          "quoted_tweet": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Tweet"
              }
            ],
            "description": "The quoted tweet embedded one level deep, present only when is_quote is true. The nested tweet omits its own retweeted_tweet/quoted_tweet so nesting is bounded to one level."
          },
          "media": {
            "type": "array",
            "description": "Media attachments, top-level for convenience. Same content and item shape as extended_entities.media below (the live API returns media in both places); present only when the tweet has media, omitted for text-only tweets.",
            "items": {
              "$ref": "#/components/schemas/Media"
            }
          },
          "extended_entities": {
            "type": "object",
            "description": "Media attached to the tweet, in the standard Twitter shape. Present only when the tweet has media; omitted for text-only tweets.",
            "properties": {
              "media": {
                "type": "array",
                "description": "Media attachments. Photos have no video_info; videos and GIFs carry video_info.variants.",
                "items": {
                  "$ref": "#/components/schemas/Media"
                }
              }
            }
          }
        }
      },
      "Media": {
        "type": "object",
        "description": "A single media attachment (photo, video, or GIF). Appears both as Tweet.media (top-level) and Tweet.extended_entities.media -- the live API returns the identical array in both places.",
        "properties": {
          "type": {
            "type": "string",
            "description": "Media type: \"photo\", \"video\", or \"animated_gif\"."
          },
          "media_url_https": {
            "type": "string",
            "nullable": true,
            "description": "Thumbnail/still image URL (normally twimg-hosted). Validate the host before fetching."
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "The t.co display URL for the media in the tweet text."
          },
          "ext_alt_text": {
            "type": "string",
            "description": "Author-supplied alt text, when present."
          },
          "video_info": {
            "type": "object",
            "description": "Present for \"video\" and \"animated_gif\". Pick the highest-bitrate video/mp4 variant for playback.",
            "properties": {
              "duration_millis": {
                "type": "integer",
                "description": "Clip duration in milliseconds."
              },
              "variants": {
                "type": "array",
                "description": "Playable renditions (an HLS manifest plus one or more mp4 bitrates).",
                "items": {
                  "type": "object",
                  "properties": {
                    "content_type": {
                      "type": "string",
                      "description": "MIME type, e.g. \"video/mp4\" or \"application/x-mpegURL\"."
                    },
                    "url": {
                      "type": "string",
                      "description": "Rendition URL (normally twimg-hosted). Validate the host before fetching."
                    },
                    "bitrate": {
                      "type": "integer",
                      "description": "Bitrate in bps; present on mp4 variants only."
                    }
                  }
                }
              }
            }
          }
        }
      },
      "User": {
        "type": "object",
        "description": "A Twitter/X user profile.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Numeric user ID as a string."
          },
          "username": {
            "type": "string",
            "description": "Handle without the leading @."
          },
          "name": {
            "type": "string",
            "description": "Display name."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether the account is legacy-verified."
          },
          "is_blue_verified": {
            "type": "boolean",
            "description": "Whether the account carries the Verified (Blue) badge."
          },
          "verified_type": {
            "type": "string",
            "nullable": true,
            "description": "Verification type, for example Business or Government, when applicable; null otherwise."
          },
          "followers_count": {
            "type": "integer",
            "description": "Follower count."
          },
          "following_count": {
            "type": "integer",
            "description": "Following count."
          },
          "tweet_count": {
            "type": "integer",
            "description": "Number of tweets the account has posted."
          },
          "favourites_count": {
            "type": "integer",
            "description": "Number of tweets the account has liked."
          },
          "media_count": {
            "type": "integer",
            "description": "Number of media items the account has posted."
          },
          "description": {
            "type": "string",
            "description": "Profile bio text."
          },
          "location": {
            "type": "string",
            "description": "Self-reported location."
          },
          "url": {
            "type": "string",
            "description": "Linked website URL from the profile, when set."
          },
          "created_at": {
            "type": "string",
            "description": "Account creation timestamp in Twitter date format."
          },
          "profile_image_url": {
            "type": "string",
            "description": "Avatar image URL."
          },
          "cover_picture": {
            "type": "string",
            "description": "Profile banner/cover image URL, when set."
          },
          "listed_count": {
            "type": "integer",
            "nullable": true,
            "description": "Number of public lists the account appears on."
          },
          "can_dm": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account accepts direct messages. Currently null on profile lookups (user/info, user/search) and on tweet authors: X no longer includes DM permission in those payloads. The key stays so it fills again if X restores it. For a real answer between two accounts, use can_dm on /twitter/user/check_follow_relationship."
          },
          "parody_commentary_fan_label": {
            "type": "string",
            "nullable": true,
            "description": "X's parody / commentary / fan account label, when the account is marked as one; null when it carries no such label."
          },
          "creator_subscriptions_enabled": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the account sells X Subscriptions to its followers; null when X does not say."
          },
          "can_media_tag": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether other accounts are permitted to tag this account in media; null when X does not report the media-tag permission."
          },
          "has_custom_timelines": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account has created custom timelines."
          },
          "is_translator": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account is a Twitter/X translator."
          },
          "possibly_sensitive": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account is flagged as possibly posting sensitive media."
          },
          "default_profile": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the account still uses the default profile theme."
          },
          "default_profile_image": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the account still uses the default avatar."
          },
          "professional_type": {
            "type": "string",
            "nullable": true,
            "description": "Professional account type when set, for example \"Creator\" or \"Business\"; null otherwise."
          },
          "profile_bio": {
            "type": "object",
            "nullable": true,
            "description": "Structured bio with entity ranges, when present.",
            "properties": {
              "description": {
                "type": "string",
                "nullable": true,
                "description": "The bio text."
              },
              "entities": {
                "type": "object",
                "nullable": true,
                "additionalProperties": true,
                "description": "Mention/URL entity ranges within the bio, when present."
              }
            }
          },
          "affiliate_label": {
            "type": "object",
            "nullable": true,
            "description": "Parent-organization/affiliate badge shown on the profile, when present.",
            "properties": {
              "description": {
                "type": "string",
                "nullable": true,
                "description": "The affiliate/parent-org label text."
              },
              "badge_url": {
                "type": "string",
                "nullable": true,
                "description": "Badge image URL."
              },
              "url": {
                "type": "string",
                "nullable": true,
                "description": "Link the badge points to."
              }
            }
          },
          "pinned_tweet_ids": {
            "type": "array",
            "description": "Numeric IDs (as strings) of the account's pinned tweet(s); empty array when the account has none pinned or when a trimmed user object omits the block.",
            "items": {
              "type": "string",
              "description": "A pinned tweet ID as a string."
            }
          },
          "protected": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account is protected (locked); null on a trimmed user object that carries no protected flag."
          },
          "type": {
            "type": "string",
            "nullable": true,
            "description": "The user result __typename, for example \"User\" or \"UserUnavailable\"; null when absent."
          },
          "is_automated": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the profile carries X's automated-account label, which is how an account declares itself a bot. Null when no such label is on the profile. This field is never set to false by inference, so null means only that X did not label the account, never that a human runs it. Null on every account sampled so far, including accounts that are plainly automated."
          },
          "automated_by": {
            "type": "string",
            "nullable": true,
            "description": "Handle of the account that manages this automated account, read from the link on the automated label. Null unless is_automated is true and that label carries a single-segment x.com or twitter.com profile link. Null on every account sampled so far."
          },
          "unavailable": {
            "type": "boolean",
            "nullable": true,
            "description": "True when X reports the account as unavailable, for example suspended or withheld. False when X returns an ordinary account result. Null on a trimmed user object that reports no account type at all. It is derived from the same value as type, so the two can never disagree: a type of UserUnavailable always gives true."
          },
          "unavailable_message": {
            "type": "string",
            "nullable": true,
            "description": "The message X returns explaining why the account is unavailable, for example the text shown in place of the profile. Null when the account is available or when X sends no message."
          },
          "unavailable_reason": {
            "type": "string",
            "nullable": true,
            "description": "The short reason code X returns for an unavailable account, for example Suspended. Null when the account is available or when X sends no reason."
          },
          "withheld_in_countries": {
            "type": "array",
            "nullable": true,
            "description": "ISO country codes in which X withholds this account. The empty array and null mean different things and the difference is legally relevant if you republish profiles: an empty array is X stating the account is withheld nowhere, while null is X not telling us. Do not read null as \"not withheld\". Null on every account today, because the block this is read from is one X no longer sends; the read is kept so the field fills in on its own if X restores it.",
            "items": {
              "type": "string",
              "description": "An ISO country code, for example DE."
            }
          }
        }
      },
      "Trend": {
        "type": "object",
        "description": "A single trending topic from X's trends list.",
        "properties": {
          "name": {
            "type": "string",
            "description": "The trend text, for example a hashtag or phrase. On a story item from a category call, the headline."
          },
          "url": {
            "type": "string",
            "description": "x.com search URL for the trend. On a story item from a category call, the story page under https://x.com/i/trending/ followed by the story id."
          },
          "query": {
            "type": "string",
            "description": "Search query for the trend. URL-encoded on location trends; on a story item from a category call, the headline."
          },
          "promoted_content": {
            "nullable": true,
            "description": "Promotion metadata when the trend is a promoted/paid placement; null for organic trends."
          },
          "tweet_volume": {
            "type": "integer",
            "nullable": true,
            "description": "Approximate number of tweets in the trend over the trailing window; null when X does not report a volume. On a story item from a category call, the post count read from X's line, for example 116000 from \"116K posts\"."
          },
          "is_hashtag": {
            "type": "boolean",
            "description": "Whether the trend is a hashtag (its name starts with #). Derived from the trend name when X sends no literal flag."
          },
          "rank": {
            "type": "integer",
            "description": "1-based position of the trend in X's trending-rank order, assigned before any count truncation. On an Explore tab category call, story items are ranked after the ranked trends. On category=business_and_finance the kept trends are re-ranked from 1 after the label filter."
          },
          "meta_description": {
            "type": "string",
            "nullable": true,
            "description": "The context line X shows under a trend. On a category call it is X's own line, for example \"Music · Trending\" on a ranked trend or \"8 hours ago · News · 116K posts\" on a story item. category=business_and_finance keeps only the ranked trends whose line starts with \"Business and finance\", for example \"Business and finance · Trending\". Null on every location trend today: those are read from X's REST trends/place.json, whose trend object carries no context string, so there is nothing to return; the field fills in on its own the day that changes. It is deliberately not synthesised from tweet_volume, because a line written here and presented as X's would be a fabrication."
          },
          "is_ai_story": {
            "type": "boolean",
            "description": "Present only on a category call. True on an item X itself marks as AI-written: every story item from an Explore tab's stories module, and any ranked trend X flags as AI-written (which keeps its rank). False on the other ranked trends. category=business_and_finance returns ranked trends only, never story items. Location trends do not carry this key."
          }
        }
      },
      "TrendServedLocation": {
        "type": "object",
        "description": "The location a trends response was actually served for, echoed back in the trends envelope so the caller knows which place the trends belong to.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable location name, for example \"Worldwide\" or \"United States\"."
          },
          "woeid": {
            "type": "integer",
            "description": "The Yahoo! Where On Earth ID for the location; pass it back as the woeid parameter to re-request the same place."
          }
        }
      },
      "TrendLocation": {
        "type": "object",
        "description": "A place trends are available for, from the trends/locations directory. Pass its woeid to the trends endpoint to read that location's trends.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable location name, for example \"Worldwide\", \"United States\", or a city name."
          },
          "woeid": {
            "type": "integer",
            "description": "The Yahoo! Where On Earth ID for the location; pass it as the woeid parameter to the trends endpoint."
          },
          "country": {
            "type": "string",
            "description": "Country name the location belongs to; empty string for supernames like Worldwide."
          },
          "countryCode": {
            "type": "string",
            "nullable": true,
            "description": "DEPRECATED camelCase alias of country_code, kept for a deprecation window. Prefer country_code (snake_case is our canonical convention). ISO country code for the location; null for supernames like Worldwide and for locations X reports no code for."
          },
          "country_code": {
            "type": "string",
            "nullable": true,
            "description": "ISO country code for the location; null for supernames like Worldwide and for locations X reports no code for. Canonical snake_case field (carries the same value as the deprecated camelCase countryCode)."
          },
          "parentid": {
            "type": "integer",
            "description": "WOEID of the parent location (0 for the top-level Worldwide supername)."
          },
          "placeType": {
            "type": "object",
            "description": "DEPRECATED camelCase alias of place_type, kept for a deprecation window. Prefer place_type. The location's place-type classification.",
            "properties": {
              "code": {
                "type": "integer",
                "description": "Numeric place-type code (for example 19 for a supername, 12 for a country, 7 for a town)."
              },
              "name": {
                "type": "string",
                "description": "Human-readable place-type name, for example \"Supername\", \"Country\", or \"Town\"."
              }
            }
          },
          "place_type": {
            "type": "object",
            "description": "The location's place-type classification. Canonical snake_case field (carries the same value as the deprecated camelCase placeType).",
            "properties": {
              "code": {
                "type": "integer",
                "description": "Numeric place-type code (for example 19 for a supername, 12 for a country, 7 for a town)."
              },
              "name": {
                "type": "string",
                "description": "Human-readable place-type name, for example \"Supername\", \"Country\", or \"Town\"."
              }
            }
          },
          "url": {
            "type": "string",
            "description": "The where.yahooapis.com reference URL X returns for the location."
          }
        }
      },
      "About": {
        "type": "object",
        "description": "A profile's full About object: identity, bio, location, linked website, verification and identity-verification flags, the professional account type and categories, follower/following counts, avatar, the account-creation date, and the \"About this account\" transparency panel (account country, how the account was created, username-change history).",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true,
            "description": "Numeric user ID as a string."
          },
          "username": {
            "type": "string",
            "nullable": true,
            "description": "Handle without the leading @."
          },
          "name": {
            "type": "string",
            "nullable": true,
            "description": "Display name."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Profile bio text."
          },
          "location": {
            "type": "string",
            "nullable": true,
            "description": "Self-reported location."
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Linked website URL, when set."
          },
          "is_blue_verified": {
            "type": "boolean",
            "description": "Whether the account carries the Verified (Blue) badge."
          },
          "verified": {
            "type": "boolean",
            "description": "Whether the account is legacy-verified."
          },
          "verified_type": {
            "type": "string",
            "nullable": true,
            "description": "Verification type, for example Business or Government, when applicable; null otherwise."
          },
          "professional_type": {
            "type": "string",
            "nullable": true,
            "description": "Professional account type, for example \"Creator\" or \"Business\", when the account publishes one; null otherwise."
          },
          "professional_categories": {
            "type": "array",
            "description": "Professional category names the account has published (populated only for Professional/Business accounts; empty array otherwise).",
            "items": {
              "type": "string",
              "description": "A human-readable category name, for example \"Software Company\"."
            }
          },
          "followers_count": {
            "type": "integer",
            "nullable": true,
            "description": "Follower count."
          },
          "following_count": {
            "type": "integer",
            "nullable": true,
            "description": "Following count."
          },
          "created_at": {
            "type": "string",
            "nullable": true,
            "description": "Account creation timestamp in Twitter date format."
          },
          "profile_image_url": {
            "type": "string",
            "nullable": true,
            "description": "Avatar image URL."
          },
          "is_identity_verified": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account has completed X's identity verification. Null when the profile carries no verification_info block (an honest \"not available\", never a fabricated value)."
          },
          "verified_since": {
            "type": "string",
            "nullable": true,
            "description": "Timestamp the account was verified, as the raw epoch-milliseconds string X emits; null when not available."
          },
          "account_based_in": {
            "type": "string",
            "nullable": true,
            "description": "Country the account is based in, from X's \"About this account\" transparency panel; null when the panel is unavailable."
          },
          "created_via": {
            "type": "string",
            "nullable": true,
            "description": "How the account was created, from X's \"About this account\" transparency panel, for example \"United States App Store\". X names this field `source` upstream; it is surfaced here as created_via (the \"connected via / created via\" concept). Null when the panel is unavailable."
          },
          "username_changes": {
            "type": "object",
            "nullable": true,
            "description": "Username-change history from X's \"About this account\" transparency panel; null when the panel is unavailable.",
            "properties": {
              "count": {
                "type": "integer",
                "description": "Number of times the account has changed its username."
              },
              "last_changed_at": {
                "type": "string",
                "nullable": true,
                "description": "When the username was last changed, as the raw epoch-milliseconds string X emits; null when the account has never changed its username (count is 0)."
              }
            }
          },
          "created_country_accurate": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether X considers account_based_in an accurate reflection of the account's country of origin; null when the transparency panel is unavailable."
          },
          "location_accurate": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether X considers the self-reported location accurate; null when the transparency panel is unavailable."
          },
          "learn_more_url": {
            "type": "string",
            "nullable": true,
            "description": "X help-center link explaining the \"About this account\" transparency data; null when the panel is unavailable."
          },
          "protected": {
            "type": "boolean",
            "nullable": true,
            "description": "Whether the account is locked, so only approved followers can see its posts. Null on a trimmed user object that carries no protected key, which is an honest \"not available\" rather than a claim the account is public."
          },
          "affiliate_label": {
            "type": "object",
            "nullable": true,
            "description": "The affiliation badge X shows beside the display name, linking the account to a parent organization. Null when the account has no affiliation.",
            "properties": {
              "description": {
                "type": "string",
                "nullable": true,
                "description": "The parent organization's display name, for example \"X\"."
              },
              "badge_url": {
                "type": "string",
                "nullable": true,
                "description": "URL of the small badge image X renders next to the name."
              },
              "url": {
                "type": "string",
                "nullable": true,
                "description": "Link to the parent organization's profile."
              }
            }
          },
          "about_profile": {
            "type": "object",
            "description": "The profile About card and the \"About this account\" transparency panel grouped into one object, alongside the flat fields above. Every member mirrors a flat field of the same meaning except birthdate, which appears nowhere else in the response. The object itself is always present on a resolved profile; each member is null when X did not send it.",
            "properties": {
              "bio": {
                "type": "string",
                "nullable": true,
                "description": "Profile bio text. Same value as the flat description field."
              },
              "location": {
                "type": "string",
                "nullable": true,
                "description": "Self-reported location. Same value as the flat location field, and an empty string when the account set none."
              },
              "website": {
                "type": "string",
                "nullable": true,
                "description": "Linked website URL. Same value as the flat url field, and an empty string when the account set none."
              },
              "birthdate": {
                "type": "object",
                "nullable": true,
                "description": "Birthday from the About card, returned only when the account has one set and makes it visible. Null otherwise. Parts X withholds come back null individually, so a birthday shown as a day and month with no year returns year null.",
                "properties": {
                  "day": {
                    "type": "integer",
                    "nullable": true,
                    "description": "Day of the month."
                  },
                  "month": {
                    "type": "integer",
                    "nullable": true,
                    "description": "Month number, 1 for January."
                  },
                  "year": {
                    "type": "integer",
                    "nullable": true,
                    "description": "Year; null when the account hides it."
                  },
                  "visibility": {
                    "type": "string",
                    "nullable": true,
                    "description": "Who the account shows the birthday to, for example Public, Followers, or Self."
                  }
                }
              },
              "account_based_in": {
                "type": "string",
                "nullable": true,
                "description": "Country the account is based in, from the transparency panel. Same value as the flat account_based_in field."
              },
              "created_via": {
                "type": "string",
                "nullable": true,
                "description": "How the account was created, for example \"United States App Store\" or \"Web\". Same value as the flat created_via field."
              },
              "username_changes": {
                "type": "object",
                "nullable": true,
                "description": "Username-change history from the transparency panel. Same value as the flat username_changes field.",
                "properties": {
                  "count": {
                    "type": "integer",
                    "description": "Number of times the account has changed its username."
                  },
                  "last_changed_at": {
                    "type": "string",
                    "nullable": true,
                    "description": "When the username was last changed, as the raw epoch-milliseconds string X emits; null when the account has never changed it."
                  }
                }
              },
              "created_country_accurate": {
                "type": "boolean",
                "nullable": true,
                "description": "Whether X considers account_based_in an accurate reflection of where the account was created."
              },
              "location_accurate": {
                "type": "boolean",
                "nullable": true,
                "description": "Whether X considers the self-reported location accurate."
              },
              "learn_more_url": {
                "type": "string",
                "nullable": true,
                "description": "X help-center link explaining the transparency data."
              }
            }
          },
          "identity_label": {
            "type": "object",
            "nullable": true,
            "description": "The identity badge X shows on business and organisation profiles. Three states, and they are not interchangeable: null means X sent no block, so we do not know; an object whose label is null means X sent an empty block, so the account has no identity label; an object with a populated label is a real badge. Null on every account sampled so far.",
            "properties": {
              "label": {
                "type": "object",
                "nullable": true,
                "description": "The badge itself. Null when X sent the block but the account carries no label.",
                "properties": {
                  "description": {
                    "type": "string",
                    "nullable": true,
                    "description": "The label text, for example the organisation name."
                  },
                  "badge_url": {
                    "type": "string",
                    "nullable": true,
                    "description": "URL of the badge image X renders beside the display name."
                  },
                  "url": {
                    "type": "string",
                    "nullable": true,
                    "description": "Link the badge points to."
                  },
                  "url_type": {
                    "type": "string",
                    "nullable": true,
                    "description": "The kind of link X attached to the badge."
                  },
                  "display_type": {
                    "type": "string",
                    "nullable": true,
                    "description": "How X displays the label on the profile."
                  },
                  "label_type": {
                    "type": "string",
                    "nullable": true,
                    "description": "The label category X assigned, for example a business or government label."
                  }
                }
              }
            }
          }
        }
      },
      "PageInfo": {
        "type": "object",
        "description": "Cursor-pagination fields present on every paged response.",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Number of items returned in this page."
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Opaque cursor for the next page. Null on the final page for list and affiliate endpoints; follower-graph endpoints return a non-null cursor even on the last page, so stop when the collection array is empty."
          }
        }
      },
      "Relationship": {
        "type": "object",
        "description": "The directional follow/block/mute relationship between a source and target account.",
        "properties": {
          "source_id": {
            "type": "string",
            "description": "Numeric ID of the source account."
          },
          "target_id": {
            "type": "string",
            "description": "Numeric ID of the target account."
          },
          "following": {
            "type": "boolean",
            "description": "True when the source account follows the target."
          },
          "followed_by": {
            "type": "boolean",
            "description": "True when the target account follows the source."
          },
          "blocking": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the source blocks the target; null when not available."
          },
          "blocked_by": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the source is blocked by the target; null when not available."
          },
          "muting": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the source mutes the target; null when not available."
          },
          "can_dm": {
            "type": "boolean",
            "nullable": true,
            "description": "True when the source can send a direct message to the target. Null when X does not say."
          }
        }
      },
      "DMConversation": {
        "type": "object",
        "description": "A Direct Message conversation (inbox entry).",
        "properties": {
          "conversation_id": {
            "type": "string",
            "description": "Conversation ID; pass to the DM conversation endpoint to read messages."
          },
          "type": {
            "type": "string",
            "nullable": true,
            "description": "Conversation type, for example ONE_TO_ONE or GROUP_DM; may be null."
          },
          "participants": {
            "type": "array",
            "description": "Numeric user IDs of the participants.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "DMMessage": {
        "type": "object",
        "description": "A single Direct Message within a conversation.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Numeric message ID as a string."
          },
          "time": {
            "type": "string",
            "nullable": true,
            "description": "Send time in epoch milliseconds as a string; may be null."
          },
          "sender_id": {
            "type": "string",
            "nullable": true,
            "description": "Numeric ID of the sending account as a string; may be null."
          },
          "text": {
            "type": "string",
            "description": "Message body text."
          }
        }
      },
      "Community": {
        "type": "object",
        "description": "An X Community. Returned by Community Info and by Community Memberships, always with the same 24 keys, but NOT with the same fields populated: Community Info is served by a reduced X operation and returns admin, invites_policy, question, search_tags and members_facepile_ids empty, moderator_count as 0, and creator with id and name null. Community Memberships returns all of those filled. Each property below states which endpoint fills it, so a null can be read correctly rather than guessed at.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Numeric community id as a string."
          },
          "name": {
            "type": "string",
            "description": "The community's display name. Returned identically by both endpoints."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "The community's description text. Null when the community has not written one, which was 1 of 39 communities sampled. Returned identically by both endpoints."
          },
          "created_at": {
            "type": "integer",
            "description": "Millisecond epoch the community was created, as an integer rather than an ISO string. 0 when X did not send it. Returned identically by both endpoints."
          },
          "member_count": {
            "type": "integer",
            "description": "Total members. Returned identically by both endpoints: it matched exactly on all 10 communities read through both on 2026-08-17, including one at 265135 members. Contrast moderator_count, which does not match."
          },
          "moderator_count": {
            "type": "integer",
            "description": "Total moderators, but only from Community Memberships. COMMUNITY INFO RETURNS 0 HERE FOR EVERY COMMUNITY, including communities that demonstrably have moderators. On 10 communities read through both endpoints on 2026-08-17, Community Memberships returned 1 to 6 and Community Info returned 0 every time, and the Community Moderators roster independently agreed with Community Memberships on all 5 it was checked against. Read a 0 from Community Info as not reported, never as no moderators."
          },
          "join_policy": {
            "type": "string",
            "nullable": true,
            "description": "How the community admits members, passed through from X. Observed values: Open and RestrictedJoinRequestsRequireModeratorApproval. Only those two have been seen, which is not the same as those two being the whole set, so the field is passed through as a string rather than narrowed to an enum. Returned identically by both endpoints."
          },
          "invites_policy": {
            "type": "string",
            "nullable": true,
            "description": "Who may invite new members, passed through from X. Observed values: MemberInvitesAllowed and ModeratorInvitesAllowed. ONLY COMMUNITY MEMBERSHIPS RETURNS IT. Community Info returns null here for every community, so a null from that endpoint means the operation serving it does not carry the field, NOT that the community has no invite policy. The two cases cannot be told apart from the response alone, which is why it is stated here: on 2026-08-17 this field was non-null on all 10 communities read through Community Memberships and null on the same 10 read through Community Info minutes later. When you need the invite policy, read it from Community Memberships."
          },
          "is_nsfw": {
            "type": "boolean",
            "description": "Whether the community is flagged not-safe-for-work. Defaults to false when X does not send the field, so an absent flag reads as not flagged rather than as unknown. Returned identically by both endpoints."
          },
          "question": {
            "type": "string",
            "nullable": true,
            "description": "The join-screen prompt applicants answer, when the community sets one. Community Info returns null here for every community, including ones that do set a question, so read it from Community Memberships. A null from Community Memberships is the real answer and means the community asks nothing."
          },
          "primary_topic": {
            "type": "object",
            "nullable": true,
            "description": "The single topic X assigns the community. Null when the community has no topic. Community Info fills name but leaves topic_id null, so take topic_id from Community Memberships if you need the numeric id. X spells the name topic_name on the wire; it is normalised to name so a consumer reading Spaces topics and Community topics does not have to care.",
            "properties": {
              "topic_id": {
                "type": "string",
                "nullable": true,
                "description": "X's numeric topic id as a string, for example 603 for Entrepreneurship. Null on Community Info, which sends the name without the id."
              },
              "name": {
                "type": "string",
                "nullable": true,
                "description": "The topic's display name, for example Entrepreneurship or Education. Filled by both endpoints."
              }
            }
          },
          "search_tags": {
            "type": "array",
            "description": "The community's search tags, as plain strings. Community Info returns an empty array for every community, including ones that do have tags, so read this from Community Memberships. An empty array from Community Memberships is the real answer and means the community set none.",
            "items": {
              "type": "string",
              "description": "One search tag, without a leading hash."
            }
          },
          "rules": {
            "type": "array",
            "description": "The community's posted rules, in the order X returns them. Returned identically by both endpoints.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Numeric rule id as a string."
                },
                "name": {
                  "type": "string",
                  "description": "The rule's title, which is the line X shows in the community's rule list."
                },
                "description": {
                  "type": "string",
                  "nullable": true,
                  "description": "The longer body text under the rule's title. Null when the community left it blank, which was 87 of 174 rules sampled on 2026-08-17, so expect roughly half of them to carry only a name. It is left null rather than filled with the rule name."
                }
              }
            }
          },
          "banner_url": {
            "type": "string",
            "nullable": true,
            "description": "The banner a client should actually render: the custom banner when the community set one, otherwise X's default. Computed for you, because both banners are always present and picking the wrong one silently shows every community the same stock gradient. Returned identically by both endpoints."
          },
          "custom_banner": {
            "type": "object",
            "nullable": true,
            "description": "The community's own banner, or null when the community never set one. Returned identically by both endpoints.",
            "properties": {
              "url": {
                "type": "string",
                "description": "Image URL on pbs.twimg.com."
              },
              "width": {
                "type": "integer",
                "description": "Image width in pixels."
              },
              "height": {
                "type": "integer",
                "description": "Image height in pixels."
              }
            }
          },
          "default_banner": {
            "type": "object",
            "nullable": true,
            "description": "X's stock banner. Present even when a custom banner exists, which is why banner_url is computed rather than left to the caller. Returned identically by both endpoints.",
            "properties": {
              "url": {
                "type": "string",
                "description": "Image URL on pbs.twimg.com."
              },
              "width": {
                "type": "integer",
                "description": "Image width in pixels."
              },
              "height": {
                "type": "integer",
                "description": "Image height in pixels."
              }
            }
          },
          "permalink": {
            "type": "string",
            "nullable": true,
            "description": "ALWAYS NULL, on both endpoints. X's community payload does not carry a permalink URL on either operation, and one is not synthesised here from the id. It was null on every community record sampled on 2026-08-17, through both endpoints. Build the link yourself: https://x.com/i/communities/ followed by the id."
          },
          "admin": {
            "allOf": [
              {
                "$ref": "#/components/schemas/User"
              }
            ],
            "description": "The community admin's full user profile, but only from Community Memberships. COMMUNITY INFO RETURNS NULL HERE FOR EVERY COMMUNITY: a full profile came back on all 10 communities read through Community Memberships on 2026-08-17 and null on the same 10 read through Community Info. If you need the admin and are starting from a community id, page Community Moderators, whose Admin row carries the same account."
          },
          "creator": {
            "allOf": [
              {
                "$ref": "#/components/schemas/User"
              }
            ],
            "description": "The community creator's full user profile, but only from Community Memberships. Community Info returns a REDUCED object here with id and name null, carrying the username and the verification flags and nothing else, so treat what Community Info gives you as a handle rather than a profile. Frequently the same account as admin, but do not assume it always is."
          },
          "members_facepile_ids": {
            "type": "array",
            "description": "User ids of the members X puts in the community facepile preview, ids only. Community Info returns an empty array for every community, so read this from Community Memberships. Use Community Members for the actual roster, which is the right tool whichever endpoint you started from.",
            "items": {
              "type": "string",
              "description": "A numeric user id as a string."
            }
          },
          "role": {
            "type": "string",
            "nullable": true,
            "description": "ALWAYS NULL, on both endpoints. It is the role of the ACCOUNT THAT MADE THE CALL, and these public reads do not run as your account, so any value here would describe a stranger. The key is kept rather than removed so it stays visible that X sends this field and we decline to answer it. For a real per-member role, use Community Members, whose members[].role is about that member and not about the caller."
          },
          "can_join": {
            "type": "boolean",
            "nullable": true,
            "description": "ALWAYS NULL, on both endpoints, for the same caller-relative reason as role. It answers whether the CALLING account may join, and the calling account is one of ours. Use join_policy for the community's own admission rule, which is a real answer."
          },
          "is_pinned": {
            "type": "boolean",
            "nullable": true,
            "description": "ALWAYS NULL, on both endpoints, for the same caller-relative reason as role. It answers whether the CALLING account pinned this community."
          },
          "viewer_relationship_type": {
            "type": "string",
            "nullable": true,
            "description": "ALWAYS NULL, on both endpoints, for the same caller-relative reason as role. It is the viewer relationship, and the viewer is not you."
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "description": "The uniform JSON body returned on every non-2xx response.",
        "required": [
          "error",
          "message"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Machine-readable error code, for example bad_request, unauthorized, or not_found.",
            "example": "bad_request"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation of the failure."
          }
        }
      }
    },
    "parameters": {
      "paid_promotion": {
        "name": "paid_promotion",
        "in": "query",
        "required": false,
        "description": "Filter this page's tweets by X's Paid partnership label: only keeps tweets whose is_paid_promotion is true, exclude keeps the rest. Omit it for every tweet. It filters the page X returned and does not fetch more, so a filtered page can hold fewer tweets than asked for, or none, while next_cursor still pages on. The response carries paid_promotion_filter { mode, kept, removed }, and count reflects what is returned. Any other value is a 400. Billing is the same as without it.",
        "schema": {
          "type": "string",
          "enum": [
            "only",
            "exclude"
          ]
        },
        "example": "only"
      },
      "fields": {
        "name": "fields",
        "in": "query",
        "required": false,
        "description": "Comma-separated list of dotted field paths to keep in the response (one parameter, never repeated), applied to every object in the returned lists and to nested objects (for example fields=id,text,author.username; the list's own name may prefix a path, fields=tweets.id). A path prefix that lands on an array applies to each element (media.media_url_https). Pagination and envelope keys (next_cursor, cursor, has_more, count, partial, error, message, reason) are always kept. Unknown paths are ignored; up to 50 paths of up to 6 segments. Projection never changes status codes or billing, and applies to data reads only: account, feedback, session status, monitor (other than deliveries), webhook and stream-compat reads return their bodies unchanged.",
        "schema": {
          "type": "string"
        },
        "example": "id,text,created_at,author.username"
      },
      "compact": {
        "name": "compact",
        "in": "query",
        "required": false,
        "description": "Set to 1 (or true) to apply the built-in compact preset: ids, url, text, created_at, lang, the engagement counts, the is_retweet/is_reply/is_quote flags, conversation ids, the author's id/username/name/followers_count/verification, and the quoted or retweeted tweet's id/url/author username. The preset trims what it recognises and leaves alone what it would empty, so it never turns a body into {}. Combine with fields to add paths on top of the preset. Typically cuts a tweet page by 70 to 90 percent for LLM tool callers.",
        "schema": {
          "type": "string",
          "enum": [
            "1"
          ]
        },
        "example": "1"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Pass your API key as a bearer token on every request: Authorization: Bearer <API_KEY>."
      }
    }
  }
}
