
X Api
- 1.4k installs
- 238k repo stars
- Updated August 5, 2026
- affaan-m/ecc
This is a copy of x-api by affaan-m - installs and ranking accrue to the original listing.
x-api is a Claude Code skill that adds programmatic posting, timeline reading, search, and analytics for X/Twitter via OAuth and REST endpoints for developers who build bots, integrations, or agent-driven social workflow
About
x-api is an ECC skill for programmatic interaction with the X (Twitter) API v2 from Python agents and scripts. It documents OAuth 2.0 bearer tokens for read-heavy search and public data, plus OAuth 1.0a user context required for posting tweets, threads, DMs, and media uploads. Core operations include posting single tweets and reply chains, reading user timelines with public_metrics fields, recent search with query operators such as from:username and -is:retweet, username lookup, and v1.1 media upload followed by v2 tweet creation. Rate-limit handling reads x-rate-limit-remaining and x-rate-limit-reset headers at runtime rather than hardcoding static quotas, and the skill flags itself as drift-prone because X tiers and permissions change frequently. Security guidance forbids hardcoded tokens, requires .gitignore for .env files, and recommends read-only credentials when writes are unnecessary. Developers reach for x-api when agents or scripts must post threads, search recent tweets, or pull engagement metrics from X.
- Supports posting tweets and threads programmatically
- Read timeline, mentions, user data, and perform advanced search
- Built-in OAuth 2.0 Bearer Token and OAuth 1.0a User Context flows
- Handles rate limits and platform-native content formatting
- Covers analytics and engagement tracking endpoints
X Api by the numbers
- 1,383 all-time installs (skills.sh)
- +85 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/affaan-m/ecc --skill x-apiAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.4k |
|---|---|
| repo stars | ★ 238k |
| Last updated | August 5, 2026 |
| Repository | affaan-m/ecc ↗ |
How do you post tweets with the X API?
Add reliable programmatic posting, timeline reading, search, and analytics capabilities for X/Twitter directly from agents and scripts.
Who is it for?
Developers building X bots, social integrations, or agent workflows that post tweets, read timelines, search recent posts, or track public_metrics programmatically.
Skip if: Developers who only need general web research without authenticated X API access should use web search tools instead of x-api.
When should I use this skill?
The user asks to post to X, search tweets via API, read timelines or mentions, or wire OAuth credentials for X/Twitter automation.
What you get
OAuth-configured X client, posted tweet or thread IDs, search JSON payloads, and rate-limit-aware request handlers
- Authenticated X API client
- Tweet or thread post handlers
- Search and timeline fetch scripts
Files
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 idsRead 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 `.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 brand-voice plus content-engine to generate platform-native content, then post via X API: 1. Pull recent original posts when voice matching matters 2. Build or reuse a VOICE PROFILE 3. Generate content with content-engine in X-native format 4. Validate length and thread structure 5. Return the draft for approval unless the user explicitly asked to post now 6. Post via X API only after approval 7. 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
interface:
display_name: "X API"
short_description: "X API posting, timelines, and analytics"
brand_color: "#000000"
default_prompt: "Use $x-api to build X API posting, timeline, or analytics workflows."
policy:
allow_implicit_invocation: true
Related skills
How it compares
Use x-api when you need direct REST integration with posting and search endpoints rather than browser scraping or generic social-media copywriting skills.
FAQ
Which X API auth mode does x-api use for posting?
x-api requires OAuth 1.0a user context with consumer key, consumer secret, access token, and access token secret for posting tweets, threads, DMs, and media. OAuth 2.0 bearer tokens suit read-heavy search and public timeline access.
How does x-api handle changing rate limits?
x-api treats X API quotas as drift-prone and reads x-rate-limit-remaining and x-rate-limit-reset response headers at runtime instead of hardcoding static tables. The skill advises checking current developer docs before implementing posting or search flows.