> ## 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 follow API: follow one X user by ID

> Follow one X user by ID from a connected account. Poll the write action, respect the 20 per minute and 400 per day limits, and verify the relationship.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-x-write-follow-200">
      ```json theme={null}
      {
        "object": "x_write_action",
        "id": "12345",
        "writeActionId": "12345",
        "action": "follow",
        "status": "success",
        "terminal": true,
        "retryable": false,
        "safeToRetry": false,
        "statusUrl": "/api/v1/x/write-actions/12345",
        "pollAfterMs": null
      }
      ```
    </Tab>

    <Tab title="202" id="response-x-write-follow-202">
      ```json theme={null}
      {
        "object": "x_write_action",
        "id": "12346",
        "writeActionId": "12346",
        "action": "follow",
        "status": "dispatching",
        "terminal": false,
        "retryable": false,
        "safeToRetry": false,
        "statusUrl": "/api/v1/x/write-actions/12346",
        "pollAfterMs": 2000
      }
      ```
    </Tab>

    <Tab title="400" id="response-x-write-follow-400">
      ```json theme={null}
      {
        "error": "missing_idempotency_key",
        "message": "Idempotency-Key is required. Generate one unique key for this write.",
        "charged": false,
        "chargedCredits": "0",
        "retryable": false,
        "safeToRetry": true
      }
      ```
    </Tab>

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

    <Tab title="402" id="response-x-write-follow-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits. Top up or subscribe to continue."
      }
      ```
    </Tab>

    <Tab title="403" id="response-x-write-follow-403">
      ```json theme={null}
      {
        "error": "account_needs_reauth",
        "message": "X account needs re-authentication. Re-add the account."
      }
      ```
    </Tab>

    <Tab title="404" id="response-x-write-follow-404">
      ```json theme={null}
      {
        "error": "account_not_found",
        "message": "X account not found. Connect it first at /dashboard/account?tab=x-accounts."
      }
      ```
    </Tab>

    <Tab title="409" id="response-x-write-follow-409">
      ```json theme={null}
      {
        "error": "idempotency_conflict",
        "message": "Idempotency-Key was already used with a different request.",
        "charged": false,
        "chargedCredits": "0",
        "retryable": false,
        "safeToRetry": true
      }
      ```
    </Tab>

    <Tab title="422" id="response-x-write-follow-422">
      ```json theme={null}
      {
        "error": "x_rejected",
        "message": "X rejected this request. Check what you sent & the account on x.com before you try again."
      }
      ```
    </Tab>

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

    <Tab title="500" id="response-x-write-follow-500">
      ```json theme={null}
      {
        "error": "x_write_failed",
        "message": "Write action failed unexpectedly. Contact support if this persists."
      }
      ```
    </Tab>

    <Tab title="503" id="response-x-write-follow-503">
      ```json theme={null}
      {
        "error": "write_tracking_unavailable",
        "message": "Write tracking unavailable. Try again.",
        "charged": false,
        "chargedCredits": "0",
        "retryable": true,
        "safeToRetry": true
      }
      ```
    </Tab>
  </Tabs>
</Panel>

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

## Follow one Twitter user by ID

Each request follows 1 target user ID.
Each request names 1 connected X account.
Verify the target user ID. Approve the acting account before sending the action.

Compare X's separate [Follow User endpoint](https://docs.x.com/x-api/users/follow-user).

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

<Warning>
  **Action-specific rate limit.** Follow allows 20 requests per minute and 400 per day per account. The general write tier allows 120 per 60s. Exceeding either limit returns `429 Too Many Requests`. `Retry-After` is the wait until the limit frees, up to 24 hours after the daily limit.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://xquik.com/api/v1/x/users/44196397/follow \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Idempotency-Key: follow-44196397-1895432178065391234" \
    -H "Content-Type: application/json" \
    -d '{
      "account": "myxaccount"
    }' | jq
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/x/users/44196397/follow", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Idempotency-Key": "follow-44196397-1895432178065391234",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      account: "myxaccount",
    }),
  });
  const followReceipt = await response.json();
  if (!response.ok) {
    throw new Error(JSON.stringify(followReceipt));
  }
  ```

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

  response = requests.post(
      "https://xquik.com/api/v1/x/users/44196397/follow",
      headers={
          "x-api-key": "xq_YOUR_KEY_HERE",
          "Idempotency-Key": "follow-44196397-1895432178065391234",
      },
      json={
          "account": "myxaccount",
      },
  )
  follow_receipt = response.json()
  response.raise_for_status()
  ```

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

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

  func main() {
      body, _ := json.Marshal(map[string]interface{}{
          "account": "myxaccount",
      })

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

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

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

## Authenticate and approve the follow

Send an Xquik API key or OAuth 2.1 bearer token.
Never send an X password or session cookie.
Show the target user ID, username, profile name, and acting account.

## Verify the Twitter follow API result

Store the target ID, acting account, action ID, and request hash.
Poll `statusUrl` until `terminal` becomes `true`.
Close already-followed results without another request.

Use [Check Follower](/api-reference/x/check-follower) when you need current proof.
Use [Following](/api-reference/x/following) to read outbound relationships.
Use [Unfollow User](/api-reference/x-write/unfollow) to reverse approval.

## Handle Twitter follow API errors

Fix the user ID or account after `400`.
Replace Xquik authentication after `401`. Reconnect after `403`.
Add credits after `402`. Review rejected input after `422`.
Honor `Retry-After` after `429`.
After `500` or `503`, check `safeToRetry` before retrying.

## Twitter API follow questions

### How do I follow a user programmatically?

Approve the target user ID and connected account.
Send this POST request. Poll the returned action until terminal.

### Can I follow a protected X account?

Protected X profiles may keep follows pending until approval.
Verify the relationship before dependent work begins.

### Can I bulk follow Twitter users?

No bulk request exists here.
Send 1 approved target ID per action and respect both limits above.

### Do I need a Twitter follow SDK?

No. Use any HTTP client or the cURL, Node.js, Python, and Go examples.
A third-party app still needs an approved connected account.

### How do I check or undo a follow?

Use Check Follower for current proof.
Use Unfollow User with new approval and a new idempotency key.

## Headers

<ParamField header="x-api-key" type="string">
  Send your Xquik API key. Generate one from the [dashboard](https://xquik.com/dashboard).
</ParamField>

<ParamField header="Authorization" type="string">
  Send `Bearer <token>` instead of `x-api-key` when using OAuth 2.1.
</ParamField>

<ParamField header="Idempotency-Key" type="string" required>
  Unique key for this intended write. Reuse it only for an exact network replay.
</ParamField>

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

## Path parameters

<ParamField path="id" type="string" required>
  User to follow: user ID, username with or without `@`, or URL-encoded profile URL, such as `x.com/nasa`.
  An unknown username returns `422 x_target_not_found`. See [path IDs](/api-reference/overview#path-ids).
</ParamField>

## Body

<ParamField body="account" type="string" required>
  X username or account ID of your connected account to act as.
</ParamField>

## Response

## Durable write recovery

<Warning>
  Send one unique `Idempotency-Key` per intended write.
  Replay the same account, target, payload, and media after a lost response.
  Keep the original key for that replay.
</Warning>

1. Store `id`, the nested `hash` in `request`, `billing`, and `statusUrl`.
2. Poll after `Retry-After` or `pollAfterMs` when `terminal` is `false`.
3. Retry only when `safeToRetry` is `true`.
4. Use a new key when `nextAction.requiresNewIdempotencyKey` is `true`.

### 200 terminal or 202 active

* After HTTP `200`, store the result and settled billing.
* After HTTP `202`, poll the same action. Never submit another write.
* After HTTP `400`, fix the named field. Use a new idempotency key.
* After HTTP `401`, fix authentication. Do not retry unchanged.
* After HTTP `402`, fund the account before another write.
* After HTTP `403`, reconnect the account.
* After HTTP `409`, keep the original action. Use a new key for new input.
* After HTTP `422`, fix the rejected request before retrying.
* After HTTP `429`, wait for `Retry-After`. Follow `nextAction`.

See [Get Write Action Status](/api-reference/x-write/get-write-action-status)
for every lifecycle field, terminal state, billing field, and retry rule.


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