One account, one post, one moment — with the numbers attached
Twitter / X Data API returns live Twitter / X Data data as clean JSON for twitter / x data The primary endpoint, profile, returns user data including user id, name, username, description and followers.
14 active endpoints. Every call is 1 credit.
- POST/twitter/v1/profile
- POST/twitter/v1/user_by_id
- POST/twitter/v1/user_tweets
- POST/twitter/v1/user_replies
- POST/twitter/v1/user_media
- POST/twitter/v1/user_likes
- POST/twitter/v1/tweet
- +7 more
What Twitter / X Data endpoints does ReefAPI ship?
14 live read endpoints. Read-only data API: no writes, no account actions, no dashboard access on the target site.
Twitter / X Data API
3 of 14 endpoints, ready to run
A profile by handle — name, bio, followers, following, tweet and like counts, verification, creation date, location, website, avatar and banner.
{ "ok": true, "meta": { "api": "twitter", "endpoint": "profile", "mode": "live", "latency_ms": 894.7, "record_count": 1, "cache_hit": false }, "data": {} }
How the Twitter / X Data API works
Twitter / X Data is a normal ReefAPI surface — the same four rules that hold for every other engine on the key.
No OAuth app, no request signing, no per-site account. One key covers all 184 engines.
Every route is a POST with a JSON body. Parameters are validated against the published schema before anything is charged.
Credits, not seats. Failed and blocked calls are never charged, and cache hits cost nothing.
One envelope everywhere. meta carries latency_ms, record_count and the endpoint that answered.
Following a conversation instead of collecting posts
A post on its own is frequently uninterpretable — it is a reply to something, or the interesting part is underneath it.
{"query": "web scraping api", "product": "Latest", "limit": "20"}Newest-first matches with the full engagement block on every row and a cursor to keep going.
{"tweet_id": "20", "limit": "5"}Then the thread under any of them — the post plus its replies, with deep cursor pagination through the conversation.
The thread rather than the post, which is where the disagreement, the correction and the actual answer usually live.
curl -X POST https://api.reefapi.com/twitter/v1/profile \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{}'{
"ok": true,
"data": { … },
"meta": {
"api": "twitter",
"endpoint": "profile",
"mode": "live",
"latency_ms": …,
"record_count": …
},
"error": null
}Field types that are not what you would guess
Most of the confusion on this API is not about missing data, it is about types. Ids are strings that look like numbers, one engagement counter is a string while the four beside it are integers, and created_at is not ISO 8601. Everything below came out of measured responses on @NASA and on a live Latest search.
| Field | Type and format | Measured value |
|---|---|---|
| tweet_id, user_id, list_id, conversation_id | String, always. Never parse them as numbers. | "2092721435663798658" and "11348282" |
| created_at (on a tweet) | Twitter's own format, EEE MMM dd HH:mm:ss +0000 yyyy, always UTC. | "Wed Aug 26 21:10:45 +0000 2026" |
| likes, retweets, replies, quotes, bookmarks | Integers. | 381, 47, 18, 7, 17 |
| views | String, not an integer. Cast it yourself. | "155736" |
| verified vs verified_type | verified is a boolean; verified_type names the badge and is null for a plain paid check. | @NASA: true plus "Government". Another account on the same page: true plus null |
| urls[] | Already expanded. text still holds the t.co shortlink. | text carried a t.co link while urls[] held https://www.youtube.com/watch?v=tGjffGccQig |
| created_at and protected (on a user) | Both came back null on every profile measured, via profile, user_by_id, search product=People and the embedded author object alike. | "created_at": null, "protected": null |
| search product=People | Returns users[] instead of tweets[]. The other three products return tweets[]. | data keys were query, product, users, count, next_cursor |
| An unknown handle | NOT_FOUND, not an empty result. | profile on a made-up handle returned NOT_FOUND with retryable false |
Every media[] entry carries url, which is the poster frame. A video entry adds video_url and duration_ms; a photo entry has neither. A measured video came back with duration_ms 28361 and an mp4 under video.twimg.com.
What a row is a snapshot of, and where the types surprise you
Measured on four profiles, a user's timeline, a reply timeline, a search, a thread, a hidden-likes account and the trends feed.
Likes, retweets, replies, quotes and bookmarks come back as numbers. The view count comes back as a string, and on old posts it is null because X did not count views then. Cast it before you compare it — this is the field that quietly breaks aggregations.
It had been null on every account since X moved the field out of the legacy block; that was found and fixed in this batch. Verification had the same shape of bug: an unverified account and an unknown one both came back as null. They are now distinguishable, with the verification type — government, business — beside it.
The reply timeline resolves each reply's parent text and author from the conversation already in the response, so you are not left with 'yes exactly this' and no idea what this was. Only the rows that actually are replies carry it, which is correct and worth knowing before you write the loop.
A user's likes came back empty for an account that hides them. That is the account's setting, not a gap, and it is why likes is a separate action rather than a field on the profile.
Measured: the Explore feed returned nothing on one call and nine topics on the very next one. X's trends are never legitimately empty, so a blank read was reaching callers as a successful answer meaning 'nothing is trending'. It is now guarded — a response that carried no timeline entries at all is reported as a failed read.
What people build with Twitter / X Data
The jobs this data is most often used for.
endpoints
credit per call
Social-listening tools use Twitter / X Data to get user profile by @username.
Creator and influencer platforms use Twitter / X Data to get user profile by numeric user_id (same fields as profile)..
Brand-monitoring teams use Twitter / X Data to get a user's tweets.
Audience analysts use Twitter / X Data to get a user's tweets AND replies (timeline incl.
What Twitter / X Data data costs
The cheapest call here is 1 credit, so $15/mo (Pro) buys 10,000 of them — $1.50 per 1,000 credits. Credits roll over and never expire, and failed or blocked calls are not charged.
Full pricing →- 1,000 free credits on signup, no card
- One key, all 184 APIs, one credit pool
- Failed and blocked calls are never charged
- Credits roll over and never expire
Call it in two lines
Sign up, get 1,000 credits and one key that works on every engine. Then this is the whole protocol.
curl -X POST https://api.reefapi.com/twitter/v1/profile \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{}'import requests
r = requests.post(
"https://api.reefapi.com/twitter/v1/profile",
headers={"x-api-key": REEF_KEY},
json={},
)
print(r.json()["data"])Have a question? We got answers.
The questions people actually ask before wiring up Twitter / X Data.
Get a free key →Why is tweet_id a string, and what breaks if I turn it into a number?▾
Because snowflake ids passed JavaScript's safe integer range years ago. A measured tweet id, 2092721435663798658, is larger than 2^53, so JSON.parse turns it into 2092721435663798784: off by 126, and pointing at nothing. The same applies to user_id and conversation_id. Keep them as strings end to end, in your database column, in your own JSON and in any URL you build. Every id this API returns is already a string for exactly this reason.
Why is views a string when likes is a number?▾
That is how X's own payload ships it, and we pass the type through rather than quietly coercing it. A measured tweet returned likes 381 as an integer alongside views "155736" as a string. Cast views before you sum or sort on it, otherwise a language that compares strings lexically will tell you "9" beats "155736". Views can also be absent entirely on very old tweets, so guard for that as well.
A retweet's text is cut off at 140 characters. Where is the full text?▾
In retweeted{}. When a row is a retweet it carries is_retweet true and a nested retweeted object holding the original tweet, and it is the outer text that is truncated with an ellipsis, not the inner one. A measured @NASA retweet had text ending "...long exposure star trails from t" while retweeted.text held the whole 408-character original along with its own author, media and counts. Read the outer row for who retweeted and when, and the inner one for what was actually said.
The retweet shows 0 likes. Is that right?▾
Yes, and it is the correct reading. Engagement lands on the original tweet, not on the retweet row. A measured retweet came back with likes 0, replies 0 and quotes 0 but retweets 120, while retweeted.likes was 788 and retweeted.retweets was also 120. So the retweet count mirrors and everything else sits at zero. If you are scoring a timeline, take engagement from retweeted{} on retweet rows or you will systematically undercount an account that retweets a lot.
How do I parse created_at?▾
It is Twitter's legacy format, not ISO 8601: "Wed Aug 26 21:10:45 +0000 2026". In Python that is strptime with "%a %b %d %H:%M:%S %z %Y"; in Go the layout is "Mon Jan 02 15:04:05 -0700 2006". It is always +0000, so you can treat it as UTC. Note that created_at on the user object is a different thing entirely (account creation date) and came back null on every profile measured, so do not use it to age an account.
How do I tell a real verified account from a paid checkmark?▾
Read verified_type, not verified. Measured on one search page: @NASA came back verified true with verified_type "Government", while an ordinary account on the same page came back verified true with verified_type null. verified alone is now true for anyone paying, so verified_type is what carries the distinction. The values observed are "Government", "Business" and null.
How do replies come back, and can I read one without a second call?▾
Usually yes. tweet_replies returns the focal tweet first and then the replies in the same tweets[] array, so index 0 is the parent. On timeline and search rows a reply carries reply_to_tweet_id and reply_to_user, and where the conversation was already in the response it also carries reply_to_text and reply_to_author. A measured search row included the parent's text inline, so the reply was interpretable without another fetch. reply_to_tweet_id is null on an original tweet.
Do the counts drift between two calls on the same tweet?▾
Yes, and that is the live site moving rather than an inconsistency. The same tweet read three times inside a minute returned views "153649", "155736" and "155557", with likes 379, 381 and 382. The author object embedded in each row carries a follower count snapshotted at that moment too, so @NASA showed 92354072 and 92366117 seconds apart. If you need a stable number, timestamp your own read rather than expecting the source to hold still.
What is the Twitter / X Data API?▾
Twitter / X Data API is a ReefAPI endpoint group for twitter / x data It returns live JSON through POST requests under /twitter/v1.
Is the Twitter / X Data API free to try?▾
Yes. ReefAPI starts with 1,000 free credits, no card required. Twitter / X Data calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Twitter / X Data login or account?▾
No login to Twitter / X Data is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Twitter / X Data data?▾
The page example is captured from a live profile call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Twitter / X Data API use?▾
Twitter / X Data actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Twitter / X Data from an AI assistant or MCP client?▾
Yes. Connect ReefAPI once through MCP and your assistant can call twitter actions with the same key, credit pool and JSON envelope used by normal REST requests.
16 More APIs APIs on the same key
One key, one credit pool, one response envelope. If you are pulling Twitter / X Data, you are one call away from the rest of the category — no second contract, no second integration.
Need something this API does not do?
Name the endpoint, the field, or a source we do not carry yet. We ship new APIs every week and you would be first to get the key. Real people read every message and reply the same day.
Try it on your own data before you pay anything
The call above is the real endpoint, not a recording. A free key gives you 1,000 credits, the other 183 APIs, and the same envelope everywhere.
Endpoints, parameters and credit costs on this page are read from the live catalog and cannot drift from what the API accepts. Field notes were captured on 2026-08-30.