X API Basics
Timeline fetching, posting tweets, and basic operations
Authentication
See Authentication for setup. Most examples use the Bearer token.
Fetch User Timeline
const userId = "12345" // Numeric user ID
const response = await fetch(
`https://api.twitter.com/2/users/${userId}/tweets?` +
new URLSearchParams({
max_results: "10",
"tweet.fields": "created_at,public_metrics,author_id",
expansions: "author_id",
"user.fields": "name,username,profile_image_url",
}),
{
headers: {
Authorization: `Bearer ${process.env.X_BEARER_TOKEN}`,
},
}
)
const data = await response.json()
console.log(data)Get User by Username
async function getUserByUsername(username: string) {
const response = await fetch(
`https://api.twitter.com/2/users/by/username/${username}?` +
new URLSearchParams({
"user.fields": "id,name,username,description,public_metrics",
}),
{
headers: {
Authorization: `Bearer ${process.env.X_BEARER_TOKEN}`,
},
}
)
return response.json()
}
const user = await getUserByUsername("elonmusk")
console.log(user.data.id) // Use this ID for timeline fetchesPost a Tweet
Posting requires OAuth 2.0 user authentication. See X API OAuth.
async function postTweet(text: string, accessToken: string) {
const response = await fetch("https://api.twitter.com/2/tweets", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ text }),
})
return response.json()
}
// With OAuth 2.0 access token
const result = await postTweet("Hello from my app!", userAccessToken)
console.log(result.data.id) // New tweet IDReply to a Tweet
async function replyToTweet(
text: string,
replyToId: string,
accessToken: string
) {
const response = await fetch("https://api.twitter.com/2/tweets", {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
text,
reply: {
in_reply_to_tweet_id: replyToId,
},
}),
})
return response.json()
}Search Recent Tweets
async function searchTweets(query: string) {
const response = await fetch(
`https://api.twitter.com/2/tweets/search/recent?` +
new URLSearchParams({
query,
max_results: "10",
"tweet.fields": "created_at,public_metrics,author_id",
}),
{
headers: {
Authorization: `Bearer ${process.env.X_BEARER_TOKEN}`,
},
}
)
return response.json()
}
const results = await searchTweets("typescript lang:en -is:retweet")Tweet Fields Reference
| Field | Description |
|---|---|
id | Tweet ID |
text | Tweet content |
created_at | Timestamp |
author_id | Author's user ID |
public_metrics | Like/retweet/reply counts |
entities | URLs, mentions, hashtags |
attachments | Media IDs |
Rate Limits
| Endpoint | Rate Limit |
|---|---|
| User timeline | 900 / 15 min |
| Search recent | 450 / 15 min |
| Post tweet | 200 / 15 min |
| User lookup | 900 / 15 min |
Error Handling
interface XAPIError {
errors?: Array<{
message: string
code: number
}>
title?: string
detail?: string
status?: number
}
async function fetchWithErrorHandling(url: string, options: RequestInit) {
const response = await fetch(url, options)
if (!response.ok) {
const error: XAPIError = await response.json()
if (response.status === 429) {
const resetTime = response.headers.get("x-rate-limit-reset")
console.error(`Rate limited. Reset at: ${resetTime}`)
}
throw new Error(error.detail || error.title || "X API error")
}
return response.json()
}