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

# Estimate extraction

> Get a cost estimate before running an extraction job

<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** - does not consume credits
</Callout>

<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",
      "resultsLimit": 500
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const response = 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",
      resultsLimit: 500,
    }),
  });
  const data = await response.json();

  if (data.allowed) {
    // Safe to proceed with extraction
  }
  ```

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

  response = requests.post(
      "https://xquik.com/api/v1/extractions/estimate",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={
          "toolType": "reply_extractor",
          "targetTweetId": "1893704267862470862",
          "resultsLimit": 500,
      },
  )
  data = response.json()

  if data.get("allowed"):
      # Safe to proceed with extraction
      pass
  ```

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

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

  func main() {
      body, _ := json.Marshal(map[string]interface{}{
          "toolType":      "reply_extractor",
          "targetTweetId": "1893704267862470862",
          "resultsLimit":  500,
      })

      req, err := http.NewRequest("POST", "https://xquik.com/api/v1/extractions/estimate", bytes.NewReader(body))
      if err != nil {
          panic(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")
      req.Header.Set("Content-Type", "application/json")

      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>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

## Body

The request body accepts the same fields as [Create Extraction](/api-reference/extractions/create), including all 16 tweet search filter parameters. Only `toolType` and the corresponding target field are required for the estimate.

<ParamField body="toolType" type="string" required>
  Extraction tool to estimate. 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 body="targetTweetId" type="string">
  Tweet ID to estimate. Required for `reply_extractor`, `repost_extractor`, `quote_extractor`, `thread_extractor`, `article_extractor`.
</ParamField>

<ParamField body="targetUsername" type="string">
  X username to estimate. Required for `follower_explorer`, `following_explorer`, `verified_follower_explorer`, `mention_extractor`, `post_extractor`, `user_likes`, and `user_media`.
</ParamField>

<ParamField body="targetCommunityId" type="string">
  Community ID to estimate. Required for `community_extractor`, `community_moderator_explorer`, `community_post_extractor`.
</ParamField>

<ParamField body="searchQuery" type="string">
  Search query to estimate. Required for `people_search`, `community_search`, `tweet_search_extractor`.
</ParamField>

<ParamField body="targetListId" type="string">
  X List ID to estimate. Required for `list_member_extractor`, `list_post_extractor`, `list_follower_explorer`.
</ParamField>

<ParamField body="targetSpaceId" type="string">
  X Space ID to estimate. Required for `space_explorer`.
</ParamField>

<ParamField body="resultsLimit" type="integer">
  Maximum number of results to extract. When set, the estimate caps `estimatedResults` to this value and adjusts projected usage accordingly. Useful for previewing the cost of a partial extraction.
</ParamField>

## Response

<Tabs>
  <Tab title="200 OK">
    <ResponseField name="allowed" type="boolean">Whether the extraction can proceed given the current credit balance.</ResponseField>
    <ResponseField name="source" type="string">Data source used for the estimate. One of: `followers`, `following`, `paginationCap`, `posts`, `quoteCount`, `replyCount`, `resultsLimit`, `retweetCount`, `unknown`.</ResponseField>
    <ResponseField name="estimatedResults" type="number">Estimated number of results the extraction will return.</ResponseField>
    <ResponseField name="creditsRequired" type="string">Credits this extraction will consume (stringified integer).</ResponseField>
    <ResponseField name="creditsAvailable" type="string">Credits currently available in your balance (stringified integer).</ResponseField>
    <ResponseField name="resolvedXUserId" type="string">Resolved X user ID when `targetUsername` was provided. Omitted for non-user-based tools.</ResponseField>

    ```json theme={null}
    {
      "allowed": true,
      "creditsRequired": "500",
      "creditsAvailable": "50000",
      "estimatedResults": 250,
      "source": "replyCount",
      "resolvedXUserId": "123456"
    }
    ```

    When `allowed` is `false`, credits required exceed the available balance:

    ```json theme={null}
    {
      "allowed": false,
      "creditsRequired": "250000",
      "creditsAvailable": "18000",
      "estimatedResults": 250000,
      "source": "followers"
    }
    ```
  </Tab>

  <Tab title="400 Invalid input">
    ```json theme={null}
    { "error": "invalid_input" }
    ```

    Request body is missing or malformed. Ensure `toolType` and the corresponding target field are present.
  </Tab>

  <Tab title="400 Invalid tool type">
    ```json theme={null}
    { "error": "invalid_tool_type" }
    ```

    The `toolType` value is not one of the 23 supported tools.
  </Tab>

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

    Missing or invalid API key.
  </Tab>

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

    No active subscription or insufficient credits. Possible error values: `no_subscription`, `subscription_inactive`, `no_credits`, `insufficient_credits`.
  </Tab>

  <Tab title="404 Not Found">
    ```json theme={null}
    { "error": "tweet_not_found", "message": "Tweet not found" }
    ```

    The target tweet does not exist, was deleted, or the ID is invalid.

    ```json theme={null}
    { "error": "user_not_found", "message": "X user not found" }
    ```

    The target user does not exist or is suspended.
  </Tab>

  <Tab title="429 Rate Limited">
    ```json theme={null}
    { "error": "rate_limit_exceeded", "message": "Too many requests. Try again later.", "retryAfter": 60 }
    ```

    Wait for the `Retry-After` value before requesting another estimate.
  </Tab>
</Tabs>

## Decision handoff

Treat the `200 OK` response as a planning checkpoint, not a running extraction. Store the estimate with the request you plan to run:

```json theme={null}
{
  "checkpoint_type": "extraction_estimate",
  "toolType": "reply_extractor",
  "targetTweetId": "1893704267862470862",
  "resultsLimit": 500,
  "estimatedResults": 500,
  "creditsRequired": "500",
  "creditsAvailable": "50000",
  "allowed": true,
  "source": "replyCount",
  "next_action": "create_extraction",
  "create_path": "/api/v1/extractions",
  "fallback_action": "lower_results_limit_or_add_credits"
}
```

<CardGroup cols={2}>
  <Card title="Allowed run" icon="circle-check">
    When `allowed` is `true`, send the same `toolType`, target fields, filters, and `resultsLimit` to [Create Extraction](/api-reference/extractions/create). Store the returned job ID from that `202 Accepted` receipt.
  </Card>

  <Card title="Blocked run" icon="circle-alert">
    When `allowed` is `false`, lower `resultsLimit`, narrow the target or filters, or add credits before calling [Create Extraction](/api-reference/extractions/create).
  </Card>

  <Card title="Source signal" icon="gauge">
    Store `source` so operators know whether the estimate came from `replyCount`, `followers`, `resultsLimit`, `paginationCap`, or another supported signal.
  </Card>

  <Card title="Audit fields" icon="clipboard-check">
    Store `estimatedResults`, `creditsRequired`, `creditsAvailable`, `allowed`, and `source` with the planned extraction request.
  </Card>
</CardGroup>

<Note>
  **Always call this endpoint before running an extraction** to avoid hitting credit limits. If `allowed` is `false`, the corresponding [Create Extraction](/api-reference/extractions/create) request will return a `402` error. Check your current usage on the [dashboard](https://xquik.com/dashboard).
</Note>

<Note>
  **Next steps:** [Create Extraction](/api-reference/extractions/create) to start an extraction, or [Extraction Workflow Guide](/guides/extraction-workflow) for the full flow.
</Note>
