x-api-reader
X API Reader
Read-only access to X (Twitter) via the X API v2. All requests use curl against https://api.x.com.
Setup
The bearer token is stored at ~/.config/x-api/.env:
X_BEARER_TOKEN=your_token_here
Before making any API call, load it:
source ~/.config/x-api/.env
If the file doesn't exist, help the user set it up:
mkdir -p ~/.config/x-api && chmod 700 ~/.config/x-api
read -s "token?Enter your X Bearer Token: "
echo "X_BEARER_TOKEN=$token" > ~/.config/x-api/.env
chmod 600 ~/.config/x-api/.env
To get a bearer token: https://developer.x.com/en/portal/dashboard — create a Project + App (Free tier gives 100 reads/month), copy the Bearer Token.
Authentication
All requests use App-Only Bearer Token auth:
-H "Authorization: Bearer $X_BEARER_TOKEN"
Core Read Endpoints
Look up a post by ID
curl -s "https://api.x.com/2/tweets/{id}?tweet.fields=created_at,public_metrics,conversation_id,author_id,article,note_tweet&expansions=author_id&user.fields=username,name" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
If the post is an X Article, the response includes article.plain_text with the full article body, article.title, and article.preview_text. Always include article in tweet.fields to capture long-form content.
Look up multiple posts by IDs
curl -s "https://api.x.com/2/tweets?ids={id1},{id2},{id3}&tweet.fields=created_at,public_metrics,author_id&expansions=author_id&user.fields=username,name" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Get a user's profile by username
curl -s "https://api.x.com/2/users/by/username/{username}?user.fields=description,public_metrics,created_at,profile_image_url" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Get a user's recent posts (timeline)
Requires the user's numeric ID (get it from the username lookup above).
curl -s "https://api.x.com/2/users/{user_id}/tweets?max_results=10&tweet.fields=created_at,public_metrics,conversation_id&expansions=author_id&user.fields=username,name" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Supports since_id, until_id, start_time, end_time, max_results (5-100), and pagination_token.
Search recent posts (last 7 days)
curl -s "https://api.x.com/2/tweets/search/recent?query={query}&max_results=10&tweet.fields=created_at,public_metrics,author_id,conversation_id&expansions=author_id&user.fields=username,name" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
The query parameter supports operators — see the search operators docs.
Common query patterns:
from:username— posts from a specific userto:username— replies to a userconversation_id:123456— all posts in a thread#hashtag— posts with a hashtag"exact phrase"— exact match-is:retweet— exclude retweetshas:links— posts containing URLs- Combine with AND (space), OR, grouping with
()
Get a user's mentions
curl -s "https://api.x.com/2/users/{user_id}/mentions?max_results=10&tweet.fields=created_at,public_metrics,author_id&expansions=author_id&user.fields=username,name" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Get quote posts for a post
curl -s "https://api.x.com/2/tweets/{id}/quote_tweets?max_results=10&tweet.fields=created_at,public_metrics,author_id&expansions=author_id&user.fields=username,name" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Reading Threads / Conversations
X doesn't have a dedicated "get thread" endpoint. To reconstruct a thread:
- Get the original post and note its
conversation_id - Search for all posts in that conversation:
curl -s "https://api.x.com/2/tweets/search/recent?query=conversation_id:{conv_id}&tweet.fields=created_at,public_metrics,author_id,in_reply_to_user_id,referenced_tweets&expansions=author_id,referenced_tweets.id&user.fields=username,name&max_results=100" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
- To get only the original author's posts in the thread, add
from:username:query=conversation_id:{conv_id} from:username
GOTCHA: search/recent only covers the last 7 days. For older threads, use the user timeline endpoint instead with start_time and end_time to narrow the window around the tweet date. Then filter results by conversation_id to find thread replies:
curl -s "https://api.x.com/2/users/{user_id}/tweets?max_results=100&tweet.fields=created_at,public_metrics,conversation_id,note_tweet,referenced_tweets&start_time=2025-12-22T00:00:00Z&end_time=2025-12-25T00:00:00Z" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Then filter the results where conversation_id matches the original tweet's ID. This works for any tweet age, unlike search/recent.
Fields & Expansions Quick Reference
Always request these tweet.fields for useful output:
created_at,public_metrics,author_id,conversation_id,article,note_tweet
article— returns full article body (article.plain_text), title, preview, and cover media for X Articlesnote_tweet— returns full text for long posts (>280 chars)
Common expansions:
author_id— includes user object for the post authorreferenced_tweets.id— includes quoted/replied-to postsattachments.media_keys— includes media objects
User fields: username,name,description,public_metrics,profile_image_url,created_at
Media fields: url,preview_image_url,type,alt_text
For the full data dictionary, see https://docs.x.com/x-api/fundamentals/data-dictionary.md
Pagination
Paginated endpoints return meta.next_token. Pass it as pagination_token in the next request:
curl -s "https://api.x.com/2/tweets/search/recent?query=...&pagination_token={next_token}" \
-H "Authorization: Bearer $X_BEARER_TOKEN"
Rate Limits
- Post lookup: 300 req/15min (app), 900 req/15min (user)
- User lookup: 300 req/15min (app), 900 req/15min (user)
- Search recent: 60 req/15min (app), 180 req/15min (user)
- User timeline: 1500 req/15min (app), 900 req/15min (user)
Free tier: 100 reads/month total. Check https://docs.x.com/x-api/fundamentals/rate-limits.md for current limits.
Error Handling
401— bad or expired token403— not authorized (check API tier)429— rate limited (checkx-rate-limit-resetheader)404— post/user not found or deleted
Output Formatting
When presenting results to the user, format posts readably:
@username (Display Name) · 2024-01-15
Post text here...
♻️ 10 💬 5 ❤️ 100 🔁 2
API Documentation
For anything not covered here, consult the official docs:
- Full docs index: https://docs.x.com/llms.txt
- Post lookup: https://docs.x.com/x-api/posts/lookup/introduction.md
- Search: https://docs.x.com/x-api/posts/search/introduction.md
- Timelines: https://docs.x.com/x-api/posts/timelines/introduction.md
- User lookup: https://docs.x.com/x-api/users/lookup/introduction.md
- Fields & expansions: https://docs.x.com/x-api/fundamentals/fields.md
- Search operators: https://docs.x.com/x-api/posts/search/integrate/operators.md
Fetch the relevant .md URL when you need endpoint details, query syntax, or parameter specifics.
Self-Improvement
If you discover new patterns, gotchas, or useful query techniques while using this skill, update this SKILL.md with what you learned. Examples:
- A field combination that works especially well
- An undocumented quirk or error pattern
- A better way to reconstruct threads
- Changes to rate limits or API tiers
Keep this file as the living reference for X API reading.