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

# Check follower

> Verify whether one X user follows another for campaign proof, giveaway eligibility, CRM flags, and audit workflows

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

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

<Info>
  Check follower verifies one known relationship without exporting a follower
  list. Pass the participant as `source` and the required brand, creator, or
  partner account as `target`. The response returns both directions:
  `isFollowing` for source-to-target proof and `isFollowedBy` for
  target-to-source context.
</Info>

<CodeGroup>
  ```bash Follow task theme={null}
  curl -G https://xquik.com/api/v1/x/followers/check \
    --data-urlencode "source=participant_handle" \
    --data-urlencode "target=brand_handle" \
    -H "x-api-key: xq_YOUR_KEY_HERE" | jq
  ```

  ```javascript Node.js theme={null}
  async function buildFollowCheckAudit() {
    const campaignId = "spring-launch-2026";
    const participantHandle = "participant_handle";
    const requiredFollowHandle = "brand_handle";
    const params = new URLSearchParams({
      source: participantHandle,
      target: requiredFollowHandle,
    });

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

    if (!response.ok) {
      throw new Error(`Follow check failed with status ${response.status}`);
    }

    const data = await response.json();
    return {
      campaign_id: campaignId,
      participant_handle: data.sourceUsername,
      required_follow_handle: data.targetUsername,
      proof_endpoint: "GET /api/v1/x/followers/check",
      participant_follows_required_account: data.isFollowing,
      required_account_follows_participant: data.isFollowedBy,
      verification_state: data.isFollowing ? "matched" : "not_matched",
    };
  }

  const auditEvent = await buildFollowCheckAudit();
  // Replace this with your DB, queue, or warehouse write.
  await saveAuditEvent(auditEvent);
  ```

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

  def build_follow_check_audit():
      campaign_id = "spring-launch-2026"
      participant_handle = "participant_handle"
      required_follow_handle = "brand_handle"
      response = requests.get(
          "https://xquik.com/api/v1/x/followers/check",
          params={
              "source": participant_handle,
              "target": required_follow_handle,
          },
          headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      )
      response.raise_for_status()
      data = response.json()
      return {
          "campaign_id": campaign_id,
          "participant_handle": data["sourceUsername"],
          "required_follow_handle": data["targetUsername"],
          "proof_endpoint": "GET /api/v1/x/followers/check",
          "participant_follows_required_account": data["isFollowing"],
          "required_account_follows_participant": data["isFollowedBy"],
          "verification_state": "matched" if data["isFollowing"] else "not_matched",
      }

  audit_event = build_follow_check_audit()
  # Replace this with your DB, queue, or warehouse write.
  save_audit_event(audit_event)
  ```
</CodeGroup>

The Node.js and Python snippets build a campaign audit event instead of printing
the raw response page. Store the event with your campaign, entrant, or CRM row
so reviewers can see the proof endpoint, the two handles checked, and the
matched or not-matched state.

## Campaign follow-check handoff

Use `GET /api/v1/x/followers/check` when a workflow already has both usernames
and needs a single proof for a follow task. It is best for campaign entry
validation, giveaway eligibility, creator partnerships, CRM qualification, and
agent review queues where the participant handle is known before the check.

<CardGroup cols={2}>
  <Card title="Single proof" icon="user-check">
    Store one audit event per participant and required account pair.
  </Card>

  <Card title="Both directions" icon="repeat-2">
    Store `isFollowing` as the required proof and `isFollowedBy` as reciprocal
    context.
  </Card>

  <Card title="Username inputs" icon="at-sign">
    Pass usernames without `@`. Use [Get user](/api-reference/x/get-user) first
    when you only have a display name, profile URL, or numeric ID.
  </Card>

  <Card title="Audit row" icon="clipboard-check">
    Persist the campaign ID, participant handle, required follow handle,
    endpoint, result booleans, and verification state.
  </Card>

  <Card title="Draw handoff" icon="trophy">
    Use [Create draw](/api-reference/draws/create) when winner selection also
    needs reply, repost, keyword, or unique-author filters.
  </Card>

  <Card title="Stopped audit" icon="coins">
    Treat `402 insufficient_credits` as a stopped audit and resume after
    credits are available.
  </Card>
</CardGroup>

## Query parameters

<ParamField query="source" type="string" required>
  Source username without `@`. In campaign verification, this is usually the
  participant or entrant whose follow action is being checked.
</ParamField>

<ParamField query="target" type="string" required>
  Target username without `@`. In campaign verification, this is usually the
  brand, creator, partner, or required account that may be followed by the
  source.
</ParamField>

## Which verification endpoint?

<CardGroup cols={2}>
  <Card title="Follow task" icon="user-check">
    Use `GET /x/followers/check` for one participant-account follow proof.
  </Card>

  <Card title="Retweet task" icon="repeat-2">
    Use [`GET /x/tweets/{id}/retweeters`](/api-reference/x/retweeters) to page
    accounts that reposted one source tweet.
  </Card>

  <Card title="Reply task" icon="message-square-reply">
    Use [`GET /x/tweets/{id}/replies`](/api-reference/x/tweet-replies) to check
    public replies under the source tweet.
  </Card>

  <Card title="Quote task" icon="quote">
    Use [`GET /x/tweets/{id}/quotes`](/api-reference/x/tweet-quotes) to inspect
    quote-tweet entries.
  </Card>

  <Card title="Follower export" icon="users">
    Use [`GET /x/users/{id}/followers`](/api-reference/x/followers) or a saved
    follower export when you need many followers for one profile.
  </Card>

  <Card title="Giveaway draw" icon="trophy">
    Use [`POST /draws`](/api-reference/draws/create) when Xquik should apply
    follow, repost, reply, keyword, and winner rules together.
  </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="sourceUsername" type="string">The source username from the request.</ResponseField>
    <ResponseField name="targetUsername" type="string">The target username from the request.</ResponseField>
    <ResponseField name="isFollowing" type="boolean">`true` if the source user follows the target user.</ResponseField>
    <ResponseField name="isFollowedBy" type="boolean">`true` if the target user follows the source user.</ResponseField>

    ```json theme={null}
    {
      "sourceUsername": "participant_handle",
      "targetUsername": "brand_handle",
      "isFollowing": true,
      "isFollowedBy": false
    }
    ```
  </Tab>

  <Tab title="400 Missing params">
    ```json theme={null}
    { "error": "missing_params", "required": ["source", "target"] }
    ```

    One or both query parameters are missing. Provide both `source` and `target`.
  </Tab>

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

    Missing or invalid API key. Check the `x-api-key` header value.
  </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:** [Campaign verification workflow](/guides/campaign-verification-workflow)
  for audit rows and draw handoffs, [Get User](/api-reference/x/get-user) to
  resolve profile details before checking, or [Get Account](/api-reference/account/get)
  to check remaining credits.
</Note>
