> ## 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 giveaway picker API & random winner draw

> Select random giveaway winners from a tweet's replies. Filter by repost, follow, keyword, hashtag, mention, language, and account age. Returns backup winners.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="201" id="response-draws-create-201">
      ```json theme={null}
      {
        "id": "f4bd00a2-7b4e-4e59-8e1b-72e2c9f12345",
        "tweetId": "1234567890",
        "totalEntries": 250,
        "validEntries": 200,
        "winners": []
      }
      ```
    </Tab>

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

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

    <Tab title="402" id="response-draws-create-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits"
      }
      ```
    </Tab>

    <Tab title="404" id="response-draws-create-404">
      ```json theme={null}
      {
        "error": "not_found",
        "message": "Resource not found."
      }
      ```
    </Tab>

    <Tab title="409" id="response-draws-create-409">
      ```json theme={null}
      {
        "error": "idempotency_conflict",
        "message": "Idempotency-Key belongs to another request. Use a new key."
      }
      ```
    </Tab>

    <Tab title="424" id="response-draws-create-424">
      ```json theme={null}
      {
        "error": "replies_incomplete",
        "message": "X stopped before every reply loaded. Retry the draw later."
      }
      ```
    </Tab>

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

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

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

Use this Twitter giveaway picker API to select primary and backup winners. Filter replies by reposts, follows, keywords, hashtags, mentions, or language. Add account-age, follower-count, or unique-author rules.

<Callout icon="coins" color="#5c3327">
  **Metered draw execution** · source lookup, replies, optional retweeters, and optional follow checks consume credits
</Callout>

<Note>
  Xquik reads every direct reply and retweeter X shows, up to what your remaining credits cover. `totalEntries` and `validEntries` count the inspected direct replies. X hides some replies, so the post can report more. A draw on a busy post takes about 1 minute, so keep the request open for 100 seconds. Xquik runs & charges follow checks only for authors who pass your other filters.
</Note>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/draws \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Idempotency-Key: $(uuidgen)" \
    -H "Content-Type: application/json" \
    -d '{
      "tweetUrl": "https://x.com/xquik/status/1893456789012345678",
      "winnerCount": 3,
      "backupCount": 2,
      "mustRetweet": true,
      "filterMinFollowers": 10,
      "requiredKeywords": ["giveaway"]
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/draws", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Idempotency-Key": crypto.randomUUID(),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      tweetUrl: "https://x.com/xquik/status/1893456789012345678",
      winnerCount: 3,
      backupCount: 2,
      mustRetweet: true,
      filterMinFollowers: 10,
      requiredKeywords: ["giveaway"],
    }),
  });
  const data = await response.json();
  console.log(data);
  ```

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

  response = requests.post(
      "https://xquik.com/api/v1/draws",
      headers={"x-api-key": "xq_YOUR_KEY_HERE", "Idempotency-Key": str(uuid4())},
      json={
          "tweetUrl": "https://x.com/xquik/status/1893456789012345678",
          "winnerCount": 3,
          "backupCount": 2,
          "mustRetweet": True,
          "filterMinFollowers": 10,
          "requiredKeywords": ["giveaway"],
      },
  )
  data = response.json()
  print(data)
  ```

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

  import (
  	"bytes"
  	"crypto/rand"
  	"encoding/json"
  	"fmt"
  	"io"
  	"log"
  	"net/http"
  )

  func main() {
  	payload := map[string]interface{}{
  		"tweetUrl":           "https://x.com/xquik/status/1893456789012345678",
  		"winnerCount":        3,
  		"backupCount":        2,
  		"mustRetweet":        true,
  		"filterMinFollowers": 10,
  		"requiredKeywords":   []string{"giveaway"},
  	}
  	body, err := json.Marshal(payload)
  	if err != nil {
  		log.Fatal(err)
  	}

  	req, err := http.NewRequest("POST", "https://xquik.com/api/v1/draws", bytes.NewReader(body))
  	if err != nil {
  		log.Fatal(err)
  	}
  	req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")
  	req.Header.Set("Idempotency-Key", rand.Text())
  	req.Header.Set("Content-Type", "application/json")

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

  	respBody, err := io.ReadAll(resp.Body)
  	if err != nil {
  		log.Fatal(err)
  	}
  	fmt.Println(string(respBody))
  }
  ```
</CodeGroup>

| Giveaway draw column | Request or response source | Audit rule |
| - | - | - |
| Draw ID | Response `id` | Use this public ID for review and export. |
| Source tweet | Response `tweetId` | Keep the giveaway tweet identifier. |
| Inspected entries | Response `totalEntries` | Record how many replies Xquik inspected. |
| Eligible entries | Response `validEntries` | Compare this count with every filter. |
| Winner order | `winners[].position` | Keep the original selection order. |
| Winner username | `winners[].authorUsername` | Store the selected X account. |
| Winning reply | `winners[].tweetId` | Retain the qualifying reply identifier. |
| Backup state | `winners[].isBackup` | Separate primary and backup winners. |

## Headers

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

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

<ParamField header="Idempotency-Key" type="string">
  Use 1-255 visible ASCII characters. Generate one unique value for each draw. Reuse it only for an exact retry. A retry returns the original draw and charges nothing. A retry while the first request runs returns `409 idempotency_in_progress`. A draw that fails frees its key for a retry. If the first request stops, the key frees after 10 minutes.
</ParamField>

## Body

<ParamField body="tweetUrl" type="string" required>
  Full tweet URL to run the draw on. Accepts `x.com` and `twitter.com` formats (for example `https://x.com/user/status/1893456789012345678`).
</ParamField>

<ParamField body="winnerCount" type="number">
  Number of winners to draw. Defaults to `1` if omitted.
</ParamField>

<ParamField body="backupCount" type="number">
  Number of backup winners to draw. Xquik selects backup winners in case you disqualify primary winners.
</ParamField>

<ParamField body="uniqueAuthorsOnly" type="boolean">
  When `true`, each author can win once, however many replies they posted.
</ParamField>

<ParamField body="mustRetweet" type="boolean">
  When `true`, only entries from users who retweeted the original tweet are eligible.
</ParamField>

<ParamField body="mustFollowUsername" type="string">
  X username that entrants must follow to be eligible. Xquik strips the `@` prefix if included.
</ParamField>

<ParamField body="filterMinFollowers" type="number">
  Minimum follower count required for eligible entries.
</ParamField>

<ParamField body="filterAccountAgeDays" type="number">
  Minimum account age in days. The draw excludes accounts younger than this.
</ParamField>

<ParamField body="filterLanguage" type="string">
  Filter entries by tweet language code (for example `en`, `tr`, `es`).
</ParamField>

<ParamField body="requiredKeywords" type="string[]">
  Array of keywords that must appear in the reply text. The draw excludes entries missing any keyword.
</ParamField>

<ParamField body="requiredHashtags" type="string[]">
  Array of hashtags that must appear in the reply text. Include the `#` prefix.
</ParamField>

<ParamField body="requiredMentions" type="string[]">
  Array of usernames that the reply text must mention. Include the `@` prefix.
</ParamField>

## Response

### 201 Created

An exact retry returns the original draw with `Idempotency-Replayed: true`.

<ResponseField name="id" type="string">Draw public ID returned by Xquik.</ResponseField>
<ResponseField name="tweetId" type="string">X tweet ID extracted from the URL.</ResponseField>
<ResponseField name="totalEntries" type="number">Entries inspected after the credit cap, which can be fewer than the post's replies.</ResponseField>
<ResponseField name="validEntries" type="number">Inspected entries that passed every filter. A credit cap can leave valid replies uninspected.</ResponseField>

<ResponseField name="winners" type="array">
  Selected winners and backup winners.
  **Winner object fields.**

  <ResponseField name="position" type="number">
    Winner position (1-indexed).
  </ResponseField>

  <ResponseField name="authorUsername" type="string">
    X username of the winner.
  </ResponseField>

  <ResponseField name="tweetId" type="string">
    Tweet ID of the winning reply.
  </ResponseField>

  <ResponseField name="isBackup" type="boolean">
    `true` if this is a backup winner.
  </ResponseField>
</ResponseField>

```json theme={null}
{
  "id": "f4bd00a2-7b4e-4e59-8e1b-72e2c9f12345",
  "tweetId": "1893456789012345678",
  "totalEntries": 847,
  "validEntries": 312,
  "winners": [
    {
      "position": 1,
      "authorUsername": "alice_web3",
      "tweetId": "1893456789012345700",
      "isBackup": false
    },
    {
      "position": 2,
      "authorUsername": "bob_dev",
      "tweetId": "1893456789012345701",
      "isBackup": false
    },
    {
      "position": 3,
      "authorUsername": "charlie_nft",
      "tweetId": "1893456789012345702",
      "isBackup": false
    },
    {
      "position": 4,
      "authorUsername": "diana_crypto",
      "tweetId": "1893456789012345703",
      "isBackup": true
    },
    {
      "position": 5,
      "authorUsername": "eve_trades",
      "tweetId": "1893456789012345704",
      "isBackup": true
    }
  ]
}
```

### 400 Invalid input

```json theme={null}
{ "error": "invalid_input", "message": "Missing or malformed request body" }
```

Missing or malformed request body. Send `tweetUrl` as a string.

### 400 Invalid tweet URL

```json theme={null}
{ "error": "invalid_tweet_url", "message": "Invalid tweet URL format" }
```

Xquik could not parse the `tweetUrl`. Must be a valid `x.com` or `twitter.com` status URL.

### 400 Invalid idempotency key

```json theme={null}
{
  "error": "invalid_idempotency_key",
  "message": "Idempotency-Key invalid. Use 1-255 visible ASCII characters."
}
```

The `Idempotency-Key` header is empty, longer than 255 characters, or not visible ASCII.

### 401 Unauthenticated

```json theme={null}
{ "error": "unauthenticated", "message": "Missing or invalid API key" }
```

Missing or invalid API key / session cookie.

### 402 Insufficient credits

```json theme={null}
{
  "error": "insufficient_credits",
  "message": "Insufficient credits. Top up or subscribe to continue."
}
```

The available balance cannot cover the minimum draw cost. A later final deduction failure also returns `insufficient_credits`. Xquik stores no draw result and charges nothing after that failure. Check your [credit balance](/api-reference/account/get).

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

### 409 Idempotency conflict

```json theme={null}
{
  "error": "idempotency_conflict",
  "message": "Idempotency-Key belongs to another request. Use a new key."
}
```

Reuse a key only for the same request. Exact retries return the original draw. Xquik reads nothing and charges nothing for this request.

### 409 Idempotency in progress

```json theme={null}
{
  "error": "idempotency_in_progress",
  "message": "Idempotency-Key belongs to a running request. Retry later."
}
```

The first request with this key is still running. Retry with the same key after it finishes. Xquik charges nothing for this request.

### 424 Short read

```json theme={null}
{
  "error": "replies_incomplete",
  "message": "X stopped before every reply loaded. Retry the draw later."
}
```

```json theme={null}
{
  "error": "draw_too_large",
  "message": "The post has more replies than 1 draw reads. Contact support."
}
```

X failed or stopped early. Retry after `replies_incomplete` or `retweeters_incomplete`. `draw_too_large` means the post has more entries than 1 draw reads; contact support. Xquik saves & charges nothing.

### 424 X API dependency failed

```json theme={null}
{
  "error": {
    "type": "dependency_error",
    "code": "x_api_unavailable",
    "message": "X data source temporarily unavailable"
  }
}
```

Send `xquik-api-contract: 2026-04-29` to receive this status for dependency failures that return `502` by default.

### 429 Rate limited

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

Too many requests. Wait for the `Retry-After` header before retrying.

### 502 X API unavailable

```json theme={null}
{ "error": "x_api_unavailable", "message": "X data source temporarily unavailable" }
```

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

<Note>
  **Next steps.** [Get Draw](/api-reference/draws/get) to retrieve full draw details including tweet metadata, [Export Draw](/api-reference/draws/export) to download results as CSV, XLSX or Markdown, or [List Draws](/api-reference/draws/twitter-giveaway-history) to see your draw history.
</Note>


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