Search public X posts with composable filters
POST /v1/x/search
Searches public posts. Every filter narrows the result, and at least one of query, phrase, hashtags, fromUsers, toUsers, mentions, listId, or quotedPostId is required. Paginate with meta.nextCursor. Billed per post returned.
Price: 1 credit per call, plus 1 credit per X post returned. Failed and refused calls cost nothing.
Rate limit: Counts as 2 requests against your per-minute rate limit.
MCP tool: search_x, on every MCP connection.
Requires an API key, sent as Authorization: Bearer <key>.
Request
curl --request POST \
--url https://api.weirapp.io/v1/x/search \
--header "Authorization: Bearer $WEIR_API_KEY" \
--header 'Content-Type: application/json' \
--data '{}'Body
| Field | Type | Required | Notes |
|---|---|---|---|
query |
string | no | Words that must all appear, in any order. · 1–200 chars |
phrase |
string | no | An exact phrase that must appear. · 1–200 chars |
anyWords |
array of string | no | At least one of these words must appear. |
excludeWords |
array of string | no | None of these words may appear. |
hashtags |
array of string | no | Any of these hashtags, with or without the #. |
fromUsers |
array of string | no | Posted by any of these usernames. |
toUsers |
array of string | no | Replying to any of these usernames. |
mentions |
array of string | no | Mentioning any of these usernames. |
language |
string | no | Language X detected, as a BCP-47 tag such as en. · 2–12 chars |
minLikes |
integer | no | min 0 |
minReplies |
integer | no | min 0 |
minReposts |
integer | no | min 0 |
onlyLinks |
boolean | no | Only posts containing a link. |
onlyOriginal |
boolean | no | Exclude replies. |
onlyReplies |
boolean | no | Only replies. |
onlyText |
boolean | no | Exclude posts with links. |
since |
string (date-time) | no | Posted at or after this instant (UTC). |
until |
string (date-time) | no | Posted before this instant (UTC). |
quotedPostId |
string | no | Only posts quoting this post. getXQuotes is the dedicated endpoint for this. · matches ^\d{1,19}$ |
listId |
string | no | Only posts by members of this public List. · matches ^\d{1,19}$ |
sinceId |
string | no | Only posts newer than this post id, exclusive. The way to resume a feed: pass the newest id already seen. · matches ^\d{1,19}$ |
untilId |
string | no | Only posts older than this post id, exclusive. · matches ^\d{1,19}$ |
sort |
string | no | latest is newest first; top is X's own engagement ranking. · latest, top, default "latest" |
limit |
integer | no | Most posts to return. X serves about 20 per page at most. · 1–100, default 25 |
cursor |
string | no | Opaque cursor from the previous page's meta.nextCursor. Pass it back unchanged, with the same path and query parameters; a cursor from another request is rejected with 400. · 1–4096 chars |
Response
X posts, in X's own field names.
200
| Field | Type | Required | Notes |
|---|---|---|---|
data |
array of object | yes | |
data[].id |
string | yes | Numeric post id, as a string. It exceeds 2^53. |
data[].text |
string | yes | Full post text, untruncated. |
data[].url |
string | yes | |
data[].lang |
string or null | yes | BCP-47 language tag detected by X. |
data[].createdAt |
string (date-time) | yes | |
data[].conversationId |
string or null | yes | The thread this post belongs to. |
data[].inReplyToId |
string or null | yes | |
data[].author |
object | yes | |
data[].author.id |
string | yes | |
data[].author.username |
string | yes | |
data[].author.name |
string | yes | |
data[].author.verified |
boolean | yes | |
data[].author.followersCount |
integer | yes | min 0 |
data[].author.profileImageUrl |
string or null | yes | |
data[].likeCount |
integer or null | yes | min 0 |
data[].retweetCount |
integer or null | yes | min 0 |
data[].replyCount |
integer or null | yes | min 0 |
data[].viewCount |
integer or null | yes | min 0 |
data[].quoteCount |
integer or null | yes | min 0 |
data[].bookmarkCount |
integer or null | yes | min 0 |
data[].media |
array of object | yes | Attached photos, videos, and GIFs, in display order. |
data[].media[].id |
string | yes | |
data[].media[].type |
string | yes | X's own media type names. · photo, video, animated_gif |
data[].media[].url |
string or null | yes | The image for a photo; the highest-bitrate MP4 for a video or GIF. Null when X offers only a stream. |
data[].media[].previewImageUrl |
string or null | yes | Poster frame for a video. Null for photos and GIFs. |
data[].entities |
object | yes | |
data[].entities.hashtags |
array of string | yes | Hashtags, without the #. |
data[].entities.mentions |
array of string | yes | Mentioned usernames, without the @. |
data[].entities.urls |
array of string | yes | Expanded link targets, not t.co short links. |
data[].quotedPost |
object or null | yes | The post this one quotes, when it is a quote post. |
data[].quotedPost.id |
string | yes | Numeric post id, as a string. It exceeds 2^53. |
data[].quotedPost.text |
string | yes | Full post text, untruncated. |
data[].quotedPost.url |
string | yes | |
data[].quotedPost.lang |
string or null | yes | BCP-47 language tag detected by X. |
data[].quotedPost.createdAt |
string (date-time) | yes | |
data[].quotedPost.conversationId |
string or null | yes | The thread this post belongs to. |
data[].quotedPost.inReplyToId |
string or null | yes | |
data[].quotedPost.author |
object | yes | |
data[].quotedPost.author.id |
string | yes | |
data[].quotedPost.author.username |
string | yes | |
data[].quotedPost.author.name |
string | yes | |
data[].quotedPost.author.verified |
boolean | yes | |
data[].quotedPost.author.followersCount |
integer | yes | min 0 |
data[].quotedPost.author.profileImageUrl |
string or null | yes | |
data[].quotedPost.likeCount |
integer or null | yes | min 0 |
data[].quotedPost.retweetCount |
integer or null | yes | min 0 |
data[].quotedPost.replyCount |
integer or null | yes | min 0 |
data[].quotedPost.viewCount |
integer or null | yes | min 0 |
data[].quotedPost.quoteCount |
integer or null | yes | min 0 |
data[].quotedPost.bookmarkCount |
integer or null | yes | min 0 |
data[].quotedPost.media |
array of object | yes | Attached photos, videos, and GIFs, in display order. |
data[].quotedPost.media[].id |
string | yes | |
data[].quotedPost.media[].type |
string | yes | X's own media type names. · photo, video, animated_gif |
data[].quotedPost.media[].url |
string or null | yes | The image for a photo; the highest-bitrate MP4 for a video or GIF. Null when X offers only a stream. |
data[].quotedPost.media[].previewImageUrl |
string or null | yes | Poster frame for a video. Null for photos and GIFs. |
data[].quotedPost.entities |
object | yes | |
data[].quotedPost.entities.hashtags |
array of string | yes | Hashtags, without the #. |
data[].quotedPost.entities.mentions |
array of string | yes | Mentioned usernames, without the @. |
data[].quotedPost.entities.urls |
array of string | yes | Expanded link targets, not t.co short links. |
data[].retweetedPost |
object or null | yes | Set when this post is a repost. Read the original's text and counts here: X truncates a repost's own text to RT @user: …. |
data[].retweetedPost.id |
string | yes | Numeric post id, as a string. It exceeds 2^53. |
data[].retweetedPost.text |
string | yes | Full post text, untruncated. |
data[].retweetedPost.url |
string | yes | |
data[].retweetedPost.lang |
string or null | yes | BCP-47 language tag detected by X. |
data[].retweetedPost.createdAt |
string (date-time) | yes | |
data[].retweetedPost.conversationId |
string or null | yes | The thread this post belongs to. |
data[].retweetedPost.inReplyToId |
string or null | yes | |
data[].retweetedPost.author |
object | yes | |
data[].retweetedPost.author.id |
string | yes | |
data[].retweetedPost.author.username |
string | yes | |
data[].retweetedPost.author.name |
string | yes | |
data[].retweetedPost.author.verified |
boolean | yes | |
data[].retweetedPost.author.followersCount |
integer | yes | min 0 |
data[].retweetedPost.author.profileImageUrl |
string or null | yes | |
data[].retweetedPost.likeCount |
integer or null | yes | min 0 |
data[].retweetedPost.retweetCount |
integer or null | yes | min 0 |
data[].retweetedPost.replyCount |
integer or null | yes | min 0 |
data[].retweetedPost.viewCount |
integer or null | yes | min 0 |
data[].retweetedPost.quoteCount |
integer or null | yes | min 0 |
data[].retweetedPost.bookmarkCount |
integer or null | yes | min 0 |
data[].retweetedPost.media |
array of object | yes | Attached photos, videos, and GIFs, in display order. |
data[].retweetedPost.media[].id |
string | yes | |
data[].retweetedPost.media[].type |
string | yes | X's own media type names. · photo, video, animated_gif |
data[].retweetedPost.media[].url |
string or null | yes | The image for a photo; the highest-bitrate MP4 for a video or GIF. Null when X offers only a stream. |
data[].retweetedPost.media[].previewImageUrl |
string or null | yes | Poster frame for a video. Null for photos and GIFs. |
data[].retweetedPost.entities |
object | yes | |
data[].retweetedPost.entities.hashtags |
array of string | yes | Hashtags, without the #. |
data[].retweetedPost.entities.mentions |
array of string | yes | Mentioned usernames, without the @. |
data[].retweetedPost.entities.urls |
array of string | yes | Expanded link targets, not t.co short links. |
meta |
object | yes | |
meta.requestId |
string | yes | |
meta.nextCursor |
string or null | no |
Errors
| Status | Meaning | What to do |
|---|---|---|
400 |
The request failed validation. | The request was malformed. The details object names the field. |
401 |
The API key is missing, malformed, expired, or revoked. | The key is missing, malformed, revoked, or expired. |
402 |
The account is out of credit. Not retryable: this cannot clear until the billing period resets or the plan changes. | Out of credits. Never retry. Only a person can clear it, by adding credits at https://weirapp.io/dashboard/billing. Retrying never will. |
403 |
The API key does not carry the scope this route requires. | The key is valid but lacks the scope this operation needs. |
404 |
The requested resource does not exist. | No such resource, or it is not public. |
429 |
The per-minute rate limit is exhausted. Retryable: wait for Retry-After and try again. | Rate limited. Retryable: wait for Retry-After, then try again. |
500 |
An unexpected error occurred. | Something failed on our side. Retryable with backoff. |
503 |
The source is temporarily unavailable. The request is safe to retry. | A source was unreachable. Retryable with backoff. |