Blog/Developer Tools/

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.

Dark cinematic render of a Twitter keyword search resolving into a timeline and an author profile, feeding an agent core

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, one SANDBASE_API_KEY.
  • Chain by natural inputs: a keyword drives search; a tweet’s screen_name becomes the username for the profile call.
  • Page the timeline with the returned next_cursor. Public, read-only data only.

SandBase vs. the official X API

Your needUse
Public, read-only search and profilesSandBase Twitter public-data API
Post, DM, or act as an accountX’s official API
Private or account-only dataNeither public workflow

The workflow at a glance

  1. Search the timeline with twitter/web/search-timeline using a keyword.
  2. Profile the authors with twitter/web/user-profile using a tweet’s screen_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.

SandBase Twitter API page with the endpoints used in this workflow 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).

SandBase API reference for the Twitter search-timeline endpoint 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().

SandBase API reference for the Twitter user-profile endpoint 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 (prefer output, fall back to outputs[0].data).
  • Page with the cursor. Resend search-timeline with next_cursor while 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: