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

# Twitter scraper API for tweets, replies & followers

> Use the Twitter scraper API to scrape tweets, export follower and following profiles, collect reply authors, paginate JSON, and download CSV, JSON, or XLSX.

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

Run bulk data extractions from X in 5 stages: check credits, estimate costs, run the job, retrieve JSON pages, and export files. Use this workflow to scrape tweets, export followers, pull tweet replies, save CSV, JSON, or XLSX files, or hand paginated JSON to a CRM, warehouse, queue, or AI agent.

Use `reply_extractor` for reply authors and `follower_explorer` for profiles.
Jobs also cover posts, communities, lists, likes, reposts, quotes, and media.
Retrieve structured JSON or export CSV, JSON, or XLSX files.
Tweet search results can filter authors, dates, engagement, media, relationships, lists, and locations.

## Workflow overview

| Extraction stage | Exact API call | Durable checkpoint |
| - | - | - |
| Check credits | `GET /account` | Available balance |
| Estimate results | `POST /extractions/estimate` | `allowed`, `estimatedCost`, `estimatedResults`, `source` |
| Start scraping | `POST /extractions` | `id`, `toolType`, `status` |
| Retrieve rows | `GET /extractions/{id}` | `nextCursor` while `hasMore` is true |
| Export a file | `GET /extractions/{id}/export` | Job ID, format, filename, destination |

<Info>
  Treat `202 Accepted` as a queued run receipt. Xquik reserves credits after the job starts. Poll `GET /extractions/{id}` before handoff. The run can lower `resultsLimit` to the affordable count or fail with `insufficient_credits`.
</Info>

<Steps>
  <Step title="Check credits">
    Verify that your available credit balance can cover the job.
  </Step>

  <Step title="Estimate cost">
    Preview the extraction cost before committing. Check whether it fits within your remaining budget.
  </Step>

  <Step title="Run the extraction">
    Submit the extraction job, store the `202 Accepted` receipt, then poll before handoff.
  </Step>

  <Step title="Retrieve results">
    Paginate through extracted data via the API, or export as CSV, JSON, XLSX, Markdown, PDF, or TXT.
  </Step>

  <Step title="Export files">
    Download CSV, JSON, XLSX, Markdown, PDF, or TXT when the next tool expects a file.
  </Step>
</Steps>

## End-to-end agent handoff

Store one checkpoint per extraction run so another worker can resume without rereading logs:

```json theme={null}
{
  "workflow": "reply_extractor_to_csv",
  "request": {
    "toolType": "reply_extractor",
    "targetTweetId": "1893704267862470862",
    "resultsLimit": 500
  },
  "estimate": {
    "estimatedResults": 500,
    "creditsRequired": "500",
    "creditsAvailable": "77000",
    "allowed": true,
    "source": "replyCount"
  },
  "create_receipt": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "running",
    "poll_path": "/api/v1/extractions/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  },
  "json_pages": {
    "limit": 1000,
    "page_cursor": null,
    "next_cursor": "990200",
    "has_more": true
  },
  "inventory_path": "/api/v1/extractions?status=completed&toolType=reply_extractor",
  "export_path": "/api/v1/extractions/a1b2c3d4-e5f6-7890-abcd-ef1234567890/export?format=csv",
  "handoff_state": "poll_until_completed_then_export"
}
```

<CardGroup cols={2}>
  <Card title="Estimate checkpoint" icon="calculator">
    Store `estimatedResults`, `creditsRequired`, `creditsAvailable`, `allowed`, and `source` before creating the job.
  </Card>

  <Card title="Create receipt" icon="clipboard-check">
    Store the returned job `id`, `status`, and `poll_path`. Result rows arrive from `GET /extractions/{id}`.
  </Card>

  <Card title="Cursor state" icon="shuffle">
    Store `page_cursor`, `next_cursor`, and `has_more` for each JSON page so workers can resume pagination.
  </Card>

  <Card title="File handoff" icon="download">
    Store `inventory_path` for later job lookup and `export_path` for the CSV, JSON, or XLSX download.
  </Card>
</CardGroup>

## Step 1: check credits

Before running an extraction, call [`GET /account`](/api-reference/account/get)
and store a small planning checkpoint:

```bash cURL theme={null}
curl -s https://xquik.com/api/v1/account \
  -H "x-api-key: xq_YOUR_KEY_HERE" | jq
```

```json theme={null}
{
  "checkpoint_type": "credit_check",
  "plan": "active",
  "credit_balance": "77000",
  "next_action": "estimate_extraction"
}
```

Store `plan` for billing context. Use `creditInfo.balance` to decide whether to
continue, top up, or lower `resultsLimit` before estimating the extraction.

## Step 2: estimate cost

Use the estimate endpoint first.
It shows expected rows and credits without charging you.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/extractions/estimate \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Content-Type: application/json" \
    -d '{
      "toolType": "reply_extractor",
      "targetTweetId": "1893704267862470862"
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const estimate = await fetch("https://xquik.com/api/v1/extractions/estimate", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      toolType: "reply_extractor",
      targetTweetId: "1893704267862470862",
    }),
  }).then((r) => r.json());

  if (!estimate.allowed) {
    throw new Error(
      `Insufficient credits: need ${estimate.creditsRequired}, have ${estimate.creditsAvailable}`,
    );
  }

  console.log(`Estimated results: ${estimate.estimatedResults}`);
  ```

  ```python Python theme={null}
  estimate = requests.post(
      "https://xquik.com/api/v1/extractions/estimate",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={
          "toolType": "reply_extractor",
          "targetTweetId": "1893704267862470862",
      },
  ).json()

  if not estimate["allowed"]:
      raise Exception(f"Insufficient credits: need {estimate['creditsRequired']}, have {estimate['creditsAvailable']}")

  print(f"Estimated results: {estimate['estimatedResults']}")
  ```
</CodeGroup>

**Response.**

```json theme={null}
{
  "allowed": true,
  "creditsRequired": "150",
  "creditsAvailable": "77000",
  "estimatedResults": 150,
  "source": "replyCount",
  "resolvedXUserId": "44196397"
}
```

The estimate reports:

* `allowed`, `creditsRequired`, and `creditsAvailable`: affordability and balance.
* `source` and `estimatedResults`: count basis and projected rows.
* `resolvedXUserId`: the ID returned by count-based profile estimates.

<Warning>
  `allowed: false` means your balance cannot fund the full estimate. Add credits or lower `resultsLimit`.
</Warning>

<Tip>
  `resultsLimit` defaults to `10,000` for estimates and jobs. Set any positive integer for a different bound. Billing follows unique emitted results. Source counts such as `followers` or `replyCount` can produce a smaller estimate.
</Tip>

## Step 3: run the extraction

Submit the job with the same parameters you used for the estimate.

<CodeGroup>
  ```bash cURL theme={null}
  IDEMPOTENCY_KEY=$(uuidgen)
  curl -X POST https://xquik.com/api/v1/extractions \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "toolType": "reply_extractor",
      "targetTweetId": "1893704267862470862"
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const idempotencyKey = crypto.randomUUID();
  const extraction = await fetch("https://xquik.com/api/v1/extractions", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Idempotency-Key": idempotencyKey,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      toolType: "reply_extractor",
      targetTweetId: "1893704267862470862",
    }),
  }).then((r) => r.json());

  console.log(`Job ${extraction.id}: ${extraction.status}`);
  ```

  ```python Python theme={null}
  from uuid import uuid4

  extraction = requests.post(
      "https://xquik.com/api/v1/extractions",
      headers={"x-api-key": "xq_YOUR_KEY_HERE", "Idempotency-Key": str(uuid4())},
      json={
          "toolType": "reply_extractor",
          "targetTweetId": "1893704267862470862",
      },
  ).json()

  print(f"Job {extraction['id']}: {extraction['status']}")
  ```
</CodeGroup>

**Response.**

```json theme={null}
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "pollAfterMs": 1000,
  "statusUrl": "/api/v1/extractions/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "waitUrl": "/api/v1/extractions/a1b2c3d4-e5f6-7890-abcd-ef1234567890?wait=10&limit=1&outputMode=compact",
  "toolType": "reply_extractor",
  "status": "running"
}
```

The endpoint returns `202 Accepted`. Save the key with the job ID. Reuse that
key only after a timeout or lost response. An exact retry returns the original
job with `Idempotency-Replayed: true`. A changed request returns `409`. A
terminal replay sets `pollAfterMs` to `0` and omits `Retry-After`.

## Step 4: retrieve results

Follow `waitUrl` until terminal. Save row count, cursor, and format before result loading.

## Data handoff

<CardGroup cols={2}>
  <Card title="App or API pipeline" icon="code">
    Use `GET /extractions/{id}`. Store `job`, `results`, `hasMore`, `nextCursor`.
    Use `limit` up to 1,000 and pass `nextCursor` as `cursor`.
    Use compact output for core fields and tweet counts.
  </Card>

  <Card title="CRM import" icon="users">
    Use `GET /extractions/{id}/export?format=csv`. Store `User ID`,
    `Username`, `Display Name`, `Followers`, and `Verified`. Upsert by stable X
    user ID when possible.
  </Card>

  <Card title="Warehouse or queue" icon="database">
    Use `GET /extractions/{id}/export?format=json` or paginated JSON. Store
    `xUserId`, `xUsername`, `tweetId`, `tweetText`, `createdAt`. Keep the
    extraction ID with each load for replay and audit.
  </Card>

  <Card title="Analyst review" icon="file-spreadsheet">
    Use `GET /extractions/{id}/export?format=xlsx`. Store export columns plus
    enrichment fields. Use CSV or JSON for automation and XLSX for manual review.
  </Card>
</CardGroup>

The export limit does not cap paginated JSON. Xquik caps file exports at 100,000 rows and PDF exports at 10,000 rows.

### Option a: paginate via API

Fetch results in pages of up to 1,000 records. Follow `nextCursor` until `hasMore` is false.

<CodeGroup>
  ```bash cURL theme={null}
  # First page
  curl -s "https://xquik.com/api/v1/extractions/77777?limit=1000" \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq

  # Next page (use nextCursor from previous response)
  curl -s "https://xquik.com/api/v1/extractions/77777?limit=1000&cursor=990100" \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq
  ```

  ```javascript Node.js theme={null}
  const extractionId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
  let cursor = undefined;
  const allResults = [];

  do {
    const params = new URLSearchParams({ limit: "1000" });
    if (cursor) params.set("after", cursor);

    const data = await fetch(`https://xquik.com/api/v1/extractions/${extractionId}?${params}`, {
      headers: { "x-api-key": "xq_YOUR_KEY_HERE" },
    }).then((r) => r.json());

    allResults.push(...data.results);
    cursor = data.hasMore ? data.nextCursor : undefined;
  } while (cursor);

  console.log(`Fetched ${allResults.length} results`);
  ```

  ```python Python theme={null}
  extraction_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  all_results = []
  cursor = None

  while True:
      params = {"limit": 1000}
      if cursor:
          params["after"] = cursor

      data = requests.get(
          f"https://xquik.com/api/v1/extractions/{extraction_id}",
          headers={"x-api-key": "xq_YOUR_KEY_HERE"},
          params=params,
      ).json()

      all_results.extend(data["results"])

      if data.get("hasMore"):
          cursor = data["nextCursor"]
      else:
          break

  print(f"Fetched {len(all_results)} results")
  ```

  ```go Go theme={null}
  extractionID := "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  cursor := ""
  var allResults []map[string]interface{}

  for {
      url := fmt.Sprintf("https://xquik.com/api/v1/extractions/%s?limit=1000", extractionID)
      if cursor != "" {
          url += "&cursor=" + cursor
      }

      req, _ := http.NewRequest("GET", url, nil)
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

      resp, _ := http.DefaultClient.Do(req)
      var data struct {
          Results    []map[string]interface{} `json:"results"`
          HasMore    bool                     `json:"hasMore"`
          NextCursor string                   `json:"nextCursor"`
      }
      json.NewDecoder(resp.Body).Decode(&data)
      resp.Body.Close()

      allResults = append(allResults, data.Results...)

      if !data.HasMore {
          break
      }
      cursor = data.NextCursor
  }

  fmt.Printf("Fetched %d results\n", len(allResults))
  ```
</CodeGroup>

### Durable JSON Lines handoff

Use JSON Lines when a queue, warehouse, or agent needs replayable rows without the export row cap. Write each paginated result with the cursor state that produced it.

```json theme={null}
{
  "extraction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "row_id": "990001",
  "x_user_id": "44196397",
  "x_username": "elonmusk",
  "tweet_id": "1893710452812718080",
  "tweet_text": "This is a great thread, thanks for sharing.",
  "page_cursor": "990100",
  "next_cursor": "990200",
  "has_more": true,
  "handoff_format": "jsonl"
}
```

Store rows in `xquik-extraction-results.jsonl` for queue replay, warehouse loads, or agent audits. Keep `page_cursor` and `next_cursor` so the job can resume from the last successful page.

Each result contains user profile data. Tweet-based tools add tweet data.

<Expandable title="Example response">
  ```json theme={null}
  {
    "id": "990001",
    "xUserId": "44196397",
    "xUsername": "elonmusk",
    "xDisplayName": "Elon Musk",
    "xFollowersCount": 210500000,
    "xVerified": true,
    "xProfileImageUrl": "https://pbs.twimg.com/profile_images/el0n.jpg",
    "tweetId": "1893710452812718080",
    "tweetText": "This is a great thread, thanks for sharing.",
    "tweetCreatedAt": "2026-02-24T10:05:00.000Z",
    "createdAt": "2026-02-24T10:06:12.000Z"
  }
  ```
</Expandable>

<Info>
  Every result includes `id`, `xUserId`, and `createdAt`. The API omits other fields when unavailable. It never sends `null`. Check that a field exists before reading it.
</Info>

### Option b: export as file

Download results as CSV, JSON, XLSX, Markdown, PDF, or TXT.
Available export rows include bios, locations, and engagement counts.

<CodeGroup>
  ```bash cURL theme={null}
  curl -s "https://xquik.com/api/v1/extractions/77777/export?format=csv" \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -o extraction-reply_extractor-77777.csv
  ```

  ```javascript Node.js theme={null}
  const extractionId = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
  const response = await fetch(
    `https://xquik.com/api/v1/extractions/${extractionId}/export?format=csv`,
    { headers: { "x-api-key": "xq_YOUR_KEY_HERE" } },
  );

  const blob = await response.blob();
  // Save to file or process as needed
  ```

  ```python Python theme={null}
  response = requests.get(
      f"https://xquik.com/api/v1/extractions/{extraction_id}/export",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      params={"format": "csv"},
  )

  with open("extraction-reply_extractor-77777.csv", "wb") as f:
      f.write(response.content)
  ```

  ```go Go theme={null}
  req, _ := http.NewRequest("GET", "https://xquik.com/api/v1/extractions/77777/export?format=csv", nil)
  req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

  resp, _ := http.DefaultClient.Do(req)
  defer resp.Body.Close()

  file, _ := os.Create("extraction-reply_extractor-77777.csv")
  defer file.Close()
  io.Copy(file, resp.Body)
  ```
</CodeGroup>

<CardGroup cols={2}>
  <Card title="CSV" icon="table">
    `format=csv` returns `text/csv; charset=utf-8` for spreadsheets and data
    pipelines.
  </Card>

  <Card title="JSON" icon="braces">
    `format=json` returns `application/json; charset=utf-8` for API clients and
    programmatic processing.
  </Card>

  <Card title="Markdown" icon="file-text">
    `format=md` returns `text/markdown; charset=utf-8` for documentation and
    issue handoffs.
  </Card>

  <Card title="Markdown document" icon="file-text">
    `format=md-document` returns `text/markdown; charset=utf-8` for longer
    markdown documents.
  </Card>

  <Card title="PDF" icon="file-down">
    `format=pdf` returns `application/pdf` for reports and sharing. Xquik caps
    PDF exports at `10,000` rows.
  </Card>

  <Card title="TXT" icon="file">
    `format=txt` returns `text/plain; charset=utf-8` for plain text and logs.
  </Card>

  <Card title="XLSX" icon="file-spreadsheet">
    `format=xlsx` returns
    `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` for
    Excel and formatted reports.
  </Card>
</CardGroup>

<Warning>
  Xquik caps exports at 100,000 rows and PDF exports at 10,000. For larger extractions, page through the API.
</Warning>

## Tool types reference

This section groups the 23 extraction tools by target type. Each requires a specific target field.

### Tweet-based tools

<CardGroup cols={2}>
  <Card title="Reply authors" icon="message-square">
    Use `reply_extractor` with `targetTweetId` to extract users who replied to a
    tweet.
  </Card>

  <Card title="Repost authors" icon="repeat-2">
    Use `repost_extractor` with `targetTweetId` to extract users who reposted a
    tweet.
  </Card>

  <Card title="Quote authors" icon="quote">
    Use `quote_extractor` with `targetTweetId` to extract users who quote-posted
    a tweet.
  </Card>

  <Card title="Like authors" icon="heart">
    Use `favoriters` with `targetTweetId` to extract visible users who liked a
    post. Liker identities can be unavailable even when the post reports likes.
    The job reads through your connected X account. Without one, the job fails
    with `errorMessage` set to `errorXAccountRequired`.
  </Card>

  <Card title="Thread tweets" icon="message-square-text">
    Use `thread_extractor` with `targetTweetId` to extract all tweets in a
    thread.
  </Card>

  <Card title="Article content" icon="file-text">
    Use `article_extractor` with `targetTweetId` to extract article content from
    a tweet.
  </Card>
</CardGroup>

### User-based tools

<CardGroup cols={2}>
  <Card title="Follower profiles" icon="users">
    Use `follower_explorer` with `targetUsername` to extract followers of an
    account.
  </Card>

  <Card title="Following profiles" icon="user-plus">
    Use `following_explorer` with `targetUsername` to extract accounts followed
    by a user.
  </Card>

  <Card title="Verified followers" icon="badge-check">
    Use `verified_follower_explorer` with `targetUsername` to extract verified
    followers of an account.
  </Card>

  <Card title="Mention tweets" icon="at-sign">
    Use `mention_extractor` with `targetUsername` to extract tweets mentioning
    an account.
  </Card>

  <Card title="Account posts" icon="send">
    Use `post_extractor` with `targetUsername` to extract posts from an
    account.
  </Card>

  <Card title="Liked tweets" icon="heart">
    Use `user_likes` with `targetUsername` to extract liked tweets that X makes visible. X shows likes only to their owner. The job reads through your connected X account. Without one, the job fails with `errorMessage` set to `errorXAccountRequired`.
  </Card>

  <Card title="Media posts" icon="image">
    Use `user_media` with `targetUsername` to extract media posts from a user.
  </Card>
</CardGroup>

### Community tools

<CardGroup cols={2}>
  <Card title="Community members" icon="users">
    Use `community_extractor` with `targetCommunityId` to extract members.
  </Card>

  <Card title="Community moderators" icon="shield-check">
    Use `community_moderator_explorer` with `targetCommunityId` to extract moderators.
  </Card>

  <Card title="Community posts" icon="message-square-text">
    Use `community_post_extractor` with `targetCommunityId` to extract posts.
  </Card>

  <Card title="Search within a community" icon="search">
    Use `community_search` with `targetCommunityId` and `searchQuery` to filter Community posts.
  </Card>
</CardGroup>

### List tools

<CardGroup cols={2}>
  <Card title="List members" icon="users">
    Use `list_member_extractor` with `targetListId` to extract members.
  </Card>

  <Card title="List tweets" icon="message-square-text">
    Use `list_post_extractor` with `targetListId` to extract tweets.
  </Card>

  <Card title="List followers" icon="user-plus">
    Use `list_follower_explorer` with `targetListId` to extract followers.
  </Card>
</CardGroup>

### Other tools

<CardGroup cols={2}>
  <Card title="People search" icon="search">
    Use `people_search` with `searchQuery` to find user profiles by keyword.
  </Card>

  <Card title="Space participants" icon="radio">
    Use `space_explorer` with `targetSpaceId` to extract participants of a
    Space.
  </Card>

  <Card title="Tweet search" icon="message-square">
    Use `tweet_search_extractor` with `searchQuery` to extract tweets by
    keyword, hashtag, or structured filters.
  </Card>
</CardGroup>

### Search filters

`tweet_search_extractor` accepts every filter below. `community_search` accepts language, dates, media, verified authors, native reposts, and the listed minimums.
Omit unrequested filters. A minimum alone does not request `queryType=Top`.
Use `advancedQuery` only for a known X search operator string.

<CardGroup cols={2}>
  <Card title="Account filters" icon="at-sign">
    Use `fromUser` for author username, `toUser` for tweets directed to a user,
    and `mentioning` for tweets that mention a user.
  </Card>

  <Card title="Date and language" icon="calendar-days">
    Use `language` for a language code such as `en`, `tr`, or `es`, then bound
    the export with `sinceDate` and `untilDate` in `YYYY-MM-DD` format.
  </Card>

  <Card title="Media and engagement" icon="image">
    Use `mediaType` for `images`, `videos`, `gifs`, `media`, `links`, or `none`.
    Set `minFaves`, `minRetweets`, `minReplies`, or `minQuotes`.
  </Card>

  <Card title="Conversation filters" icon="message-circle">
    Use `replies`, `retweets`, and `quotes` with `include`, `exclude`, or `only`.
    Set `verifiedOnly` when only verified authors should match.
  </Card>

  <Card title="Query refinement" icon="sliders-horizontal">
    Combine `exactPhrase`, `excludeWords`, `anyWords`, `hashtags`, `cashtags`,
    and `url` for terms, entities, or linked domains.
  </Card>

  <Card title="Tweet relationships" icon="git-branch">
    Use `conversationId`, `inReplyToTweetId`, `quotesOfTweetId`, or
    `retweetsOfTweetId` for one conversation or source tweet.
  </Card>

  <Card title="List and location scopes" icon="map-pin">
    Use `listId`, `place`, `placeCountry`, `pointRadius`, or `boundingBox`.
    These fields narrow search results to a list or location.
  </Card>

  <Card title="Advanced query" icon="code">
    Use `advancedQuery` only for raw X search syntax.
    Prefer the 30 structured fields when one already represents the filter.
  </Card>
</CardGroup>

**Example.** Search for popular English tweets with images from the last week.

```bash cURL theme={null}
curl -X POST https://xquik.com/api/v1/extractions \
  -H "x-api-key: xq_YOUR_KEY_HERE" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "toolType": "tweet_search_extractor",
    "searchQuery": "artificial intelligence",
    "language": "en",
    "mediaType": "images",
    "minFaves": 100,
    "sinceDate": "2026-03-06",
    "untilDate": "2026-03-13",
    "retweets": "exclude"
  }' | jq
```

<Tip>
  Combine filters with `resultsLimit` to narrow a search and cap its cost. For example, find the 50 top tweets about a topic from verified accounts in the last 24 hours.
</Tip>

## Twitter scraper API questions

### What is a Twitter scraper API?

A Twitter scraper API collects X posts and profiles through documented requests.
Xquik creates a job, returns its ID, and exposes cursor-based JSON results.
It can also generate downloadable files.
This Twitter data scraper covers tweets, replies, followers, following, communities, and lists.
It also covers spaces, likes, reposts, quotes, and media posts.

### Can Python scrape Twitter without the official API?

Yes, through Xquik's REST API and the Python examples above.
API access still requires an [Xquik API key](/x-api-quickstart).
You do not need to maintain an X developer application.
Poll the job, follow every cursor, and save structured tweet or profile rows.

### How do I export Twitter followers?

Run `follower_explorer` with the Twitter account username in `targetUsername`.
This Twitter follower scraper returns visible follower profiles.
Estimate the job before creating it.
Then poll every JSON page or download a file.
The follower export API keeps each Twitter profile ID, username, counts, and verification.
It also keeps names when available.

### How do I export tweet replies?

Use `reply_extractor` with `targetTweetId` for visible reply-author profiles.
Use `tweet_search_extractor` when the reply posts themselves matter.
Pass `inReplyToTweetId` to restrict results to one source tweet.
A tweet replies export can use CSV, JSON, XLSX, or paginated JSON.
Store the source tweet ID, extraction ID, row IDs, and cursor checkpoint.

### Why use a Twitter scrape API instead of a custom web scraper?

A custom web scraper must maintain selectors, login behavior, retries, and parsers.
A Twitter scrape API uses documented requests, statuses, cursors, and output fields.

## MCP equivalent

The same workflow works through the MCP server using the `execute` sandbox tool:

<CardGroup cols={2}>
  <Card title="Check account" icon="user-check">
    REST route: `GET /account`. MCP call:
    `xquik.request('/api/v1/account')` to confirm account state, credits, and
    usage before a run.
  </Card>

  <Card title="Estimate extraction" icon="calculator">
    REST route: `POST /extractions/estimate`. MCP call:
    `xquik.request('/api/v1/extractions/estimate', { method: 'POST', body })`
    with the same body you plan to run.
  </Card>

  <Card title="Start extraction" icon="rocket">
    REST route: `POST /extractions`. MCP call:
    `xquik.request('/api/v1/extractions', { method: 'POST', body })` to create
    the background job.
  </Card>

  <Card title="Poll results" icon="refresh-cw">
    REST route: `GET /extractions/{id}`. MCP call:
    `xquik.request('/api/v1/extractions/ID')` to retrieve the job status and
    rows.
  </Card>
</CardGroup>

**Example prompts for AI agents.**

* "How much would it cost to extract all followers of @elonmusk?"
* "Extract visible replies to this tweet: `https://x.com/vercel/status/1893704267862470862`"
* "Show me the results of my last extraction."

<Note>
  File export (`GET /extractions/{id}/export`) is only available via the REST API. The MCP server returns results as structured JSON via `xquik.request()`.
</Note>

## Error handling

<CardGroup cols={2}>
  <Card title="Resolve billing access" icon="credit-card">
    A `402` means the account cannot fund this extraction. Check the available
    balance and `payment_options`. You need no active plan when enough
    credits remain.
  </Card>

  <Card title="Top up credits" icon="coins">
    `402 insufficient_credits` means the account cannot cover the requested
    extraction. Top up credits, wait for the next grant, or lower `resultsLimit`.
  </Card>

  <Card title="Fix toolType" icon="list-checks">
    `400 invalid_tool_type` means `toolType` is not one of the supported
    extraction tools. Check the [tool types](#tool-types-reference) reference.
  </Card>

  <Card title="Fix required fields" icon="wrench">
    `400 invalid_input` usually means the target field is missing or malformed.
    Match `targetTweetId`, `targetUsername`, `targetCommunityId`,
    `targetListId`, `targetSpaceId`, or `searchQuery` to the selected tool.
  </Card>

  <Card title="Retry read service" icon="refresh-cw">
    `502 x_api_unavailable` means the read service is temporarily unavailable.
    Retry with exponential backoff, then contact support if the error persists.
  </Card>
</CardGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Create extraction" icon="pickaxe" href="/api-reference/extractions/create">
    Full API reference with request and response schemas.
  </Card>

  <Card title="Estimate extraction" icon="calculator" href="/api-reference/extractions/twitter-scraping-cost-estimator">
    Cost estimation endpoint reference.
  </Card>

  <Card title="Export extraction" icon="download" href="/api-reference/extractions/export">
    CSV, XLSX, and Markdown export with column details.
  </Card>

  <Card title="Billing & usage" icon="credit-card" href="/guides/billing">
    Pricing, credits, and usage scenarios.
  </Card>
</CardGroup>

<div className="related-api-links">
  <Accordion title="Related follower, list & community APIs" icon="link">
    * Profiles: [Search users](/api-reference/x/search-users) · [Search autocomplete](/api-reference/x/search-autocomplete) · [Get user](/api-reference/x/twitter-profile-lookup) · [Batch users](/api-reference/x/batch-users)
    * Followers: [Followers](/api-reference/x/followers) · [Following](/api-reference/x/following) · [Follower IDs](/api-reference/x/follower-ids) · [Following IDs](/api-reference/x/following-ids) · [Creator subscriptions](/api-reference/x/user-subscriptions) · [Affiliates](/api-reference/x/user-affiliates) · [Similar accounts](/api-reference/x/user-similar) · [Verified followers](/api-reference/x/verified-followers) · [Followers you know](/api-reference/x/followers-you-know) · [Check follower](/api-reference/x/check-follower)
    * Lists: [Search lists](/api-reference/x/search-lists) · [User lists](/api-reference/x/user-lists) · [List memberships](/api-reference/x/user-list-memberships) · [List members](/api-reference/x/list-members) · [List followers](/api-reference/x/list-followers)
    * Communities: [Find](/api-reference/x/community-find) · [Popular](/api-reference/x/community-popular) · [Topics](/api-reference/x/community-topics) · [Suggested](/api-reference/x/community-suggested) · [Details](/api-reference/x/community-info) · [Members](/api-reference/x/community-members) · [Moderators](/api-reference/x/community-moderators) · [Timeline](/api-reference/x/community-tweets) · [Media](/api-reference/x/community-media) · [Keyword search](/api-reference/x/community-search)
  </Accordion>
</div>


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