X API Skill
Product summary
The X API provides programmatic access to X's public conversation through REST endpoints. Agents use it to read posts, publish content, manage users, search historical data, and stream near real-time posts. The API uses pay-per-usage pricing with Bearer Token (app-only) or OAuth authentication. Key files: Developer Console at https://console.x.com for credentials and usage tracking. Primary docs: https://docs.x.com/x-api/introduction
When to use
Reach for this skill when:
- Building applications that read or publish posts, manage users, or access trends
- Searching historical posts (last 7 days with recent search, or full archive back to 2006)
- Streaming near real-time posts matching filter rules
- Accessing user profiles, followers, following, blocks, mutes, or lists
- Managing direct messages, spaces, or community notes
- Analyzing engagement metrics or post analytics
- Integrating X data into dashboards, research tools, or automation workflows
Do not use for: X Ads API (separate product), X for Websites (embedded widgets), or operations requiring user authentication on behalf of another account (use OAuth flows instead).
Quick reference
Authentication methods
| Method | Use case | Setup |
|---|
| Bearer Token (app-only) | Read public data, publish as app | Generate in Developer Console, use Authorization: Bearer $TOKEN |
| OAuth 1.0a user context | Act on behalf of a user | 3-legged flow, requires user approval |
| OAuth 2.0 auth code + PKCE | Web/mobile apps, user sign-in | Authorization code flow with PKCE |
Core endpoints by category
| Category | Key endpoints | Purpose |
|---|
| Posts | /2/tweets/search/recent, /2/tweets/search/all, /2/tweets/search/stream | Search and stream posts |
| Posts | /2/tweets, /2/tweets/{id} | Create, delete, lookup posts |
| Users | /2/users/by/username/{username}, /2/users/{id} | Look up user profiles |
| Users | /2/users/{id}/followers, /2/users/{id}/following | Get follower/following lists |
| Streams | /2/tweets/search/stream/rules | Manage filtered stream rules |
| Direct Messages | /2/dm_conversations, /2/dm_events | Send/receive DMs |
| Lists | /2/lists, /2/lists/{id}/members | Create, manage, query lists |
Request parameters
| Parameter | Purpose | Example |
|---|
tweet.fields | Request additional post fields | created_at,public_metrics,lang |
user.fields | Request additional user fields | description,public_metrics,verified |
expansions | Include related objects (author, media, etc.) | author_id,attachments.media_keys |
max_results | Limit results per request | 100 (varies by endpoint) |
pagination_token | Navigate paginated results | From previous response |
Response headers for rate limiting
x-rate-limit-limit: 900
x-rate-limit-remaining: 847
x-rate-limit-reset: 1705420800
Check these before hitting limits. Reset time is Unix timestamp.
Decision guidance
When to use search vs. filtered stream
| Scenario | Use search | Use filtered stream |
|---|
| Historical data (past 7 days or archive) | ✓ | ✗ |
| Real-time posts as published | ✗ | ✓ |
| One-time data collection | ✓ | ✗ |
| Continuous monitoring | ✗ | ✓ |
| Complex queries with many operators | ✓ | ✓ |
| Persistent connection acceptable | ✗ | ✓ |
When to use fields vs. expansions
| Need | Use fields | Use expansions |
|---|
| Additional data on primary object | ✓ | ✗ |
| Include related objects (author, media) | ✗ | ✓ |
| Reduce API calls | ✗ | ✓ |
| Get specific metrics (likes, reposts) | ✓ | ✗ |
Bearer Token vs. OAuth for user context
| Requirement | Bearer Token | OAuth 1.0a/2.0 |
|---|
| Read public data only | ✓ | ✓ |
| Act on behalf of user | ✗ | ✓ |
| Publish posts as app | ✓ | ✗ |
| Access user's private data | ✗ | ✓ |
| Simpler setup | ✓ | ✗ |
Workflow
Making your first request
- Get credentials: Sign in to https://console.x.com, create an app, copy the Bearer Token
- Choose an endpoint: Start with user lookup (
/2/users/by/username/{username}) or recent search - Build the request: Use cURL, Postman, or an SDK with
Authorization: Bearer $TOKEN header - Add parameters: Include
tweet.fields, user.fields, or expansions to customize response - Parse response: Primary data is in
data field; related objects in includes section - Check rate limits: Monitor
x-rate-limit-remaining header; implement exponential backoff on 429 errors
Streaming near real-time posts
- Create rules: POST to
/2/tweets/search/stream/rules with filter rules (e.g., from:xdevelopers) - Verify rules: GET
/2/tweets/search/stream/rules to confirm they're active - Connect to stream: GET
/2/tweets/search/stream with Bearer Token; maintain persistent connection - Handle keep-alives: Expect blank lines every 20 seconds; reconnect if no data/keep-alive for 20+ seconds
- Process posts: Parse JSON from stream line-by-line; each line is a complete post object
- Manage rules: Add/remove rules without disconnecting; use
add and delete arrays in POST body
Searching historical posts
- Build query: Use operators like
from:user, #hashtag, "phrase", lang:en, -is:retweet - Choose endpoint: Recent search (last 7 days, all developers) or full archive (pay-per-use/Enterprise)
- Make request: GET
/2/tweets/search/recent or /2/tweets/search/all with query parameter - Handle pagination: Use
pagination_token from response to fetch next page - Request fields: Add
tweet.fields and expansions to get author, media, metrics - Parse results: Check
meta.result_count to see how many posts matched
Common gotchas
- Bearer Token expires: Regenerating it in the console invalidates the old one. Update all running applications immediately.
- Rate limits reset every 15 minutes: Don't assume a fixed reset time; use the
x-rate-limit-reset header value. - Expansions require fields: Requesting
author_id expansion alone returns only the ID. Add user.fields to get author details. - Search queries are case-insensitive:
from:X and from:x match the same user. - Filtered stream rules are persistent: Rules remain active until explicitly deleted. Check existing rules before adding duplicates.
- Keep-alive signals are blank lines: Don't treat them as errors; they maintain the connection.
- Post edits create new IDs: Edited posts get new IDs; check
edit_history_tweet_ids to link versions. - Owned Reads pricing: Requests for your own data (posts, bookmarks, followers) cost $0.001 per resource—much cheaper than standard reads.
- Field order in responses may differ: Don't rely on response field order matching request order.
- Some fields require user context: Private metrics and certain user fields need OAuth, not Bearer Token.
Verification checklist
Before submitting work with the X API:
- Bearer Token is stored securely (not in code or version control)
- Rate limit headers are checked; exponential backoff implemented for 429 errors
- Filtered stream rules are verified with GET
/2/tweets/search/stream/rules before assuming they're active - Expansions are paired with corresponding field parameters (e.g.,
author_id with user.fields) - Pagination is handled correctly;
pagination_token is used for subsequent requests - Keep-alive signals in streams are not treated as errors
- Error responses are parsed from
errors array, not data field - API usage is monitored in Developer Console to track costs
- Owned Reads are used where applicable to reduce costs
- OAuth flows (if used) include proper error handling and token refresh logic
Resources
For additional documentation and navigation, see: https://docs.x.com/llms.txt