How do I get replies or a full thread on X (Twitter)?
Call GET /v1/twitter/posts/{id}/comments. Each request returns one page of direct replies with the author, text, time, and metrics, plus a cursor for the next page. For the replies under a reply, call GET /v1/twitter/posts/{id}/comments/{replyId}/replies.
A self-thread, where the author replies to their own post, is the same call. Filter replies where author.id equals the original author to read the thread in order.
Checked September 2026 · request and response run against the API · no affiliate links
curl "https://api.openhandle.dev/v1/twitter/posts/940100000000000001/comments" \
-H "Authorization: Bearer $OPENHANDLE_API_KEY"import { OpenHandle } from '@openhandle/sdk';
const openhandle = new OpenHandle({ apiKey: process.env.OPENHANDLE_API_KEY! });
let page = await openhandle.twitter.post('940100000000000001').comments.list();
while (page) {
for (const reply of page.data) console.log(reply.author.handle, reply.text);
page = await page.next();
}{
"platform": "twitter",
"resource": "comment",
"capturedAt": "2026-09-18T12:22:41Z",
"source": "live",
"data": [
{
"id": "940200000000000001",
"postId": "940100000000000001",
"text": "Synthetic Twitter reply 1.",
"createdAt": "2026-08-09T15:31:00Z",
"author": { "id": "940000000020", "handle": "reply_signal_x_test" },
"metrics": { "likes": 0, "replies": 0 }
}
],
"meta": { "cursors": { "next": "b3BhcXVlLWN1cnNvcg" } }
}Trimmed to one reply. The example post is a Test fixture with three replies, so you can test paging on a free Test key.
From a status URL
Pass the x.com status URL to POST /v1/urls/fetch or openhandle.fetch(url). It returns the post with its id and conversationId. Then read the replies. Store the ID. URLs carry handles, and handles change.
Thread, replies, quotes
- —Direct replies. The comments endpoint. One level deep, newest as X orders them.
- —Nested replies. The replies endpoint under a comment. Call it for each reply whose
metrics.repliesis above zero. - —The author’s thread. Direct replies where
author.idmatches the original post’s author, sorted bycreatedAt. - —Quote posts. A post that quotes another carries
quotedPost. Search for the original URL to find quotes of it.
Why the old tools half-worked
X loads replies in chunks behind cursors that expire within minutes. Scrapers that paused between pages lost the rest of the thread. Openhandle cursors are bound to the request and stay valid, so a slow pipeline still gets every page.
When this does not work
These answers are definitive. Store them, do not retry them.
| Situation | Status | Code |
|---|---|---|
| The post is deleted or never existed | 404 | POST_NOT_FOUND |
| The author’s account is protected | 403 | PROFILE_PRIVATE |
| The cursor came from another request | 400 | CURSOR_MISMATCH |
{
"error": {
"code": "POST_NOT_FOUND",
"message": "This post was not found.",
"requestId": "req_01j8…",
"retryable": false
}
}A reply from a protected account does not appear. X hides it from logged-out visitors, and so do we. Replies X marks as hidden by the author are not returned either.
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.