Docs · Tweet
Tweet
One tweet: text, author, likes, replies, reposts, quotes, bookmarks, views, media and the tweet it quotes.
https://api.lurkapi.com/v1/twitter/tweetWhen to use this
Use it to check how a post performed or to pull its text and media. Pass the tweet's URL (x.com or twitter.com) or its id. Videos come with playable MP4 files in media[].variants, best quality first.
text is what x.com shows: long posts in full and t.co links expanded. For a retweet, retweeted_tweet holds the original; for a quote, quoted_tweet holds the quoted tweet. views is null on tweets from before 2023.
When X's main source is busy we answer from its embed data instead: then retweets, quotes, bookmarks, views and author.followers are null, and long posts are cut to 280 characters.
Deleted tweets, tweets from protected accounts and age-restricted tweets return 404 not_found.
Parameters
All parameters go in the query string.
| Parameter | Description |
|---|---|
urlstringrequired | The tweet's URL, e.g. https://x.com/NASA/status/2104593672624886205 (twitter.com links work too), or its numeric id.
|
Example request
Replace YOUR_API_KEY with your key, or set LURKAPI_KEY for the code. Get a free key.
curl "https://api.lurkapi.com/v1/twitter/tweet?url=https%3A%2F%2Fx.com%2FNASA%2Fstatus%2F2104593672624886205" \
-H "x-api-key: YOUR_API_KEY"const params = new URLSearchParams({
url: "https://x.com/NASA/status/2104593672624886205",
});
const res = await fetch(`https://api.lurkapi.com/v1/twitter/tweet?${params}`, {
headers: { "x-api-key": process.env.LURKAPI_KEY },
});
const data = await res.json();
if (!data.success) throw new Error(`${data.code}: ${data.error}`);
console.log(data.media);import os
import requests
res = requests.get(
"https://api.lurkapi.com/v1/twitter/tweet",
params={
"url": "https://x.com/NASA/status/2104593672624886205",
},
headers={"x-api-key": os.environ["LURKAPI_KEY"]},
timeout=60,
)
data = res.json()
if not data["success"]:
raise RuntimeError(f"{data['code']}: {data['error']}")
print(data["media"])Example response
A real response from this endpoint, captured from the live API and trimmed to a couple of items. Strings over 96 characters (mostly signed media URLs) are cut short and end in ….
Show the example response (2 KB)Hide
{
"success": true,
"credits_remaining": 999999,
"credits_charged": 1,
"id": "2104593672624886205",
"url": "https://x.com/NASA/status/2104593672624886205",
"text": "How do we respond when we detect an asteroid that could pose a threat to…",
"created_at": "2026-09-28T15:26:47.000Z",
"lang": "en",
"source": "Sprinklr",
"author": {
"id": "11348282",
"handle": "NASA",
"name": "NASA",
"avatar": "https://pbs.twimg.com/profile_images/1321163587679784960/0ZxKlEKB_400x400.jpg",
"verified": true,
"verified_type": "Government",
"followers": 92377447
},
"counts": {
"likes": 3228,
"replies": 210,
"retweets": 538,
"quotes": 40,
"bookmarks": 267,
"views": 676901
},
"media": [
{
"type": "video",
"url": "https://pbs.twimg.com/media/HTUEyn0XkAALVB_.png",
"width": 405,
"height": 720,
"duration_ms": 38605,
"variants": [
{
"url": "https://video.twimg.com/amplify_video/2104593621043314689/vid/avc1/608x1…",
"content_type": "video/mp4",
"bitrate": 2176000
},
{
"url": "https://video.twimg.com/amplify_video/2104593621043314689/vid/avc1/480x8…",
"content_type": "video/mp4",
"bitrate": 950000
},
{
"url": "https://video.twimg.com/amplify_video/2104593621043314689/vid/avc1/320x5…",
"content_type": "video/mp4",
"bitrate": 632000
},
{
"url": "https://video.twimg.com/amplify_video/2104593621043314689/pl/iMMWqCJ1OZowER7i.m3u8?tag=16&v=2b3",
"content_type": "application/x-mpegURL",
"bitrate": null
}
]
}
],
"hashtags": [],
"mentions": [],
"links": [
"https://go.nasa.gov/4AUCQ3Z"
],
"reply_to_id": null,
"reply_to_handle": null,
"conversation_id": "2104593672624886205",
"quoted_id": null,
"possibly_sensitive": false,
"quoted_tweet": null,
"retweeted_tweet": null
}Response fields
Every field of a successful response. [] marks a list: a[].b is the b of each item in a. nullable fields can be null; optional fields can be missing.
Show all 122 fieldsHide
| Field | Type | Description |
|---|---|---|
| success | true | Always true here; errors have success: false. |
| credits_remaining | number | Your balance after this call. On anonymous playground calls: free tries left today. |
| credits_charged | number | Credits this call cost; 0 on free endpoints. On anonymous playground calls: tries used (1). |
| id | string | Tweet id, e.g. 2104593672624886205. |
| url | string | The tweet on x.com. |
| text | string | The text as x.com shows it: long posts in full, t.co links expanded, without a reply's leading @mentions or the trailing media link. Empty for media-only tweets. |
| created_at | string | When it was posted, ISO 8601. |
| lang | stringnullable | Language as X detects it, e.g. en (und when it can't tell); null if unknown. |
| source | stringnullable | The app it was posted from, e.g. Twitter for iPhone; null if X doesn't say. |
| author | object | Who posted it. |
| author.id | string | Numeric user id. It stays the same when the handle changes. |
| author.handle | string | Username (handle), without @. |
| author.name | string | Display name. |
| author.avatar | stringnullable | Profile picture URL, 400×400; null if none. |
| author.verified | boolean | Has the blue check (X Premium). |
| author.verified_type | stringnullable | Business (gold check, a verified organization) or Government (grey check); null otherwise. |
| author.followers | numbernullable | Followers when fetched; null when X's main source was busy and the tweet came from its embed data. |
| counts | object | Engagement when fetched. Exact numbers, not rounded. |
| counts.likes | number | Likes. |
| counts.replies | number | Replies. |
| counts.retweets | numbernullable | Reposts (retweets); null when X's main source was busy and the tweet came from its embed data. |
| counts.quotes | numbernullable | Quote posts; null when X's main source was busy and the tweet came from its embed data. |
| counts.bookmarks | numbernullable | Bookmarks; null when X's main source was busy and the tweet came from its embed data. |
| counts.views | numbernullable | Views; null on tweets from before 2023 (X didn't count them then), and null when X's main source was busy and the tweet came from its embed data. |
| media | object[] | Attached photos, videos and GIFs, in order. Empty if none. |
| media[].type | string | photo, video or gif (X plays GIFs as silent looping MP4s). |
| media[].url | string | The image; for videos and GIFs, the poster (thumbnail) image. |
| media[].width | number | Original width in pixels. |
| media[].height | number | Original height in pixels. |
| media[].duration_ms | numbernullable | Video length in milliseconds; null for photos and GIFs. |
| media[].variants | object[] | Playable files for videos and GIFs: MP4s from highest to lowest bitrate, then the HLS playlist. Empty for photos. |
| media[].variants[].url | string | File URL on video.twimg.com. |
| media[].variants[].content_type | string | video/mp4, or application/x-mpegURL for the HLS playlist. |
| media[].variants[].bitrate | numbernullable | Bits per second; null for the HLS playlist. |
| hashtags | string[] | Hashtags in the text, without #. |
| mentions | string[] | Usernames @mentioned, including the ones a reply is addressed to. |
| links | string[] | Links in the text, expanded (not t.co). The tweet's own photos and videos aren't included. |
| reply_to_id | stringnullable | Id of the tweet this replies to; null if it isn't a reply. |
| reply_to_handle | stringnullable | Username of the account this replies to; null if it isn't a reply. |
| conversation_id | stringnullable | Id of the thread's first tweet (its own id if it starts one); null if X doesn't say. |
| quoted_id | stringnullable | Id of the tweet this one quotes; null if it isn't a quote. |
| possibly_sensitive | boolean | X marks the media as possibly sensitive. |
| quoted_tweet | objectnullable | The tweet this one quotes (without its own quoted or retweeted tweet); null if none or it's no longer available. |
| quoted_tweet.id | string | Tweet id, e.g. 2104593672624886205. |
| quoted_tweet.url | string | The tweet on x.com. |
| quoted_tweet.text | string | The text as x.com shows it: long posts in full, t.co links expanded, without a reply's leading @mentions or the trailing media link. Empty for media-only tweets. |
| quoted_tweet.created_at | string | When it was posted, ISO 8601. |
| quoted_tweet.lang | stringnullable | Language as X detects it, e.g. en (und when it can't tell); null if unknown. |
| quoted_tweet.source | stringnullable | The app it was posted from, e.g. Twitter for iPhone; null if X doesn't say. |
| quoted_tweet.author | object | Who posted it. |
| quoted_tweet.author.id | string | Numeric user id. It stays the same when the handle changes. |
| quoted_tweet.author.handle | string | Username (handle), without @. |
| quoted_tweet.author.name | string | Display name. |
| quoted_tweet.author.avatar | stringnullable | Profile picture URL, 400×400; null if none. |
| quoted_tweet.author.verified | boolean | Has the blue check (X Premium). |
| quoted_tweet.author.verified_type | stringnullable | Business (gold check, a verified organization) or Government (grey check); null otherwise. |
| quoted_tweet.author.followers | numbernullable | Followers when fetched; null when X's main source was busy and the tweet came from its embed data. |
| quoted_tweet.counts | object | Engagement when fetched. Exact numbers, not rounded. |
| quoted_tweet.counts.likes | number | Likes. |
| quoted_tweet.counts.replies | number | Replies. |
| quoted_tweet.counts.retweets | numbernullable | Reposts (retweets); null when X's main source was busy and the tweet came from its embed data. |
| quoted_tweet.counts.quotes | numbernullable | Quote posts; null when X's main source was busy and the tweet came from its embed data. |
| quoted_tweet.counts.bookmarks | numbernullable | Bookmarks; null when X's main source was busy and the tweet came from its embed data. |
| quoted_tweet.counts.views | numbernullable | Views; null on tweets from before 2023 (X didn't count them then), and null when X's main source was busy and the tweet came from its embed data. |
| quoted_tweet.media | object[] | Attached photos, videos and GIFs, in order. Empty if none. |
| quoted_tweet.media[].type | string | photo, video or gif (X plays GIFs as silent looping MP4s). |
| quoted_tweet.media[].url | string | The image; for videos and GIFs, the poster (thumbnail) image. |
| quoted_tweet.media[].width | number | Original width in pixels. |
| quoted_tweet.media[].height | number | Original height in pixels. |
| quoted_tweet.media[].duration_ms | numbernullable | Video length in milliseconds; null for photos and GIFs. |
| quoted_tweet.media[].variants | object[] | Playable files for videos and GIFs: MP4s from highest to lowest bitrate, then the HLS playlist. Empty for photos. |
| quoted_tweet.media[].variants[].url | string | File URL on video.twimg.com. |
| quoted_tweet.media[].variants[].content_type | string | video/mp4, or application/x-mpegURL for the HLS playlist. |
| quoted_tweet.media[].variants[].bitrate | numbernullable | Bits per second; null for the HLS playlist. |
| quoted_tweet.hashtags | string[] | Hashtags in the text, without #. |
| quoted_tweet.mentions | string[] | Usernames @mentioned, including the ones a reply is addressed to. |
| quoted_tweet.links | string[] | Links in the text, expanded (not t.co). The tweet's own photos and videos aren't included. |
| quoted_tweet.reply_to_id | stringnullable | Id of the tweet this replies to; null if it isn't a reply. |
| quoted_tweet.reply_to_handle | stringnullable | Username of the account this replies to; null if it isn't a reply. |
| quoted_tweet.conversation_id | stringnullable | Id of the thread's first tweet (its own id if it starts one); null if X doesn't say. |
| quoted_tweet.quoted_id | stringnullable | Id of the tweet this one quotes; null if it isn't a quote. |
| quoted_tweet.possibly_sensitive | boolean | X marks the media as possibly sensitive. |
| retweeted_tweet | objectnullable | For retweets: the original tweet, with its own text and counts. null for everything else. |
| retweeted_tweet.id | string | Tweet id, e.g. 2104593672624886205. |
| retweeted_tweet.url | string | The tweet on x.com. |
| retweeted_tweet.text | string | The text as x.com shows it: long posts in full, t.co links expanded, without a reply's leading @mentions or the trailing media link. Empty for media-only tweets. |
| retweeted_tweet.created_at | string | When it was posted, ISO 8601. |
| retweeted_tweet.lang | stringnullable | Language as X detects it, e.g. en (und when it can't tell); null if unknown. |
| retweeted_tweet.source | stringnullable | The app it was posted from, e.g. Twitter for iPhone; null if X doesn't say. |
| retweeted_tweet.author | object | Who posted it. |
| retweeted_tweet.author.id | string | Numeric user id. It stays the same when the handle changes. |
| retweeted_tweet.author.handle | string | Username (handle), without @. |
| retweeted_tweet.author.name | string | Display name. |
| retweeted_tweet.author.avatar | stringnullable | Profile picture URL, 400×400; null if none. |
| retweeted_tweet.author.verified | boolean | Has the blue check (X Premium). |
| retweeted_tweet.author.verified_type | stringnullable | Business (gold check, a verified organization) or Government (grey check); null otherwise. |
| retweeted_tweet.author.followers | numbernullable | Followers when fetched; null when X's main source was busy and the tweet came from its embed data. |
| retweeted_tweet.counts | object | Engagement when fetched. Exact numbers, not rounded. |
| retweeted_tweet.counts.likes | number | Likes. |
| retweeted_tweet.counts.replies | number | Replies. |
| retweeted_tweet.counts.retweets | numbernullable | Reposts (retweets); null when X's main source was busy and the tweet came from its embed data. |
| retweeted_tweet.counts.quotes | numbernullable | Quote posts; null when X's main source was busy and the tweet came from its embed data. |
| retweeted_tweet.counts.bookmarks | numbernullable | Bookmarks; null when X's main source was busy and the tweet came from its embed data. |
| retweeted_tweet.counts.views | numbernullable | Views; null on tweets from before 2023 (X didn't count them then), and null when X's main source was busy and the tweet came from its embed data. |
| retweeted_tweet.media | object[] | Attached photos, videos and GIFs, in order. Empty if none. |
| retweeted_tweet.media[].type | string | photo, video or gif (X plays GIFs as silent looping MP4s). |
| retweeted_tweet.media[].url | string | The image; for videos and GIFs, the poster (thumbnail) image. |
| retweeted_tweet.media[].width | number | Original width in pixels. |
| retweeted_tweet.media[].height | number | Original height in pixels. |
| retweeted_tweet.media[].duration_ms | numbernullable | Video length in milliseconds; null for photos and GIFs. |
| retweeted_tweet.media[].variants | object[] | Playable files for videos and GIFs: MP4s from highest to lowest bitrate, then the HLS playlist. Empty for photos. |
| retweeted_tweet.media[].variants[].url | string | File URL on video.twimg.com. |
| retweeted_tweet.media[].variants[].content_type | string | video/mp4, or application/x-mpegURL for the HLS playlist. |
| retweeted_tweet.media[].variants[].bitrate | numbernullable | Bits per second; null for the HLS playlist. |
| retweeted_tweet.hashtags | string[] | Hashtags in the text, without #. |
| retweeted_tweet.mentions | string[] | Usernames @mentioned, including the ones a reply is addressed to. |
| retweeted_tweet.links | string[] | Links in the text, expanded (not t.co). The tweet's own photos and videos aren't included. |
| retweeted_tweet.reply_to_id | stringnullable | Id of the tweet this replies to; null if it isn't a reply. |
| retweeted_tweet.reply_to_handle | stringnullable | Username of the account this replies to; null if it isn't a reply. |
| retweeted_tweet.conversation_id | stringnullable | Id of the thread's first tweet (its own id if it starts one); null if X doesn't say. |
| retweeted_tweet.quoted_id | stringnullable | Id of the tweet this one quotes; null if it isn't a quote. |
| retweeted_tweet.possibly_sensitive | boolean | X marks the media as possibly sensitive. |
Caching and freshness
Responses are cached for up to 5 minutes, so a repeat call within that window can return the same data. It still costs 1 credit.
Errors
Errors return { success: false, error, code, docs } with the HTTP status below. Validation errors, 401/402/429 rejections and 5xx failures are free; not_found is charged (how charging works). All error codes.
| Status | Code | Meaning |
|---|---|---|
| 401 | missing_api_key | No API key. Send it in the x-api-key header. |
| 401 | invalid_api_key | The key is unknown or was revoked. |
| 402 | insufficient_credits | Not enough credits for this call. Buy a pack or wait for tomorrow's top-up. |
| 404 | not_found | The endpoint, or the thing you asked for (ad, post, subreddit), doesn't exist. Charged when the platform was checked. |
| 405 | method_not_allowed | Endpoints take GET with query params. |
| 429 | rate_limited | Too many calls at once. Wait for the retry-after seconds, then retry. |
| 500 | internal_error | Something broke on our side. Retry; 5xx errors are free. |
| 502 | upstream_error | The platform didn't give a usable answer. Retry; 5xx errors are free. |
| 503 | upstream_busy | All our connections to the platform are busy. Retry in a few seconds; 5xx errors are free. |
| 504 | upstream_timeout | The platform took over 30 seconds to answer. Retry; timeouts are free. |
Use it in Claude
Once LurkAPI is connected to Claude, this endpoint is the twitter_tweet tool. Ask in plain English, for example:
Use LurkAPI's twitter_tweet with url "https://x.com/NASA/status/2104593672624886205" and summarize what you find.Claude calls twitter_tweet with arguments like these, and each call costs 1 credit:
{
"url": "https://x.com/NASA/status/2104593672624886205"
}Tool results skip nulls and empty lists to save tokens.