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

> Unfollow 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-unfollow-200">
      ```json theme={null}
      {
        "object": "x_write_action",
        "id": "12345",
        "writeActionId": "12345",
        "action": "unfollow",
        "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-unfollow-202">
      ```json theme={null}
      {
        "object": "x_write_action",
        "id": "12346",
        "writeActionId": "12346",
        "action": "unfollow",
        "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-unfollow-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-unfollow-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-unfollow-402">
      ```json theme={null}
      {
        "error": "insufficient_credits",
        "message": "Insufficient credits. Top up or subscribe to continue."
      }
      ```
    </Tab>

    <Tab title="403" id="response-x-write-unfollow-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-unfollow-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-unfollow-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-unfollow-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-unfollow-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-unfollow-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-unfollow-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>

## Unfollow one Twitter user by ID

Each request unfollows 1 target user ID.
Each request names 1 connected X account.
Verify the target user ID and acting account before approval.

Compare X's separate [Unfollow User endpoint](https://docs.x.com/x-api/users/unfollow-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.** Unfollow shares the follow-action limits of 20 requests per minute and 400 per day. The DELETE tier also applies. A breached limit returns `429 Too Many Requests`.
</Warning>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE https://xquik.com/api/v1/x/users/44196397/follow \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Idempotency-Key: unfollow-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: "DELETE",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Idempotency-Key": "unfollow-44196397-1895432178065391234",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      account: "myxaccount",
    }),
  });
  const unfollowReceipt = await response.json();
  if (!response.ok) {
    throw new Error(JSON.stringify(unfollowReceipt));
  }
  ```

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

  response = requests.delete(
      "https://xquik.com/api/v1/x/users/44196397/follow",
      headers={
          "x-api-key": "xq_YOUR_KEY_HERE",
          "Idempotency-Key": "unfollow-44196397-1895432178065391234",
      },
      json={
          "account": "myxaccount",
      },
  )
  unfollow_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("DELETE", "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", "unfollow-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 unfollowReceipt map[string]interface{}
      if err := json.NewDecoder(resp.Body).Decode(&unfollowReceipt); err != nil {
          panic(err)
      }
      fmt.Println(unfollowReceipt)
  }
  ```
</CodeGroup>

## Authenticate and select the relationship

Send an Xquik API key or OAuth 2.1 bearer token.
Never send an X password or session cookie.
The path ID names the profile that the acting account follows.
The body names the connected account that will stop following it.

Use the stable numeric user ID as the relationship key.
Keep the username and profile name as review labels.
Show both profiles before a user approves the write action.

The profile page and unfollow button are manual X controls.
This endpoint does the same from code, after approval.

## Unfollow Twitter accounts one request at a time

Create a new idempotency key whenever the relationship changes.
Never reuse the key from an earlier follow action.
Reuse the unfollow key only after an interrupted network request.

Store the returned action ID, request hash, and `statusUrl` from the response.
Poll the same action while `terminal` remains `false`.
Never submit a second write while the first action is active.

The endpoint accepts 1 target user ID per request.
It exposes no mass unfollow body or bulk unfollow feature.
Queue approved targets separately when you unfollow Twitter accounts in bulk.
Each row needs its own target, reason, approval, and idempotency key.

With separate rows, one failure does not affect other accounts.
A failed row must not erase the record of successful unfollow actions.
A team can stage approved rows for later processing.
Store each acting account and target ID separately.

Respect X's terms of service and every returned rate limit.
Unfollow people only after a clear user or workflow decision.

## Select inactive users before unfollowing

This write endpoint does not discover inactive users or non-followers.
Read [Following](/api-reference/x/following) before selecting cleanup targets.
Define inactivity from an approved timestamp or business rule.
Never infer inactivity from a missing profile or stale export.

Store the selection rule with the target user ID.
Review the acting account and target as separate fields.
Then send 1 approved unfollow action for each relationship.

## Verify the Twitter unfollow API result

Poll `statusUrl` until the action becomes terminal.
Store the final status, billing fields, and request identifiers.
Use [Check Follower](/api-reference/x/check-follower) when you need current proof.
Check Following to confirm the target disappeared from the outbound list.

No response field says whether X sent a notification.
Do not claim whether X notified the target account.
Verify the relationship itself.

## Choose unfollow or remove follower

Unfollow stops the connected account from following the target profile.
[Remove Follower](/api-reference/x-write/remove-follower) ends one inbound relationship.
Use Remove Follower when someone should stop following the connected account.

Unretweet removes one repost and changes no follow relationship.
Delete Tweet removes one post and changes no follow relationship.
Keep these write actions in separate steps.

## Handle Twitter API unfollow errors

Fix the target user ID or acting account after `400`.
Replace Xquik authentication after `401`. Reconnect after `403`.
Add credits after `402`. Review rejected input after `422`.
Keep the original action after an idempotency conflict at `409`.
Honor `Retry-After` after `429`.
After `500` or `503`, check `safeToRetry` before retrying.

## Twitter unfollow API questions

### How do I unfollow someone on Twitter with an API?

Approve the target user ID and connected account.
Send this DELETE request, then poll the returned action until terminal.

### Can I mass unfollow or schedule unfollow actions?

Use your scheduler to queue 1 approved target per request.
Throttle the queue to both documented limits above.

### Can I unfollow someone without them knowing?

Xquik cannot confirm whether X sends a notification.
Confirm only the outbound relationship change.

### Do I need unfollow tools or browser extensions?

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

### How do I manage several connected accounts?

Repeat approval for each acting account.
Never reuse one action ID across accounts.

### How do I get an API key?

Create an Xquik API key in the dashboard.
You can also send an OAuth 2.1 bearer token.

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