curl --request GET \
--url https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search \
--header 'X-API-Key: <api-key>'import requests
url = "https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"bookmark_count": 34,
"content_type": "original",
"conversation_id": "1799123456789",
"display_name": "Cathie Wood",
"entity_mentions": {
"people": [
{
"confidence": 123,
"mention_method": "<string>",
"person_id": 123
}
],
"tickers": [
{
"confidence": 123,
"mention_method": "<string>",
"ticker": "<string>"
}
],
"topics": [
{
"matched_keywords": [
"<string>"
],
"topic_id": "<string>"
}
]
},
"first_observed_at": "2025-04-25T12:00:00Z",
"full_text": "Disruptive innovation will continue.",
"hashtags": [
"AI",
"ETF"
],
"in_reply_to_user_id": "44196397",
"last_edited_at": "2025-04-25T12:40:00Z",
"last_observed_at": "2025-04-25T12:40:00Z",
"like_count": 1234,
"media": [
{
"alt_text": "<string>",
"duration_ms": 15000,
"height": 800,
"media_key": "3_1234",
"preview_image_url": "<string>",
"type": "photo",
"url": "https://pbs.twimg.com/media/foo.jpg",
"variants": [
{
"bit_rate": 123,
"content_type": "video/mp4",
"url": "<string>"
}
],
"width": 1200
}
],
"media_json": "<string>",
"mentions": [
"elonmusk"
],
"meta_json": "<string>",
"platform_id": "1799123456789",
"profile_image_url": "https://pbs.twimg.com/profile_images/1234/avatar_normal.jpg",
"published_at": "2025-04-25T12:34:56Z",
"quote_count": 12,
"referenced_tweet_id": "1799000000001",
"referenced_tweet_type": "quoted",
"referenced_tweets": [
{
"author_display_name": "Elon Musk",
"author_external_id": "44196397",
"author_handle": "elonmusk",
"id": "1799000000001",
"published_at": "2025-04-25T12:34:56Z",
"text": "<string>",
"type": "quoted"
}
],
"reply_count": 78,
"retweet_count": 56,
"source": "<unknown>",
"twitter_handle": "CathieDWood",
"updated_at": "2025-04-25T12:40:00.123456Z",
"url": "https://x.com/CathieDWood/status/1799123456789",
"view_count": 90000
}
],
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}Search X (Twitter) feed
OpenAPI JSON Spec
Full-text search over the tweet corpus via the TweetSearchService
(ESSearch — BM25 ranking on full_text + multilingual analyzers).
Currently only the registry index is searched; pass an optional
handle to restrict the search to a single author.
q is optional: when omitted, the endpoint returns the latest
tweets (sorted by published_at DESC) within the time window.
Anti-scrape rule: when both q and handle are empty, since
must be within the last 30 days (default 30d if omitted). Pass
either q or handle to widen the window back to the 10y default.
sort controls ordering: relevance (default, BM25 over
full_text), latest (reverse-chronological by published_at), or
hottest (by view_count, may be stale). Use latest for
recency/discovery so recent tweets are not buried under
higher-scoring older matches.
Returns HTTP 501 if the upstream search backend is not configured.
Update polling: updated_after + updated_before (Unix seconds,
inclusive after, exclusive before) return the tweets whose
updated_at moved inside the window, ordered by updated_at ASC
then platform_id ASC, paged by pagination.cursor. updated_at
records projection time for a first index or a change to engagement
counts, text, deleted flag, has_media or normalized media content.
Identical observations and retries retain it; last_observed_at
advances on every re-observation and is not a substitute.
A window reaching past what the sync writer has confirmed searchable
is served up to that boundary rather than refused:
pagination.indexed_through (Unix seconds) reports how far the page
is complete, has_more stays true, and a Retry-After header gives
the wait. Page until has_more is false before advancing your own
checkpoint; a page carrying indexed_through is never drained.
Partial search results and an unreadable indexing checkpoint still
return HTTP 503; retry the same bounds and cursor.
The window may span at most 7 days. sort is ignored in this mode
and offset is rejected; q, handle, content_type, has_media,
since and until stay optional intersections and are bound into
the cursor, so send the cursor back unchanged with the same window
and the same filters. limit may change between pages. An omitted
cursor with has_more=false means the window is drained; start each
new window without the old cursor. An omitted cursor with
has_more=true means nothing was indexed yet in this window: ask
again for the same bounds with no cursor. This is current-state polling,
not a snapshot or a deletion feed: overlap your windows, dedupe by
platform_id on content, and expect intermediate versions to
coalesce. Deleted tweets are not surfaced through the window.
curl --request GET \
--url https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search \
--header 'X-API-Key: <api-key>'import requests
url = "https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://data-tools.prd.arrays.org/api/v1/social-feeds/x/search")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"data": [
{
"bookmark_count": 34,
"content_type": "original",
"conversation_id": "1799123456789",
"display_name": "Cathie Wood",
"entity_mentions": {
"people": [
{
"confidence": 123,
"mention_method": "<string>",
"person_id": 123
}
],
"tickers": [
{
"confidence": 123,
"mention_method": "<string>",
"ticker": "<string>"
}
],
"topics": [
{
"matched_keywords": [
"<string>"
],
"topic_id": "<string>"
}
]
},
"first_observed_at": "2025-04-25T12:00:00Z",
"full_text": "Disruptive innovation will continue.",
"hashtags": [
"AI",
"ETF"
],
"in_reply_to_user_id": "44196397",
"last_edited_at": "2025-04-25T12:40:00Z",
"last_observed_at": "2025-04-25T12:40:00Z",
"like_count": 1234,
"media": [
{
"alt_text": "<string>",
"duration_ms": 15000,
"height": 800,
"media_key": "3_1234",
"preview_image_url": "<string>",
"type": "photo",
"url": "https://pbs.twimg.com/media/foo.jpg",
"variants": [
{
"bit_rate": 123,
"content_type": "video/mp4",
"url": "<string>"
}
],
"width": 1200
}
],
"media_json": "<string>",
"mentions": [
"elonmusk"
],
"meta_json": "<string>",
"platform_id": "1799123456789",
"profile_image_url": "https://pbs.twimg.com/profile_images/1234/avatar_normal.jpg",
"published_at": "2025-04-25T12:34:56Z",
"quote_count": 12,
"referenced_tweet_id": "1799000000001",
"referenced_tweet_type": "quoted",
"referenced_tweets": [
{
"author_display_name": "Elon Musk",
"author_external_id": "44196397",
"author_handle": "elonmusk",
"id": "1799000000001",
"published_at": "2025-04-25T12:34:56Z",
"text": "<string>",
"type": "quoted"
}
],
"reply_count": 78,
"retweet_count": 56,
"source": "<unknown>",
"twitter_handle": "CathieDWood",
"updated_at": "2025-04-25T12:40:00.123456Z",
"url": "https://x.com/CathieDWood/status/1799123456789",
"view_count": 90000
}
],
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}{
"data": "<unknown>",
"error": {
"code": "RESOURCE_NOT_FOUND",
"details": [
{
"field": "<string>",
"got": "<string>",
"reason": "<string>"
}
],
"docs_url": "<string>",
"examples": [
"<string>"
],
"hint": "<string>",
"message": "The requested resource was not found.",
"suggestions": [
"<string>"
]
},
"metadata": "<unknown>",
"pagination": "<unknown>",
"request_id": "<string>",
"success": true
}Authorizations
API Key authentication. Example: "your-api-key-here"
Query Parameters
Search query (BM25 over full_text; #tag and @user route to filter clauses). Omit for reverse-chronological listing.
Restrict to tweets authored by this Twitter handle (no @, case-insensitive)
Start time (unix seconds)
End time (unix seconds)
Filter by content type
original, retweet, quote, reply Only return tweets with media when true
Max results (default 50, max 200)
Offset
Result ordering: relevance (default, BM25), latest (reverse-chronological), or hottest (by view_count)
relevance, latest, hottest Inclusive tweet-update bound (Unix seconds); requires updated_before
Exclusive tweet-update bound (Unix seconds); must be greater than updated_after and at most 7 days past it
Opaque update-window continuation; incompatible with offset

