> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xquik.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Tweet thread API, conversation export & authors

> Retrieve the tweet thread around one tweet with authors, reply relationships, text, media, engagement metrics, and cursors. Costs 1 credit per tweet returned.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-x-tweet-thread-200">
      ```json theme={null}
      {
        "tweets": [],
        "has_next_page": false,
        "next_cursor": ""
      }
      ```
    </Tab>

    <Tab title="400" id="response-x-tweet-thread-400">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

    <Tab title="401" id="response-x-tweet-thread-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required."
      }
      ```
    </Tab>

    <Tab title="402" id="response-x-tweet-thread-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits. Top up or subscribe to continue."
      }
      ```
    </Tab>

    <Tab title="404" id="response-x-tweet-thread-404">
      ```json theme={null}
      {
        "error": "tweet_not_found",
        "message": "Tweet not found. Check the tweet ID."
      }
      ```
    </Tab>

    <Tab title="424" id="response-x-tweet-thread-424">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "X data source temporarily unavailable. Try again later."
      }
      ```
    </Tab>

    <Tab title="429" id="response-x-tweet-thread-429">
      ```json theme={null}
      {
        "error": "rate_limit_exceeded",
        "message": "Too many requests. Try again later.",
        "retryAfter": 60
      }
      ```
    </Tab>

    <Tab title="502" id="response-x-tweet-thread-502">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "X data source temporarily unavailable. Try again later."
      }
      ```
    </Tab>

    <Tab title="503" id="response-x-tweet-thread-503">
      ```json theme={null}
      {
        "error": "x_api_unavailable",
        "message": "Xquik is busy right now. Retry shortly."
      }
      ```
    </Tab>
  </Tabs>
</Panel>

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

<Note>
  Repost records include `retweetedAt`, the repost event's UTC ISO 8601 timestamp. It is `null` when
  that timestamp is unavailable. The API omits it for original posts. The nested original post keeps
  its own creation date. This field does not report every account that reposted a post. [Request
  per-account timestamps with Get retweeters.](/api-reference/x/retweeters#retweet-timestamps)
</Note>

Requested result counts are upper bounds for paid authenticated calls. When remaining credits cannot cover the full page or ID list, Xquik returns fewer results. If zero paid results are affordable, it returns `402 insufficient_credits`.

<Callout icon="coins" color="#5c3327">
  **1 credit per tweet returned** · [All plans](https://xquik.com/#pricing) from \$0.00012/credit · Supports [guest paid reads](/guides/guest-wallets)
</Callout>

Get tweet thread returns tweet rows in the conversation thread around one
source tweet. Results exclude X ads. The
endpoint is `GET /api/v1/x/tweets/{id}/thread`.

A post X does not have returns `404 tweet_not_found`, as
[Get tweet](/api-reference/x/get-tweet) does. Deleted, suspended-account &
protected posts count as missing. A 404 costs no credits.

<CodeGroup>
  ```bash First page theme={null}
  curl "https://xquik.com/api/v1/x/tweets/1893456789012345678/thread" \
    -H "x-api-key: xq_your_api_key_here" | jq
  ```

  ```bash Next page theme={null}
  curl -G https://xquik.com/api/v1/x/tweets/1893456789012345678/thread \
    --data-urlencode "cursor=abc123" \
    -H "x-api-key: xq_your_api_key_here" | jq
  ```

  ```javascript Node.js theme={null}
  const tweetId = "1893456789012345678";
  const cursor = process.env.XQUIK_CURSOR ?? "";
  const params = new URLSearchParams();
  if (cursor !== "") {
    params.set("cursor", cursor);
  }
  const query = params.toString();
  const url = `https://xquik.com/api/v1/x/tweets/${tweetId}/thread${query ? `?${query}` : ""}`;
  const response = await fetch(url, {
    headers: { "x-api-key": "xq_your_api_key_here" },
  });
  const data = await response.json();
  const nextCursor = data.has_next_page ? data.next_cursor : null;
  const threadRows = data.tweets.map((tweet) => {
    const author = tweet.author ?? {};

    return {
      source_tweet_id: tweetId,
      thread_tweet_id: tweet.id,
      text: tweet.text,
      author_id: author.id ?? null,
      author_username: author.username ?? null,
      author_name: author.name ?? null,
      author_followers: author.followers ?? null,
      author_verified: author.verified ?? null,
      author_profile_picture: author.profilePicture ?? null,
      created_at: tweet.createdAt ?? null,
      conversation_id: tweet.conversationId ?? null,
      in_reply_to_id: tweet.inReplyToId ?? null,
      media_urls: tweet.media?.map((item) => item.mediaUrl).filter(Boolean) ?? [],
    };
  });
  const checkpoint = { source_tweet_id: tweetId, next_cursor: nextCursor };

  for (const row of threadRows) {
    process.stdout.write(`${JSON.stringify(row)}\n`);
  }
  process.stdout.write(`${JSON.stringify({ checkpoint })}\n`);
  ```

  ```python Python theme={null}
  import json
  import requests

  tweet_id = "1893456789012345678"
  cursor = ""
  params = {"cursor": cursor} if cursor else None
  response = requests.get(
      f"https://xquik.com/api/v1/x/tweets/{tweet_id}/thread",
      params=params,
      headers={"x-api-key": "xq_your_api_key_here"},
  )
  data = response.json()
  next_cursor = data["next_cursor"] if data["has_next_page"] else None
  thread_rows = []
  for tweet in data["tweets"]:
      author = tweet.get("author") or {}
      thread_rows.append(
          {
              "source_tweet_id": tweet_id,
              "thread_tweet_id": tweet["id"],
              "text": tweet["text"],
              "author_id": author.get("id"),
              "author_username": author.get("username"),
              "author_name": author.get("name"),
              "author_followers": author.get("followers"),
              "author_verified": author.get("verified"),
              "author_profile_picture": author.get("profilePicture"),
              "created_at": tweet.get("createdAt"),
              "conversation_id": tweet.get("conversationId"),
              "in_reply_to_id": tweet.get("inReplyToId"),
              "media_urls": [
                  item["mediaUrl"]
                  for item in tweet.get("media", [])
                  if item.get("mediaUrl")
              ],
          }
      )
  checkpoint = {"source_tweet_id": tweet_id, "next_cursor": next_cursor}

  for row in thread_rows:
      print(json.dumps(row))
  print(json.dumps({"checkpoint": checkpoint}))
  ```
</CodeGroup>

The Node.js and Python snippets write JSON Lines thread rows plus a separate
checkpoint. They do not write raw response pages. Store each mapped row and the latest
`next_cursor`. A support timeline, research job, moderation queue, or agent
handoff can then resume from the last completed page without duplicate rows.

## Direct tweet thread handoff

Use `GET /api/v1/x/tweets/{id}/thread` when a workflow needs ordered thread
rows around one tweet. Store `source_tweet_id`,
`thread_tweet_id`, `text`, `author_id`, `author_username`, `author_name`,
`author_followers`, `author_verified`, `author_profile_picture`, `created_at`,
`conversation_id`, `in_reply_to_id`, media URLs, and a separate `next_cursor`
checkpoint for later jobs.

<CardGroup cols={2}>
  <Card title="Thread rows" icon="list-tree">
    Store `tweets[]` as the thread context rows returned for one source tweet.
  </Card>

  <Card title="Stable upserts" icon="key-round">
    Store `tweets[].id` as `thread_tweet_id` with `source_tweet_id` for
    idempotent imports.
  </Card>

  <Card title="Reply joins" icon="message-square-reply">
    Store `conversationId`, `inReplyToId`, `inReplyToUserId`, and
    `inReplyToUsername` to rebuild thread structure.
  </Card>

  <Card title="Author joins" icon="user-round">
    Store `tweets[].author.id`, `username`, `name`, `followers`, `verified`, and
    `profilePicture` for review, CRM, or research tools.
  </Card>

  <Card title="Media context" icon="image">
    Store `media[].mediaUrl`, `entities`, `quoted_tweet`, and `retweeted_tweet`
    when returned to keep attached context.
  </Card>

  <Card title="Next page" icon="arrow-right">
    Store `has_next_page` and `next_cursor`, then pass `next_cursor` back as `cursor`
    only when `has_next_page` is true.
  </Card>

  <Card title="Credit-limited pages" icon="coins">
    Use `tweets.length`, not a requested page size, for row counts. Low balances
    can return fewer rows.
  </Card>

  <Card title="Saved exports" icon="file-spreadsheet">
    Use `thread_extractor` when you need a saved extraction job or CSV, JSON, or
    XLSX export.
  </Card>
</CardGroup>

Direct tweet thread reads cost 1 credit per tweet returned. Low credit balances
can return fewer tweets than a full page. Zero affordable results return
`402 insufficient_credits`.

## Reconstruct an ordered tweet thread

Use this route when several connected posts form one authored sequence. Start
from a known tweet ID.

Store each tweet ID, text, author, creation time, engagement counts, media, and
thread position. Keep the starting tweet ID with the complete result.

Render posts in the returned thread order. Do not sort by engagement counts.
Keep media and quote relationships inside each post.

Thread results can support long-form reading, approved archiving, or
conversation context. A reply from another author may belong to a different
conversation path.

Use tweet replies for responses under one post. Use quote tweets for external
commentary. Use exact tweet lookup when only one post is required.

## Path parameters

<ParamField path="id" type="string" required>
  Post ID or URL-encoded post URL, such as `x.com/nasa/status/20`. See [path IDs](/api-reference/overview#path-ids).
</ParamField>

## Query parameters

<ParamField query="cursor" type="string">
  Pagination cursor from `next_cursor` in a previous response. Omit for the
  first page. Pass a cursor only when `has_next_page` is true.
</ParamField>

<ParamField query="pageSize" type="integer">
  Tweets per page. Range: `1-100`. Defaults to `20`.
</ParamField>

### Tweet result filters

<ParamField query="fromUser" type="string">
  Filter to posts from this username. The `@` prefix is optional.
</ParamField>

<ParamField query="toUser" type="string">
  Filter to replies directed to this username.
</ParamField>

<ParamField query="mentioning" type="string">
  Filter to posts that mention this username.
</ParamField>

<ParamField query="language" type="string">
  Only include posts with this language code.
</ParamField>

<ParamField query="sinceDate" type="string">
  Include posts created on or after this date or timestamp.
</ParamField>

<ParamField query="untilDate" type="string">
  Include posts up to this date or timestamp. A date is a UTC day, inclusive, so its own posts count.
</ParamField>

<ParamField query="mediaType" type="string">
  Use `images`, `videos`, `gifs`, `media`, `links`, or `none`.
</ParamField>

<ParamField query="minLikes" type="integer">
  Require this minimum like count.
</ParamField>

<ParamField query="minRetweets" type="integer">
  Require this minimum repost count.
</ParamField>

<ParamField query="minReplies" type="integer">
  Require this minimum reply count.
</ParamField>

<ParamField query="minQuotes" type="integer">
  Require this minimum quote count.
</ParamField>

<ParamField query="minViews" type="integer">
  Require this minimum view count.
</ParamField>

<ParamField query="minBookmarks" type="integer">
  Require this minimum bookmark count.
</ParamField>

<ParamField query="maxFaves" type="integer">
  Allow this maximum like count. Missing counts pass.
</ParamField>

<ParamField query="maxRetweets" type="integer">
  Allow this maximum repost count. Missing counts pass.
</ParamField>

<ParamField query="maxReplies" type="integer">
  Allow this maximum reply count. Missing counts pass.
</ParamField>

<ParamField query="maxQuotes" type="integer">
  Allow this maximum quote count. Missing counts pass.
</ParamField>

<ParamField query="blueVerifiedOnly" type="boolean">
  When `true`, only return posts from Blue-verified authors.
</ParamField>

<ParamField query="verifiedOnly" type="boolean">
  When `true`, only return posts from verified authors.
</ParamField>

<ParamField query="replies" type="string">
  Use `include`, `exclude`, or `only` for replies.
  This setting overrides `includeReplies` when the endpoint supports both.
</ParamField>

<ParamField query="retweets" type="string">
  Use `include`, `exclude`, or `only` for reposts.
</ParamField>

<ParamField query="exactPhrase" type="string">
  Match this literal phrase, including any hyphens.
</ParamField>

<ParamField query="excludeWords" type="string">
  Exclude comma-separated or whitespace-separated terms.
</ParamField>

<ParamField query="anyWords" type="string">
  Require at least 1 comma-separated or whitespace-separated term.
</ParamField>

<ParamField query="hashtags" type="string">
  Match these hashtags. Separate values with commas or spaces.
</ParamField>

<ParamField query="cashtags" type="string">
  Match these cashtags. Separate values with commas or spaces.
</ParamField>

<ParamField query="quotes" type="string">
  Use `include`, `exclude`, or `only` for quote posts.
</ParamField>

<ParamField query="url" type="string">
  URL substring or domain that must appear in tweet URL entities.
</ParamField>

<ParamField query="conversationId" type="string">
  Filter to tweets in this conversation thread.
</ParamField>

<ParamField query="inReplyToTweetId" type="string">
  Only include replies to this tweet ID.
</ParamField>

<ParamField query="quotesOfTweetId" type="string">
  Filter to quote tweets of this tweet ID.
</ParamField>

<ParamField query="retweetsOfTweetId" type="string">
  Filter to retweets of this tweet ID.
</ParamField>

<ParamField query="sinceId" type="string">
  Return Tweets whose IDs exceed this ID.
</ParamField>

<ParamField query="maxId" type="string">
  Return Tweets at or below this ID.
</ParamField>

<ParamField query="nativeRetweets" type="boolean">
  When `true`, only return native reposts.
</ParamField>

<ParamField query="withinTime" type="string">
  Match Tweets from this recent window, such as `90m` or `7d`. Use a whole number & `s`, `m`, `h` or `d`.
</ParamField>

## Which thread endpoint?

<CardGroup cols={2}>
  <Card title="Tweet thread" icon="list-tree">
    Use `GET /x/tweets/{id}/thread` for conversation thread context around one
    tweet.
  </Card>

  <Card title="Tweet replies" icon="message-square-reply">
    Use [`GET /x/tweets/{id}/replies`](/api-reference/x/tweet-replies) when you
    need reply tweet rows under one source tweet.
  </Card>

  <Card title="Quote tweets" icon="quote">
    Use [`GET /x/tweets/{id}/quotes`](/api-reference/x/tweet-quotes) for tweet
    rows that quote one source tweet.
  </Card>

  <Card title="Search tweets" icon="search">
    Use [`GET /x/tweets/search`](/api-reference/x/search-tweets) when you need
    keyword, operator, or structured-filter discovery across many tweets.
  </Card>

  <Card title="Saved exports" icon="file-spreadsheet">
    Use [`Create extraction`](/api-reference/extractions/create) with
    `toolType=thread_extractor` when you need a saved job or CSV, JSON, or XLSX
    export.
  </Card>

  <Card title="Single tweet" icon="message-square">
    Use [`Get tweet`](/api-reference/x/get-tweet) when you only need one tweet
    object by ID.
  </Card>
</CardGroup>

## Headers

<ParamField header="x-api-key" type="string">
  Full account key. Sessions and OAuth also work.
</ParamField>

<ParamField header="Authorization" type="string">
  `Bearer xq_your_guest_key_here` for `paid_reads`.
</ParamField>

## Response

### 200 OK

<ResponseField name="tweets" type="object[]">
  Array of tweets in the thread, in time order.
  **Tweet object fields.**

  <ResponseField name="id" type="string">Tweet ID.</ResponseField>
  <ResponseField name="text" type="string">Tweet text.</ResponseField>
  <ResponseField name="type" type="string">Tweet type. Omitted if unavailable.</ResponseField>
  <ResponseField name="createdAt" type="string">ISO 8601 creation timestamp.</ResponseField>
  <ResponseField name="isNoteTweet" type="boolean">Whether this is a Note Tweet. Omitted if unavailable.</ResponseField>
  <ResponseField name="isPinned" type="boolean">Whether the author pinned this post to their profile. Omitted if unavailable.</ResponseField>
  <ResponseField name="likeCount" type="number">Like count. Omitted if unavailable.</ResponseField>
  <ResponseField name="retweetCount" type="number">Retweet count. Omitted if unavailable.</ResponseField>
  <ResponseField name="replyCount" type="number">Reply count. Omitted if unavailable.</ResponseField>
  <ResponseField name="quoteCount" type="number">Quote tweet count. Omitted if unavailable.</ResponseField>
  <ResponseField name="viewCount" type="number">View count. Omitted if unavailable.</ResponseField>
  <ResponseField name="bookmarkCount" type="number">Bookmark count. Omitted if unavailable.</ResponseField>
  <ResponseField name="url" type="string">Permalink URL on X. Omitted if unavailable.</ResponseField>
  <ResponseField name="lang" type="string">Tweet language code. Omitted if unavailable.</ResponseField>
  <ResponseField name="isReply" type="boolean">Whether this tweet is a reply in the thread.</ResponseField>
  <ResponseField name="inReplyToId" type="string">Tweet ID being replied to. Omitted if not a reply.</ResponseField>
  <ResponseField name="inReplyToUserId" type="string">User ID being replied to. Omitted if unavailable.</ResponseField>
  <ResponseField name="inReplyToUsername" type="string">Username being replied to. Omitted if unavailable.</ResponseField>
  <ResponseField name="conversationId" type="string">Thread conversation ID.</ResponseField>
  <ResponseField name="source" type="string">Client used to post the tweet. Omitted if unavailable.</ResponseField>
  <ResponseField name="displayTextRange" type="number[]">Start and end offsets for rendered tweet text. Omitted if unavailable.</ResponseField>
  <ResponseField name="isLimitedReply" type="boolean">Whether replies are limited. Omitted if unavailable.</ResponseField>
  <ResponseField name="isQuoteStatus" type="boolean">Whether this tweet quotes another tweet. Omitted if unavailable.</ResponseField>
  <ResponseField name="isRetweet" type="boolean">Whether this row is a retweet. `text` carries the original post in full.</ResponseField>
  <ResponseField name="entities" type="object">Parsed entities. Omitted if unavailable.</ResponseField>
  <ResponseField name="contentDisclosure" type="object">Disclosure metadata for paid partnership and AI-generated media labels. Includes `advertising.isPaidPromotion` and `aiGenerated.hasAiGeneratedMedia` when X returns them. Omitted if unavailable.</ResponseField>

  <ResponseField name="author" type="object">
    Tweet author profile. Omitted if unavailable.
    **Author object fields.**
    <ResponseField name="id" type="string">Author user ID.</ResponseField>
    <ResponseField name="username" type="string">Author handle without `@`.</ResponseField>
    <ResponseField name="name" type="string">Author display name. Omitted if unavailable.</ResponseField>
    <ResponseField name="followers" type="number">Follower count. Omitted if unavailable.</ResponseField>
    <ResponseField name="verified" type="boolean">Whether the author is verified. Omitted if unavailable.</ResponseField>
    <ResponseField name="profilePicture" type="string">Author profile image URL. Omitted if unavailable.</ResponseField>
  </ResponseField>

  <ResponseField name="media" type="object[]">
    Media attachments. Omitted when the tweet has no media.
    **Media object fields.**
    <ResponseField name="mediaUrl" type="string">Direct media URL.</ResponseField>
    <ResponseField name="videoVariants" type="object[]">Available video renditions with bitrate, content type, and URL. Omitted for images.</ResponseField>
    <ResponseField name="type" type="string">Media type.</ResponseField>
    <ResponseField name="url" type="string">Shortened URL from the tweet text.</ResponseField>
  </ResponseField>

  <ResponseField name="quoted_tweet" type="object">Embedded quoted tweet. Omitted if not a quote tweet.</ResponseField>
  <ResponseField name="retweeted_tweet" type="object">Original retweeted tweet. Omitted if not a retweet.</ResponseField>
</ResponseField>

<ResponseField name="has_next_page" type="boolean">Whether more results are available.</ResponseField>
<ResponseField name="next_cursor" type="string">Cursor for the next page.</ResponseField>

```json theme={null}
{
  "tweets": [
    {
      "id": "1893456789012345678",
      "text": "Thread starts here...",
      "createdAt": "2026-03-27T10:00:00.000Z",
      "author": {
        "id": "9876543210",
        "username": "xquik",
        "name": "Xquik",
        "followers": 12000,
        "verified": true,
        "profilePicture": "https://pbs.twimg.com/profile_images/example.jpg"
      }
    }
  ],
  "has_next_page": false,
  "next_cursor": ""
}
```

### 400 Invalid tweet ID

```json theme={null}
{ "error": "invalid_tweet_id" }
```

### 401 Unauthenticated

Anonymous requests get `WWW-Authenticate: Bearer` and a guest wallet checkout action. This is not a Payment challenge.

```json theme={null}
{ "error": "unauthenticated" }
```

### 402 Payment required

Account keys get account options. Guest keys get guest top-up only.
No checkout starts automatically. Confirm any payment action.

### 502 X API unavailable

```json theme={null}
{ "error": "x_api_unavailable" }
```

The read service returned an error. Retry after a short delay.

### 429 Rate limit exceeded

```json theme={null}
{ "error": "rate_limit_exceeded", "retryAfter": 60 }
```

You exceeded your tier rate limit. Wait for the `Retry-After` header before retrying.

### 424 Dependency failed

```json theme={null}
{ "error": "x_api_unavailable" }
```

The normalized v1 response contract can return 424 when the read service is unavailable.

<Note>
  **Related.** [Tweet replies](/api-reference/x/tweet-replies) · [Quote tweets](/api-reference/x/tweet-quotes) · [Retweeters](/api-reference/x/retweeters) · [Create extraction](/api-reference/extractions/create)
</Note>

<div className="related-api-links">
  <Accordion title="Related tweet, reply & media APIs" icon="link">
    * Tweets: [Get tweet](/api-reference/x/get-tweet) · [Batch tweets](/api-reference/x/batch-tweets) · [Tweet thread](/api-reference/x/tweet-thread) · [Hidden replies](/api-reference/x/tweet-hidden-replies) · [Translate tweet](/api-reference/x/tweet-translation) · [Embed tweet](/api-reference/x/tweet-embed) · [Resolve links](/api-reference/x/resolve-links) · [Tweet subtitles](/api-reference/x/tweet-subtitles) · [X Article](/api-reference/x/get-article)
    * Analysis: [Sentiment analysis](/api-reference/x/sentiment-analysis) · [Brand mentions](/api-reference/x/brand-monitoring) · [News classification](/api-reference/x/news-classification) · [Market signals](/api-reference/x/market-signals) · [Viral score](/api-reference/x/viral-score) · [Classify posts](/api-reference/x/classify-tweets)
    * Engagement: [Tweet replies](/api-reference/x/tweet-replies) · [Quote tweets](/api-reference/x/tweet-quotes) · [Likers](/api-reference/x/favoriters) · [Reposters](/api-reference/x/retweeters) · [Check repost](/api-reference/x/tweet-repost-check)
    * Profiles: [User tweets](/api-reference/x/user-tweets) · [Batch user tweets](/api-reference/x/batch-user-tweets) · [User replies](/api-reference/x/user-replies) · [User likes](/api-reference/x/user-likes) · [User media](/api-reference/x/user-media) · [User highlights](/api-reference/x/user-highlights) · [User articles](/api-reference/x/user-articles)
    * Feeds: [List tweets](/api-reference/x/list-tweets) · [Trends](/api-reference/x/trends) · [Trend locations](/api-reference/x/trend-locations) · [Search Spaces](/api-reference/x/search-spaces) · [Get Space](/api-reference/x/get-space) · [Space replay](/api-reference/x/space-replay) · [Get broadcast](/api-reference/x/get-broadcast) · [Hashflags](/api-reference/x/hashflags) · [Search places](/api-reference/x/search-places) · [Download media](/api-reference/x/download-media)
  </Accordion>
</div>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.