> ## 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 scraping job history & export status API

> List tweet, follower, following, reply, profile, timeline, media, community, and list extraction jobs by tool, status, and cursor. Listing jobs is free.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-extractions-twitter-scraping-job-history-200">
      ```json theme={null}
      {
        "extractions": [],
        "hasMore": false
      }
      ```
    </Tab>

    <Tab title="400" id="response-extractions-twitter-scraping-job-history-400">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

    <Tab title="401" id="response-extractions-twitter-scraping-job-history-401">
      ```json theme={null}
      {
        "error": "unauthenticated",
        "message": "Authentication required. Provide a valid API key or bearer token."
      }
      ```
    </Tab>

    <Tab title="429" id="response-extractions-twitter-scraping-job-history-429">
      ```json theme={null}
      {
        "error": "rate_limit_exceeded",
        "message": "Too many requests. Try again later.",
        "retryAfter": 60
      }
      ```
    </Tab>
  </Tabs>
</Panel>

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

<Callout icon="circle-check" color="#16a34a">
  **Free.** This endpoint does not consume credits.
</Callout>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://xquik.com/api/v1/extractions?limit=20&toolType=reply_extractor" \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq
  ```

  ```javascript Node.js theme={null}
  const params = new URLSearchParams({
    limit: "20",
    toolType: "reply_extractor",
  });

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

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

  response = requests.get(
      "https://xquik.com/api/v1/extractions",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      params={
          "limit": 20,
          "toolType": "reply_extractor",
      },
  )
  data = response.json()
  ```

  ```go Go theme={null}
  package main

  import (
      "encoding/json"
      "fmt"
      "net/http"
  )

  func main() {
      req, err := http.NewRequest("GET", "https://xquik.com/api/v1/extractions?limit=20&toolType=reply_extractor", nil)
      if err != nil {
          panic(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

      resp, err := http.DefaultClient.Do(req)
      if err != nil {
          panic(err)
      }
      defer resp.Body.Close()

      var data map[string]interface{}
      if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
          panic(err)
      }
      fmt.Println(data)
  }
  ```
</CodeGroup>

## Headers

<ParamField header="x-api-key" type="string" required>
  Your API key. Session cookie authentication is also supported. Generate a key from the [dashboard](https://xquik.com/dashboard).
</ParamField>

## Query parameters

<ParamField query="limit" type="number">
  Number of extractions to return per page. Default: `50`. Maximum: `100`.
</ParamField>

<ParamField query="toolType" type="string">
  Filter by tool type. One of: `article_extractor`, `community_extractor`, `community_moderator_explorer`, `community_post_extractor`, `community_search`, `favoriters`, `follower_explorer`, `following_explorer`, `list_follower_explorer`, `list_member_extractor`, `list_post_extractor`, `mention_extractor`, `people_search`, `post_extractor`, `quote_extractor`, `reply_extractor`, `repost_extractor`, `space_explorer`, `thread_extractor`, `tweet_search_extractor`, `user_likes`, `user_media`, `verified_follower_explorer`.
</ParamField>

<ParamField query="status" type="string">
  Filter by job status. One of: `completed`, `failed`, `running`.
</ParamField>

<ParamField query="cursor" type="string">
  Cursor for pagination. Use the `nextCursor` value from the previous response to fetch the next page.
</ParamField>

| Scraping job inventory column | Response source | Reconciliation rule |
| - | - | - |
| Job ID | `extractions[].id` | Open the matching extraction result pages. |
| Scraper tool | `extractions[].toolType` | Separate tweet, follower, reply, and profile jobs. |
| Job state | `extractions[].status` | Handle completed, failed, and running jobs separately. |
| Extracted rows | `extractions[].totalResults` | Compare this count with saved result pages. |
| Started at | `extractions[].createdAt` | Keep the collection start time. |
| Completed at | `extractions[].completedAt` | Measure completed-job duration. |
| More jobs | `hasMore` | Continue only while this value is `true`. |
| Next page | `nextCursor` | Pass this value as the next `cursor` parameter. |

## Response

### 200 OK

<ResponseField name="extractions" type="object[]">
  Array of extraction job summaries.
  **Extraction object fields.**

  <ResponseField name="id" type="string">
    Unique extraction job ID.
  </ResponseField>

  <ResponseField name="toolType" type="string">
    Tool type used for this extraction.
  </ResponseField>

  <ResponseField name="status" type="string">
    Job status: `completed`, `failed`, or `running`.
  </ResponseField>

  <ResponseField name="totalResults" type="number">
    Total number of extracted results.
  </ResponseField>

  <ResponseField name="createdAt" type="string">
    ISO 8601 timestamp of when the job was created.
  </ResponseField>

  <ResponseField name="completedAt" type="string">
    ISO 8601 timestamp of when the job finished. Only present for completed jobs.
  </ResponseField>
</ResponseField>

<ResponseField name="hasMore" type="boolean">Whether more results exist beyond this page.</ResponseField>
<ResponseField name="nextCursor" type="string">Cursor for the next `cursor` parameter. Only present when `hasMore` is `true`.</ResponseField>

```json theme={null}
{
  "extractions": [
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "toolType": "reply_extractor",
      "status": "completed",
      "totalResults": 150,
      "createdAt": "2026-02-24T10:00:00.000Z",
      "completedAt": "2026-02-24T10:00:12.000Z"
    },
    {
      "id": "b2c3d4e5-f6a1-7890-abcd-ef2345678901",
      "toolType": "follower_explorer",
      "status": "completed",
      "totalResults": 4832,
      "createdAt": "2026-02-23T18:30:00.000Z",
      "completedAt": "2026-02-23T18:31:45.000Z"
    },
    {
      "id": "c3d4e5f6-a1b2-7890-abcd-ef3456789012",
      "toolType": "repost_extractor",
      "status": "failed",
      "totalResults": 0,
      "createdAt": "2026-02-23T12:00:00.000Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "eyJjIjoiMjAyNi0wMi0yM1QxMjowMDowMC4wMDBaIiwiaSI6Ijc3NzY4In0"
}
```

### 401 Unauthenticated

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

Missing or invalid API key.

### 429 Rate limited

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Try again later.",
  "retryAfter": 1
}
```

Wait for the `Retry-After` value before making another request.

## Pagination

The API orders results by creation date (newest first). To iterate through all extractions:

1. Make the initial request without the `cursor` parameter.
2. Check `hasMore`. Pass `nextCursor` as the next `cursor` value.
3. Repeat until `hasMore` is `false`.

```javascript theme={null}
import { appendFile } from "node:fs/promises";

let cursor = undefined;
let pageIndex = 0;

do {
  const params = new URLSearchParams({
    limit: "100",
    status: "completed",
  });
  if (cursor) params.set("cursor", cursor);
  const pageCursor = cursor ?? null;

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

  const rows = data.extractions.map((job) => ({
    extraction_id: job.id,
    tool_type: job.toolType,
    status: job.status,
    total_results: job.totalResults,
    created_at: job.createdAt,
    completed_at: job.completedAt ?? null,
    detail_path: `/api/v1/extractions/${job.id}`,
    export_path:
      job.status === "completed" ? `/api/v1/extractions/${job.id}/export?format=csv` : null,
    page_index: pageIndex,
    page_cursor: pageCursor,
    next_cursor: data.nextCursor ?? null,
    has_more: data.hasMore,
    handoff_format: "jsonl",
  }));

  if (rows.length > 0) {
    await appendFile(
      "xquik-extraction-jobs.jsonl",
      `${rows.map((row) => JSON.stringify(row)).join("\n")}\n`,
    );
  }

  cursor = data.hasMore ? data.nextCursor : undefined;
  pageIndex += 1;
} while (cursor);
```

## Job inventory handoff

Use `GET /extractions` as the job inventory step before fetching details or
exporting files. Treat `nextCursor` as opaque and pass it back as `cursor`. Do
not write raw job lists to shared logs.

<CardGroup cols={2}>
  <Card title="Page checkpoint" icon="bookmark">
    Store `page_index`, `page_cursor`, `next_cursor`, `has_more`, `limit`,
    `tool_type_filter`, and `status_filter` after each successful page.
  </Card>

  <Card title="Completed jobs" icon="circle-check">
    Store completed job `id`, `toolType`, `totalResults`, `completedAt`,
    `detail_path`, and `export_path` for the next fetch or file export.
  </Card>

  <Card title="Running or failed jobs" icon="circle-alert">
    Keep `status`, `createdAt`, and `id` so dashboards can retry failed jobs or
    poll running jobs without rereading older pages.
  </Card>

  <Card title="Next API step" icon="route">
    Use [Get Extraction](/api-reference/extractions/twitter-extraction-results) for paginated JSON
    rows, or [Export Extraction](/api-reference/extractions/export) for files.
  </Card>
</CardGroup>

Store page checkpoints separately from job rows:

```json theme={null}
{
  "page_index": 2,
  "page_cursor": "eyJjIjoiMjAyNi0wMi0yM1QxODozMTo0NS4wMDBaIiwiaSI6Ijc3NzY4In0",
  "next_cursor": "eyJjIjoiMjAyNi0wMi0yM1QxMjowMDowMC4wMDBaIiwiaSI6Ijc3NzY0In0",
  "has_more": true,
  "limit": 100,
  "tool_type_filter": "reply_extractor",
  "status_filter": "completed",
  "handoff_format": "jsonl"
}
```

<Note>
  **Next steps.** [Get Extraction](/api-reference/extractions/twitter-extraction-results) to retrieve full results for a specific job, or [Create Extraction](/api-reference/extractions/create) to run a new extraction.
</Note>


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