All questionsX (Twitter)

How do I search X (Twitter) posts by keyword?

Call the Openhandle search endpoint with your query in q. Pick sort=latest or sort=top. Each request returns one page of public posts with the author, text, time, and metrics, plus a cursor for the next page.

You pay per answered request, not per month. There is no plan to pick and no post cap to plan around.

Checked September 2026 · request and response run against the API · no affiliate links

GET /v1/twitter/search/posts?q=…&sort=latest
curl "https://api.openhandle.dev/v1/twitter/search/posts?q=synthetic&sort=latest" \
  -H "Authorization: Bearer $OPENHANDLE_API_KEY"
TypeScript SDK
import { OpenHandle } from '@openhandle/sdk';

const openhandle = new OpenHandle({ apiKey: process.env.OPENHANDLE_API_KEY! });
let page = await openhandle.twitter.search.posts.list({ q: 'synthetic', sort: 'latest' });

while (page) {
    for (const post of page.data) console.log(post.author.handle, post.text);
    page = await page.next();
}
200 OK
{
  "platform": "twitter",
  "resource": "post",
  "capturedAt": "2026-09-18T09:42:19Z",
  "source": "live",
  "data": [
    {
      "id": "940100000000000001",
      "url": "https://x.com/copperfield_lab_x_test/status/940100000000000001",
      "text": "A deterministic text post from a fictional lab. #synthetic",
      "createdAt": "2026-08-09T15:30:00Z",
      "author": { "id": "940000000001", "handle": "copperfield_lab_x_test" },
      "metrics": { "likes": 42, "reposts": 3, "comments": 3, "quotes": 0, "views": null }
    }
  ],
  "meta": { "cursors": { "next": "b3BhcXVlLWN1cnNvcg" } }
}

Trimmed to one post and the fields this question needs. Views are null here because the Test fixture does not publish them. On a live post, views are the number X shows, or null when X hides it.

Why people leave the official X API

X sells read access in monthly tiers with a fixed post cap. The free tier cannot read. Teams that need a few thousand searches a month pay for a plan sized for far more. Openhandle bills one price per answered request and nothing per month.

Latest or top

  • latest. Newest posts first. Use it for monitoring a brand, a handle, or a product name.
  • top. Posts X ranks highest for the query. Use it for a snapshot of what people see.
  • Replies and threads. A post in the results carries conversationId. Read the thread under it with GET /v1/twitter/posts/{id}/comments.

Monitor a keyword over time

Search returns what X shows now. It does not keep history for you. To monitor a keyword, run sort=latest on a schedule, store each post id, and skip IDs you already have. Store capturedAt with each run so the report can be repeated.

When this does not work

Empty is an answer. A cursor from another query is a mistake.

SituationStatusCode
No public posts match the query200empty data
The cursor came from another query or sort400CURSOR_MISMATCH
400 Bad Request
{
  "error": {
    "code": "CURSOR_MISMATCH",
    "message": "The cursor does not belong to this request.",
    "requestId": "req_01j8…",
    "retryable": false
  }
}

An empty page bills as an answered request. A cursor is bound to its query, sort, and freshness. Change any of them and start without a cursor. Every new workspace starts with 100 free live requests, no card needed.

Read next

More X (Twitter) questions

Send your agent ahead.

Paste the prompt into your agent and it sets everything up. Or come yourself, it takes five minutes.

For agents