Response format
TwittrAPI returns X's raw GraphQL JSON unchanged. The exceptions (search, lookups, account actions) and how to read timelines, tweets and users.
Most endpoints return exactly the JSON that X's web app receives for the same request: X's internal GraphQL API, passed through without changes. That gives you every field X sends, but the shape is X's, not ours, and X changes it from time to time.
Each reference page names the X query behind the endpoint (for example UserByScreenName or UserTweets) and says where the data is.
Reading X's JSON
Single objects. A user lookup returns data.user.result, with the numeric ID in rest_id. A single tweet returns data.tweetResult.result.
Timelines (user tweets, followers, lists, communities, search) return a list of instructions. Content is in the TimelineAddEntries instruction:
{
"type": "TimelineAddEntries",
"entries": [
{
"entryId": "tweet-1790000000000000000",
"content": {
"entryType": "TimelineTimelineItem",
"itemContent": {
"itemType": "TimelineTweet",
"tweet_results": { "result": { "rest_id": "1790000000000000000", "...": "..." } }
}
}
},
{ "entryId": "cursor-bottom-...", "content": { "cursorType": "Bottom", "value": "..." } }
]
}entryIdprefixes tell you what an entry is:tweet-,user-,profile-conversation-andconversationthread-(threads),cursor-top-andcursor-bottom-.- Users come as
user_results.result, tweets astweet_results.result. A tweet's author is nested inside the tweet. - Some results are wrapped in a
TweetWithVisibilityResultsobject with the tweet undertweet. - A pinned tweet comes in a separate
TimelinePinEntryinstruction.
Write parsers that search for these markers instead of following one fixed path, and treat every field as optional. The examples repository has small extractors for Python, Node.js, Go and jq.
Exceptions
These endpoints return something other than X's raw GraphQL response:
| Endpoint | Response |
|---|---|
GET /search | {"category": "Latest", "entries": [...]}: the tab you searched and X's instructions array. |
GET /username/to/id/{username} | {"userId": "12"} |
GET /user/usernames/to/ids | {"userIds": {"jack": "12"}} (unresolved handles are left out) |
GET /user/usernames/status | {"usernamesStatus": {"jack": "active"}} |
GET /user/by/username/{username} | X's JSON, or {"data": {}, "userExists": false} when the handle does not exist |
GET /trends/{locationId}, GET /misc/locations, GET /user/friendships/show, GET /misc/emojis | X's older v1.1 JSON (not GraphQL) |
Account actions (/client/*) | {"status_code": 200, "response": "<X body as a string>"}. Parse response again to get X's JSON. |
Direct messages (/client/dm/*) | JSON built by the API (conversations, decrypted messages, settings) with X's field names; see each endpoint page. |
Errors
Errors are always {"error": "..."} with a non-2xx status. See Errors.
Example responses
Reference pages show a captured example response where one is available. Until then they show a placeholder. The SDKs return the same JSON, unmodified.
Coming from another API
If your code expects flat objects or the v2 data / includes shape, the migration guides map those fields to X's JSON and include adapters: from twitterapi.io, from SocialData and from the official X API.