Twitter Keyword Search API Tutorial | SandBase
Build a Twitter/X keyword-search workflow: search a timeline, page results, and profile the authors — one SandBase key, no Twitter login, no SDK.

If you track a topic on Twitter/X — a product launch, a hashtag, a competitor — you want a repeatable loop: search the timeline for a keyword, page through matches, and profile the accounts behind the noteworthy tweets. This Twitter Keyword Search API tutorial wires that loop with two SandBase endpoints so an agent can run it end to end. It builds on the Twitter public data API hub; read that first for the big picture.
Everything here is public, read-only data. There is no Twitter login and no SDK — a SandBase API key is still required to authenticate. The endpoint API reference is the source of truth for parameters and the response envelope. The reference guarantees only that envelope; the payload field names below come from calls I ran (tested on 2026-09-28, UTC) and are illustrative, observed-only — not documented guarantees — so confirm them against a live response.
Key takeaway
- Two endpoints form the loop:
search-timeline(find tweets) →user-profile(profile the author).- Each call is
POST /v1/api/twitter/web/<path>with only that endpoint’s params, oneSANDBASE_API_KEY.- Chain by natural inputs: a
keyworddrives search; a tweet’sscreen_namebecomes theusernamefor the profile call.- Page the timeline with the returned
next_cursor. Public, read-only data only.
SandBase vs. the official X API
| Your need | Use |
|---|---|
| Public, read-only search and profiles | SandBase Twitter public-data API |
| Post, DM, or act as an account | X’s official API |
| Private or account-only data | Neither public workflow |
The workflow at a glance
- Search the timeline with
twitter/web/search-timelineusing akeyword. - Profile the authors with
twitter/web/user-profileusing a tweet’sscreen_name.
Each endpoint returns the shared envelope — an id, a status, the model, and the payload on a completed run. The reference documents the payload under outputs[0].data; read it defensively.
The Twitter endpoints on SandBase — search-timeline and user-profile drive this loop.
Step 0: one helper for every call
import os
import requests
API = "https://api.sandbase.ai/v1/api"
HEADERS = {
"Authorization": f"Bearer {os.environ['SANDBASE_API_KEY']}",
"Content-Type": "application/json",
}
def call(path: str, payload: dict) -> dict:
resp = requests.post(f"{API}/{path}", headers=HEADERS, json=payload, timeout=60)
resp.raise_for_status()
body = resp.json()
if body.get("status") != "completed":
raise RuntimeError(body.get("error", {}).get("message", f"{path} did not complete"))
# Envelope can vary: prefer a top-level `output`, else `outputs[0].data`.
output = body.get("output")
if output is None and body.get("outputs"):
output = body["outputs"][0].get("data", {})
return output or {}
Step 1: search the timeline
data = call("twitter/web/search-timeline", {"keyword": "AI agents"})
tweets = data.get("timeline", [])
next_cursor = data.get("next_cursor")
print(len(tweets), "tweets, more:", bool(next_cursor))
In the response I captured (search run id cad13e3a-5e0d-4aa7-b077-2e4883655ffc, tested on 2026-09-28, UTC), the payload carried a timeline list, plus next_cursor and prev_cursor. Each tweet carried tweet_id, text, screen_name, created_at, and engagement counts (favorites, retweets, replies). These are illustrative, observed-only fields — confirm against a live response.
To page, resend search-timeline with the returned next_cursor (confirm the exact parameter name against the reference).
The search-timeline reference — the source of truth for the keyword parameter and paging.
Step 2: profile the authors
screen_names = {t.get("screen_name") for t in tweets if isinstance(t, dict) and t.get("screen_name")}
for name in list(screen_names)[:5]:
profile = call("twitter/web/user-profile", {"username": name})
print(name, "-", profile.get("name"), "|", profile.get("friends"), "following")
The user-profile endpoint takes a username — a tweet’s screen_name works directly. In my run (user-profile run id eb35152f-fa49-4c74-8b80-7e6957efc2b3), the payload carried name, desc, friends, media_count, blue_verified, and created_at — illustrative, observed-only fields the reference does not guarantee. Read each with .get().
The user-profile reference — pass a username; a tweet’s screen_name works as that identifier.
Putting it together
def research(keyword: str, max_authors: int = 5):
data = call("twitter/web/search-timeline", {"keyword": keyword})
tweets = data.get("timeline", [])
seen, authors = set(), []
for t in tweets:
if not isinstance(t, dict):
continue
name = t.get("screen_name")
if name and name not in seen:
seen.add(name)
profile = call("twitter/web/user-profile", {"username": name})
authors.append({"screen_name": name, "profile": profile})
if len(authors) >= max_authors:
break
return {"tweets": tweets, "authors": authors}
Because both endpoints share the same envelope, the loop stays flat: one status check in call(...), one .get() pattern, and the screen_name flowing from a tweet into the profile call.
Common use cases
Brand and launch monitoring
Search a product name or hashtag with search-timeline, page with the cursor, and diff the tweet set across runs to catch spikes in mentions. Profile the loudest accounts to understand who is driving the conversation. Input: a keyword. Output: a timeline plus author profiles. Endpoints: search-timeline, user-profile.
Competitor and creator research
Search a competitor’s name or a niche topic, collect the recurring screen_names, and profile each with user-profile to build a shortlist ranked by follower count and activity. Input: a keyword. Output: ranked author profiles. Endpoints: search-timeline, user-profile.
Topic and sentiment sampling
Pull a keyword’s timeline on a schedule to sample how a topic is discussed over time. Because each tweet carries text and engagement counts, you can feed the sample to a model for downstream classification. Input: a keyword. Output: a timeline sample. Endpoint: search-timeline.
Practical notes
- Envelope can vary. The reference documents
outputs[0].data; read either shape (preferoutput, fall back tooutputs[0].data). - Page with the cursor. Resend
search-timelinewithnext_cursorwhile more results exist. - Business fields are observed-only. Treat
timeline,screen_name,friends, and the like as observed and confirm live. - Public, read-only data only. No posting, DMs, or private/account-only data. Authenticate with a SandBase API key.
- Be a good client. Retry with backoff on transient errors such as HTTP 429; page rather than hammering.
FAQ
Do I need a Twitter/X developer account or login?
No. You authenticate to SandBase with your SANDBASE_API_KEY. These read endpoints need no X account or OAuth on your side.
How do I get from a tweet to its author?
Each tweet in the timeline carries a screen_name; pass it as the username to user-profile.
How do I page through more tweets?
The search payload carries a next_cursor; resend search-timeline with it. Confirm the exact parameter against the reference.
Can I read private tweets or DMs? No. The API returns public data only. Private and account-authorized content are out of scope.
Wrap up
Two endpoints, one envelope, a screen_name flowing between steps — that is the whole keyword-search loop. For the full endpoint catalog, see the Twitter public data API hub. When you are ready: