x-apilisted
Install: claude install-skill Mixard/fable-pack
# X (Twitter) API
Base URL for v2: `https://api.x.com/2`. Media upload still lives on v1.1: `https://upload.twitter.com/1.1/media/upload.json`.
## Authentication
Two schemes; the choice is dictated by the operation, not preference:
- **OAuth 2.0 Bearer token (app-only)** — read-only public data: search, timelines, user lookup.
- **OAuth 1.0a (user context)** — required for every write: posting tweets, media upload, DMs, account management.
```bash
export X_BEARER_TOKEN="..."
# OAuth 1.0a credentials:
export X_CONSUMER_KEY="..."
export X_CONSUMER_SECRET="..."
export X_ACCESS_TOKEN="..."
export X_ACCESS_TOKEN_SECRET="..."
```
Legacy env names (`X_API_KEY`, `X_API_SECRET`, `X_ACCESS_SECRET`) may exist in older setups; prefer the `X_CONSUMER_*` / `X_ACCESS_TOKEN_SECRET` names for new wiring. Tokens are regenerated at developer.x.com.
```python
import os
import requests
from requests_oauthlib import OAuth1Session
bearer_headers = {"Authorization": f"Bearer {os.environ['X_BEARER_TOKEN']}"}
oauth = OAuth1Session(
os.environ["X_CONSUMER_KEY"],
client_secret=os.environ["X_CONSUMER_SECRET"],
resource_owner_key=os.environ["X_ACCESS_TOKEN"],
resource_owner_secret=os.environ["X_ACCESS_TOKEN_SECRET"],
)
```
## Posting
`POST https://api.x.com/2/tweets` (OAuth 1.0a). Success status is **201**; tweet ID at `resp.json()["data"]["id"]`.
```python
resp = oauth.post("https://api.x.com/2/tweets", json={"text": "Hello"})
tweet_id = resp.json()["data"]["id"]
```
Reply pa