> ## 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.

# Search community tweets

> Search for tweets across X communities by keyword with optional sort order

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

<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`.
</Note>

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

<CodeGroup>
  ```bash cURL theme={null}
  curl -G https://xquik.com/api/v1/x/communities/search \
    --data-urlencode "q=web development" \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq
  ```

  ```javascript Node.js theme={null}
  const searchQuery = "web development";
  const queryType = "Latest";
  const params = new URLSearchParams({ q: searchQuery, queryType });
  const response = await fetch(`https://xquik.com/api/v1/x/communities/search?${params}`, {
    headers: { "x-api-key": "xq_YOUR_KEY_HERE" },
  });
  const data = await response.json();
  const tweetRows = data.tweets.map((tweet) => {
    const author = tweet.author ?? {};

    return {
      search_query: searchQuery,
      query_type: queryType,
      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,
      like_count: tweet.likeCount ?? null,
      reply_count: tweet.replyCount ?? null,
      retweet_count: tweet.retweetCount ?? null,
      media_urls: tweet.media?.map((item) => item.mediaUrl).filter(Boolean) ?? [],
    };
  });
  const nextCursor = data.has_next_page ? data.next_cursor : null;

  for (const row of tweetRows) {
    process.stdout.write(`${JSON.stringify(row)}\n`);
  }
  if (nextCursor !== null) {
    const checkpoint = {
      search_query: searchQuery,
      query_type: queryType,
      next_cursor: nextCursor,
    };
    process.stdout.write(`${JSON.stringify(checkpoint)}\n`);
  }
  ```

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

  search_query = "web development"
  query_type = "Latest"
  response = requests.get(
      "https://xquik.com/api/v1/x/communities/search",
      params={"q": search_query, "queryType": query_type},
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
  )
  data = response.json()
  tweet_rows = []
  for tweet in data["tweets"]:
      author = tweet.get("author") or {}
      tweet_rows.append(
          {
              "search_query": search_query,
              "query_type": query_type,
              "tweet_id": tweet["id"],
              "text": tweet.get("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"),
              "like_count": tweet.get("likeCount"),
              "reply_count": tweet.get("replyCount"),
              "retweet_count": tweet.get("retweetCount"),
              "media_urls": [
                  item["mediaUrl"]
                  for item in tweet.get("media", [])
                  if item.get("mediaUrl")
              ],
          }
      )

  next_cursor = data["next_cursor"] if data["has_next_page"] else None

  for row in tweet_rows:
      print(json.dumps(row))
  if next_cursor is not None:
      print(json.dumps({
          "search_query": search_query,
          "query_type": query_type,
          "next_cursor": next_cursor,
      }))
  ```
</CodeGroup>

The Node.js & Python snippets shape one durable row per matching community
tweet instead of printing the full response page. Persist the final
`next_cursor` row when `has_next_page` is true, then pass it back as `cursor`
with the same `q` & `queryType`.

## Direct community search handoff

Use `GET /x/communities/search` when a monitoring job, research queue,
moderation review, social listening workflow, or agent needs tweets across X
communities by keyword.

Store `search_query`, `query_type`, `tweet_id`, `text`, `author_id`,
`author_username`, `author_name`, `author_followers`, `author_verified`,
`author_profile_picture`, `created_at`, engagement counts, & `media_urls` for
each row. Keep
`has_next_page` & `next_cursor` with the export checkpoint so the next run can
continue the same community search without duplicating earlier rows.

Set `queryType=Latest` for recent queues or backfills. Set `queryType=Top` for
relevance-ranked review.

<CardGroup cols={2}>
  <Card title="Search row checkpoint" icon="search">
    Store `search_query`, `query_type`, `has_next_page`, and `next_cursor` with
    the tweet rows so the next run resumes the same search.
  </Card>

  <Card title="Sort mode" icon="arrow-down-up">
    Use `Latest` for recent collection and `Top` for relevance-ranked review.
    Keep the same `queryType` when you pass a cursor.
  </Card>

  <Card title="Default page" icon="rows-3">
    Direct calls use the default paid tweet page size. Treat the returned
    `tweets.length` as the row count returned for this page.
  </Card>

  <Card title="Saved export" icon="file-spreadsheet">
    Use `community_search` with `searchQuery` when the workflow needs a saved
    job with CSV/JSON/XLSX output.
  </Card>
</CardGroup>

## Query parameters

<ParamField query="q" type="string" required>
  Search query for community tweets.
</ParamField>

<ParamField query="queryType" type="string">
  Sort order. `Top` returns most relevant tweets, `Latest` returns most recent. Defaults to `Latest`.
</ParamField>

<ParamField query="cursor" type="string">
  Pagination cursor from a previous response. Omit for the first page.
</ParamField>

## Which community search route?

<CardGroup cols={2}>
  <Card title="Community search route" icon="list-filter">
    Use `GET /x/communities/search` for keyword searches across communities.
  </Card>

  <Card title="Cross-community tweets" icon="search">
    Use [`GET /x/communities/tweets`](/api-reference/x/search-community-tweets)
    when your integration already uses that route name. It accepts the same `q`, `queryType`, and `cursor` shape.
  </Card>

  <Card title="Known community posts" icon="message-square-text">
    Use [`GET /x/communities/{id}/tweets`](/api-reference/x/community-tweets)
    for posts from one known community ID.
  </Card>

  <Card title="Bulk community jobs" icon="file-spreadsheet">
    Use [`Create extraction`](/api-reference/extractions/create) with
    `community_search` or `community_post_extractor` when the workflow needs a
    saved export.
  </Card>
</CardGroup>

## Headers

<ParamField header="x-api-key" type="string" required>
  Your API key. Session cookie authentication is also supported.
</ParamField>

## Response

<Tabs>
  <Tab title="200 OK">
    <ResponseField name="tweets" type="object[]">
      Array of matching community tweets.

      <Expandable title="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="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 the tweet is a reply. Omitted if unavailable.</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">Conversation thread ID. Omitted if unavailable.</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="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.

          <Expandable title="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>
          </Expandable>
        </ResponseField>

        <ResponseField name="media" type="object[]">
          Media attachments. Omitted when the tweet has no media.

          <Expandable title="Media object fields">
            <ResponseField name="mediaUrl" type="string">Direct media URL.</ResponseField>
            <ResponseField name="type" type="string">Media type.</ResponseField>
            <ResponseField name="url" type="string">Shortened URL from the tweet text.</ResponseField>
          </Expandable>
        </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>
      </Expandable>
    </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. Pass as the `cursor` query parameter.</ResponseField>

    ```json theme={null}
    {
      "tweets": [
        {
          "id": "1893456789012345678",
          "text": "Great discussion about web development",
          "createdAt": "2026-02-24T10:00:00.000Z",
          "likeCount": 75,
          "retweetCount": 12,
          "replyCount": 8,
          "viewCount": 5400,
          "author": {
            "id": "987654321",
            "username": "devuser",
            "name": "Developer",
            "followers": 25000,
            "verified": false,
            "profilePicture": "https://pbs.twimg.com/profile_images/example.jpg"
          }
        }
      ],
      "has_next_page": true,
      "next_cursor": "DAACCgACGE..."
    }
    ```
  </Tab>

  <Tab title="400 Missing query">
    ```json theme={null}
    { "error": "missing_query" }
    ```

    The `q` query parameter is empty or missing.
  </Tab>

  <Tab title="401 Unauthenticated">
    ```json theme={null}
    { "error": "unauthenticated" }
    ```

    Missing or invalid API key.
  </Tab>

  <Tab title="402 Subscription required">
    ```json theme={null}
    { "error": "no_subscription" }
    ```

    No active subscription or insufficient credits. Possible error values: `no_subscription`, `subscription_inactive`, `no_credits`, `insufficient_credits`.
    For [MPP](/mpp/overview) requests without a valid payment credential, 402 returns a `WWW-Authenticate: Payment` challenge header instead.
  </Tab>

  <Tab title="502 X API unavailable">
    ```json theme={null}
    { "error": "x_api_unavailable" }
    ```

    The read service returned an error. Retry after a short delay.
  </Tab>

  <Tab title="429 Rate Limit Exceeded">
    ```json theme={null}
    { "error": "rate_limit_exceeded", "retryAfter": 60 }
    ```

    Your tier rate limit was exceeded. Wait for the `Retry-After` header before retrying.
  </Tab>

  <Tab title="424 Dependency Failed">
    ```json theme={null}
    { "error": "x_api_unavailable" }
    ```

    The normalized v1 response contract can return 424 when the read service is unavailable.
  </Tab>
</Tabs>

<Note>
  **Next steps:** [Community Info](/api-reference/x/community-info) to look up a community, or [Search Tweets](/api-reference/x/search-tweets) for general tweet search.
</Note>
