Agent skill
x-api
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.
Install this agent skill to your Project
npx add-skill https://github.com/affaan-m/everything-claude-code/tree/main/skills/x-api
SKILL.md
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 Bearer Token (App-Only)
Best for: read-heavy operations, search, public data.
# Environment setup
export X_BEARER_TOKEN="your-bearer-token"
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, and any write flow.
# Environment setup — source before use
export X_CONSUMER_KEY="your-consumer-key"
export X_CONSUMER_SECRET="your-consumer-secret"
export X_ACCESS_TOKEN="your-access-token"
export X_ACCESS_TOKEN_SECRET="your-access-token-secret"
Legacy aliases such as X_API_KEY, X_API_SECRET, and X_ACCESS_SECRET may exist in older setups. Prefer the X_CONSUMER_* and X_ACCESS_TOKEN_SECRET names when documenting or wiring new flows.
import os
from requests_oauthlib import OAuth1Session
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"],
)
Core Operations
Post a Tweet
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
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
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
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",
}
)
Pull Recent Original Posts for Voice Modeling
resp = requests.get(
"https://api.x.com/2/tweets/search/recent",
headers=headers,
params={
"query": "from:affaanmustafa -is:retweet -is:reply",
"max_results": 25,
"tweet.fields": "created_at,public_metrics",
}
)
voice_samples = resp.json()
Get User by Username
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
# 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
X API rate limits vary by endpoint, auth method, and account tier, and they change over time. Always:
- Check the current X developer docs before hardcoding assumptions
- Read
x-rate-limit-remainingandx-rate-limit-resetheaders at runtime - Back off automatically instead of relying on static tables in code
import time
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
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
.envfiles. - Never commit
.envfiles. 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 brand-voice plus content-engine to generate platform-native content, then post via X API:
- Pull recent original posts when voice matching matters
- Build or reuse a
VOICE PROFILE - Generate content with
content-enginein X-native format - Validate length and thread structure
- Return the draft for approval unless the user explicitly asked to post now
- Post via X API only after approval
- Track engagement via public_metrics
Related Skills
brand-voice— Build a reusable voice profile from real X and site/source materialcontent-engine— Generate platform-native content for Xcrosspost— Distribute content across X, LinkedIn, and other platformsconnections-optimizer— Reorganize the X graph before drafting network-driven outreach
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
python-testing
Python testing best practices using pytest including fixtures, parametrization, mocking, coverage analysis, async testing, and test organization. Use when writing or improving Python tests.
golang-patterns
Go-specific design patterns and best practices including functional options, small interfaces, dependency injection, concurrency patterns, error handling, and package organization. Use when working with Go code to apply idiomatic Go patterns.
e2e-testing
Playwright E2E testing patterns, Page Object Model, configuration, CI/CD integration, artifact management, and flaky test strategies.
agentic-engineering
Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when AI agents perform most implementation work and humans enforce quality and risk controls.
api-design
REST API design patterns including resource naming, status codes, pagination, filtering, error responses, versioning, and rate limiting for production APIs.
python-patterns
Python-specific design patterns and best practices including protocols, dataclasses, context managers, decorators, async/await, type hints, and package organization. Use when working with Python code to apply Pythonic patterns.
Didn't find tool you were looking for?