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 October 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": "cache",
  "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-17T14:00: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

The X API bills $0.005 for each post a search returns. A search that returns 100 posts costs $0.50. X’s pricing page lists no free tier. Openhandle bills one price per answered request, however many posts the page holds, 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

100 free requests. No card needed.