mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
212 lines
5.4 KiB
Markdown
212 lines
5.4 KiB
Markdown
---
|
|
name: x-api
|
|
description: X/Twitter API integration for posting tweets, threads, reading timelines, search, and analytics. Covers OAuth auth patterns, rate limits, and platform-native content posting. Use when the user wants to interact with X programmatically.
|
|
origin: ECC
|
|
---
|
|
|
|
# X API
|
|
|
|
Programmatic interaction with X (Twitter) for posting, reading, searching, and analytics.
|
|
|
|
## When to Activate
|
|
|
|
- User wants to post tweets or threads programmatically
|
|
- Reading timeline, mentions, or user data from X
|
|
- Searching X for content, trends, or conversations
|
|
- Building X integrations or bots
|
|
- Analytics and engagement tracking
|
|
- User says "post to X", "tweet", "X API", or "Twitter API"
|
|
|
|
## Authentication
|
|
|
|
### OAuth 2.0 (App-Only / User Context)
|
|
|
|
Best for: read-heavy operations, search, public data.
|
|
|
|
```bash
|
|
# Environment setup
|
|
export X_BEARER_TOKEN="your-bearer-token"
|
|
```
|
|
|
|
```python
|
|
import os
|
|
import requests
|
|
|
|
bearer = os.environ["X_BEARER_TOKEN"]
|
|
headers = {"Authorization": f"Bearer {bearer}"}
|
|
|
|
# Search recent tweets
|
|
resp = requests.get(
|
|
"https://api.x.com/2/tweets/search/recent",
|
|
headers=headers,
|
|
params={"query": "claude code", "max_results": 10}
|
|
)
|
|
tweets = resp.json()
|
|
```
|
|
|
|
### OAuth 1.0a (User Context)
|
|
|
|
Required for: posting tweets, managing account, DMs.
|
|
|
|
```bash
|
|
# Environment setup — source before use
|
|
export X_API_KEY="your-api-key"
|
|
export X_API_SECRET="your-api-secret"
|
|
export X_ACCESS_TOKEN="your-access-token"
|
|
export X_ACCESS_SECRET="your-access-secret"
|
|
```
|
|
|
|
```python
|
|
import os
|
|
from requests_oauthlib import OAuth1Session
|
|
|
|
oauth = OAuth1Session(
|
|
os.environ["X_API_KEY"],
|
|
client_secret=os.environ["X_API_SECRET"],
|
|
resource_owner_key=os.environ["X_ACCESS_TOKEN"],
|
|
resource_owner_secret=os.environ["X_ACCESS_SECRET"],
|
|
)
|
|
```
|
|
|
|
## Core Operations
|
|
|
|
### Post a Tweet
|
|
|
|
```python
|
|
resp = oauth.post(
|
|
"https://api.x.com/2/tweets",
|
|
json={"text": "Hello from Claude Code"}
|
|
)
|
|
resp.raise_for_status()
|
|
tweet_id = resp.json()["data"]["id"]
|
|
```
|
|
|
|
### Post a Thread
|
|
|
|
```python
|
|
def post_thread(oauth, tweets: list[str]) -> list[str]:
|
|
ids = []
|
|
reply_to = None
|
|
for text in tweets:
|
|
payload = {"text": text}
|
|
if reply_to:
|
|
payload["reply"] = {"in_reply_to_tweet_id": reply_to}
|
|
resp = oauth.post("https://api.x.com/2/tweets", json=payload)
|
|
tweet_id = resp.json()["data"]["id"]
|
|
ids.append(tweet_id)
|
|
reply_to = tweet_id
|
|
return ids
|
|
```
|
|
|
|
### Read User Timeline
|
|
|
|
```python
|
|
resp = requests.get(
|
|
f"https://api.x.com/2/users/{user_id}/tweets",
|
|
headers=headers,
|
|
params={
|
|
"max_results": 10,
|
|
"tweet.fields": "created_at,public_metrics",
|
|
}
|
|
)
|
|
```
|
|
|
|
### Search Tweets
|
|
|
|
```python
|
|
resp = requests.get(
|
|
"https://api.x.com/2/tweets/search/recent",
|
|
headers=headers,
|
|
params={
|
|
"query": "from:affaanmustafa -is:retweet",
|
|
"max_results": 10,
|
|
"tweet.fields": "public_metrics,created_at",
|
|
}
|
|
)
|
|
```
|
|
|
|
### Get User by Username
|
|
|
|
```python
|
|
resp = requests.get(
|
|
"https://api.x.com/2/users/by/username/affaanmustafa",
|
|
headers=headers,
|
|
params={"user.fields": "public_metrics,description,created_at"}
|
|
)
|
|
```
|
|
|
|
### Upload Media and Post
|
|
|
|
```python
|
|
# Media upload uses v1.1 endpoint
|
|
|
|
# Step 1: Upload media
|
|
media_resp = oauth.post(
|
|
"https://upload.twitter.com/1.1/media/upload.json",
|
|
files={"media": open("image.png", "rb")}
|
|
)
|
|
media_id = media_resp.json()["media_id_string"]
|
|
|
|
# Step 2: Post with media
|
|
resp = oauth.post(
|
|
"https://api.x.com/2/tweets",
|
|
json={"text": "Check this out", "media": {"media_ids": [media_id]}}
|
|
)
|
|
```
|
|
|
|
## Rate Limits Reference
|
|
|
|
| Endpoint | Limit | Window |
|
|
|----------|-------|--------|
|
|
| POST /2/tweets | 200 | 15 min |
|
|
| GET /2/tweets/search/recent | 450 | 15 min |
|
|
| GET /2/users/:id/tweets | 1500 | 15 min |
|
|
| GET /2/users/by/username | 300 | 15 min |
|
|
| POST media/upload | 415 | 15 min |
|
|
|
|
Always check `x-rate-limit-remaining` and `x-rate-limit-reset` headers.
|
|
|
|
```python
|
|
remaining = int(resp.headers.get("x-rate-limit-remaining", 0))
|
|
if remaining < 5:
|
|
reset = int(resp.headers.get("x-rate-limit-reset", 0))
|
|
wait = max(0, reset - int(time.time()))
|
|
print(f"Rate limit approaching. Resets in {wait}s")
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
```python
|
|
resp = oauth.post("https://api.x.com/2/tweets", json={"text": content})
|
|
if resp.status_code == 201:
|
|
return resp.json()["data"]["id"]
|
|
elif resp.status_code == 429:
|
|
reset = int(resp.headers["x-rate-limit-reset"])
|
|
raise Exception(f"Rate limited. Resets at {reset}")
|
|
elif resp.status_code == 403:
|
|
raise Exception(f"Forbidden: {resp.json().get('detail', 'check permissions')}")
|
|
else:
|
|
raise Exception(f"X API error {resp.status_code}: {resp.text}")
|
|
```
|
|
|
|
## Security
|
|
|
|
- **Never hardcode tokens.** Use environment variables or `.env` files.
|
|
- **Never commit `.env` files.** Add to `.gitignore`.
|
|
- **Rotate tokens** if exposed. Regenerate at developer.x.com.
|
|
- **Use read-only tokens** when write access is not needed.
|
|
- **Store OAuth secrets securely** — not in source code or logs.
|
|
|
|
## Integration with Content Engine
|
|
|
|
Use `content-engine` skill to generate platform-native content, then post via X API:
|
|
1. Generate content with content-engine (X platform format)
|
|
2. Validate length (280 chars for single tweet)
|
|
3. Post via X API using patterns above
|
|
4. Track engagement via public_metrics
|
|
|
|
## Related Skills
|
|
|
|
- `content-engine` — Generate platform-native content for X
|
|
- `crosspost` — Distribute content across X, LinkedIn, and other platforms
|