Search X
Search public X posts by keyword or boolean query. Results are relevance/recency-ranked and carry full post metadata.
GET /v1/x/search
Building a query
Supply either a single query or the structured boolean parameters — not
both (if query is set, it wins).
X's own search operators work directly inside query:
| Operator | Example | Matches |
|---|---|---|
AND (space) | tesla model3 | both terms |
OR | model3 OR modely | either term |
- | tesla -recall | excludes a term |
"…" | "climate change" | exact phrase |
from: | from:nasa | posts from an account |
# | #AI | a hashtag |
lang: | lang:en | a language |
min_faves: | min_faves:100 | minimum likes |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | — | A full query with X operators (max 512 characters; over-length queries return 400 query_too_long). Omit to use the structured params below. |
all | string[] | — | Every term must appear (AND). |
any | string[] | — | At least one term must appear (OR). |
none | string[] | — | None of these terms may appear. |
exact | string[] | — | Exact phrase(s), matched verbatim. |
from | string[] | — | Only posts from these accounts. |
hashtag | string[] | — | Posts containing these hashtags. |
lang | string | — | Language code, e.g. en, tr. |
min_likes | integer | — | Minimum like count. |
product | string | Latest | Tab to pull: Latest, Top, or Media. |
since | date or timestamp | — | Oldest point to reach. A date (YYYY-MM-DD) enables deep-history mode (see below); a full UTC timestamp (2024-01-01T14:30:00Z) applies second-precise filtering. Dates are interpreted in UTC. |
until | date or timestamp | today | Newest point to search — a date (YYYY-MM-DD) or a full UTC timestamp. Used with since. |
window_days | integer | 1 | Date-slice width for deep-history mode (smaller = deeper, more pages). Max 31. |
max_pages | integer | 1 | Pages to fetch (max 15). Each page ≈ 20 posts. To go further, send another request with the returned next_cursor. Billed per page. |
cursor | string | — | Resume token from a previous response's next_cursor. Continues a standard search exactly where the last request stopped (ignored in deep-history mode). |
Deep history
A single X query only surfaces a shallow slice of recent posts. Set since to
pull far deeper history: the service slides a date window backwards across
[since, until], searching each slice with date operators, and deduplicates
across windows. max_pages then caps the total pages fetched across all
windows.
Paging further
Each response returns a next_cursor. To continue a standard search beyond
max_pages, send the same request again with cursor set to that value — it
resumes exactly where the previous response stopped, with no gaps or duplicates.
next_cursor is null once results are exhausted. (Deep-history since-date
searches page by date window instead and do not return a cursor.)
curl -G "$LISTENX_BASE/v1/x/search" \
-H "X-API-Key: $LISTENX_KEY" \
--data-urlencode 'query=tesla min_faves:50' \
--data-urlencode 'max_pages=10' \
--data-urlencode 'cursor=PASTE_NEXT_CURSOR_HERE'
Precise time window
Give since/until full UTC timestamps (instead of dates) to filter to an
exact, second-precise window — useful for incremental polling. Timestamps run a
standard search (with cursor), not deep-history windowing.
curl -G "$LISTENX_BASE/v1/x/search" \
-H "X-API-Key: $LISTENX_KEY" \
--data-urlencode 'query=tesla' \
--data-urlencode 'since=2026-10-23T09:00:00Z' \
--data-urlencode 'until=2026-10-23T12:00:00Z'
Long or non-Latin queries (POST)
When a query is long or has many non-Latin keywords that inflate once
URL-encoded, send it in the JSON body with POST /v1/x/search to avoid the
request-URL length limit. The body accepts the same fields as the query
parameters; the 512-character query limit still applies.
curl -X POST "$LISTENX_BASE/v1/x/search" \
-H "X-API-Key: $LISTENX_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "特斯拉 OR 比亚迪 min_faves:50", "max_pages": 5}'
Examples
Boolean query with operators:
curl -G "$LISTENX_BASE/v1/x/search" \
-H "X-API-Key: $LISTENX_KEY" \
--data-urlencode 'query=tesla (model3 OR modely) -recall min_faves:50' \
--data-urlencode 'max_pages=3'
Structured boolean params:
curl -G "$LISTENX_BASE/v1/x/search" \
-H "X-API-Key: $LISTENX_KEY" \
--data-urlencode 'all=tesla' \
--data-urlencode 'any=model3' --data-urlencode 'any=modely' \
--data-urlencode 'none=recall' \
--data-urlencode 'lang=en'
Deep history over a date range:
curl -G "$LISTENX_BASE/v1/x/search" \
-H "X-API-Key: $LISTENX_KEY" \
--data-urlencode 'query=from:nasa artemis' \
--data-urlencode 'since=2024-01-01' \
--data-urlencode 'until=2024-02-01' \
--data-urlencode 'window_days=3' \
--data-urlencode 'max_pages=20'
Response
{
"query": "tesla (model3 OR modely) -recall min_faves:50",
"product": "Latest",
"pages_requested": 3,
"pages_fetched": 3,
"returned": 54,
"next_cursor": "DAABCgAB...",
"fetched_at": "2026-10-30T12:00:00+00:00",
"results": [
{
"id": "1234567890123456789",
"created_at": "Mon Oct 27 10:00:00 +0000 2025",
"text": "The Model 3 refresh is excellent …",
"lang": "en",
"type": "post",
"url": "https://x.com/example/status/1234567890123456789",
"is_quote": false,
"metrics": {
"replies": 12, "retweets": 30, "likes": 240,
"quotes": 4, "bookmarks": 18, "views": 15400
},
"entities": {
"hashtags": ["Tesla"], "symbols": ["TSLA"],
"mentions": ["Tesla"], "urls": ["https://…"]
},
"media": [
{ "type": "photo", "media_url": "https://…", "alt_text": null }
],
"author": {
"id": "44196397", "screen_name": "example", "name": "Example",
"verified": false, "blue_verified": true,
"followers": 10500, "following": 300, "tweets": 8700
}
}
],
"billing": { "endpoint": "x.search", "units": 3, "unit_price": "0.010000", "amount": "0.030000", "balance_after": "97.00", "request_id": "…" }
}
fetched_at is the UTC timestamp when the result set was captured — engagement
metrics are a snapshot from that moment, so use it to compare the same post
across requests over time. For a deep-history request the response also carries
since, until, window_days, and windows_searched.
Billing
Search is billed per page fetched — units = pages_fetched, minimum 1. In
deep-history mode this is the total pages across all date windows. See
Billing.
Notes
- To pull a single post's full record, call the post endpoint with a
result's
idorurl. - Search is a discovery surface; results are not exhaustive and can shift over time.