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

# Error handling

> Recover from Xquik API error codes and rate limits

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

Every error includes an `error` code. Use it to choose recovery.

<CardGroup cols={3}>
  <Card title="Getting 400?" icon="circle-x">
    Fix your request body. See [validation errors](#error-codes-detailed).
  </Card>

  <Card title="Getting 402?" icon="credit-card">
    Check your balance or subscription. See [billing errors](#error-codes-detailed) or [billing guide](/guides/billing).
  </Card>

  <Card title="Getting 429?" icon="gauge">
    Implement backoff. See [retry strategy](#retry-with-exponential-backoff) or [rate limits](/guides/rate-limits).
  </Card>
</CardGroup>

## Quick reference

Start with the HTTP family, then apply the recovery rule. Retry only when a
card says the error is retryable.

<CardGroup cols={2}>
  <Card title="400 request validation" icon="circle-alert">
    Retry: no. Fix the body, query, or path. Covers `invalid_input`,
    `invalid_json`, `invalid_id`, `invalid_tweet_url`, `invalid_tweet_id`,
    `invalid_username`, `invalid_user_id`, `invalid_tool_type`,
    `invalid_format`, `invalid_params`, `missing_query`, `missing_ids`,
    `missing_params`, `too_many_ids`, and `unsupported_field`.
  </Card>

  <Card title="401 authentication" icon="key-round">
    Retry: no. Check `x-api-key`, regenerate revoked keys, or re-authenticate
    the connected X account. Covers `unauthenticated` and `x_auth_failure`.
  </Card>

  <Card title="402 billing and credits" icon="credit-card">
    Retry: no. Subscribe, reactivate billing, update payment, or top up credits.
    Covers `no_subscription`, `subscription_inactive`, `no_addon`,
    `payment_failed`, `no_credits`, and `insufficient_credits`.
  </Card>

  <Card title="403 permissions and account health" icon="shield-alert">
    Retry: no. Delete an extra key, check billing status, use a participating
    DM account, re-authenticate the X account, or resolve account health on
    x.com. Covers `api_key_limit_reached`, `monitor_limit_reached`,
    `dm_not_permitted`, `account_needs_reauth`, and `account_restricted`.
  </Card>

  <Card title="404 missing resource" icon="search-x">
    Retry: no. Verify the resource ID, connected account, username, tweet ID,
    media, article, draft, or cached style. Covers `not_found`,
    `account_not_found`, `user_not_found`, `tweet_not_found`, `no_media`,
    `article_not_found`, `draft_not_found`, `style_not_found`, and
    `no_cached_style`.
  </Card>

  <Card title="409 duplicate monitor" icon="copy-check">
    Retry: no. Use the existing monitor or update it. Covers
    `monitor_already_exists`.
  </Card>

  <Card title="422 write validation" icon="message-circle-warning">
    Retry: no. Fix the account capability, target, content, DM permissions, or
    media URL before sending again. Covers `x_account_feature_required`,
    `x_account_suspended`, `x_account_protected`, `x_duplicate_action`,
    `x_dm_not_allowed`, `x_target_not_found`, `x_content_too_long`,
    `x_rejected`, and `media_download_failed`.
  </Card>

  <Card title="202 pending confirmation" icon="clock">
    Retry: no. Store `writeActionId`, poll
    [Get Write Action Status](/api-reference/x-write/get-write-action-status),
    and do not retry-send while status is `pending_confirmation`. Covers
    `x_write_unconfirmed`.
  </Card>

  <Card title="429 rate limit or cooldown" icon="timer">
    Retry: mixed. Retry `rate_limit_exceeded` and `x_rate_limited` after
    `Retry-After` or exponential backoff. Wait out `login_cooldown` via
    `retryAfterMs`. Do not retry `x_daily_limit` on the same X account for 24
    hours.
  </Card>

  <Card title="500, 502, and 503 transient failures" icon="rotate-ccw">
    Retry: yes for `internal_error`, `x_api_rate_limited`,
    `x_api_unavailable`, `x_api_unauthorized`, `x_write_failed`, and
    `x_transient_error`. Stop after 3 attempts. For `x_write_ambiguous`, verify
    the result manually before sending anything again.
  </Card>
</CardGroup>

## Error codes (detailed)

**Response format:**

```json theme={null}
{ "error": "error_code", "message": "Human-readable description" }
```

Some errors include additional context fields (e.g. `limit`, `retryAfter`).

<AccordionGroup>
  <Accordion title="Validation errors (400)">
    Request body, query, or path validation failed. Fix the request shape before
    retrying.

    <CardGroup cols={2}>
      <Card title="invalid_input" icon="circle-alert">
        Request body failed validation. Check required fields, types, and enum
        values against the endpoint docs.
      </Card>

      <Card title="invalid_json" icon="file-code">
        Request body is not valid JSON. Rebuild the body and send a parseable
        JSON object.
      </Card>

      <Card title="invalid_id" icon="hash">
        Path ID is not valid. Use the numeric string returned by the create or
        list endpoint.
      </Card>

      <Card title="invalid_tweet_url" icon="link">
        Tweet URL is malformed. Use the full format
        `https://x.com/user/status/ID`.
      </Card>

      <Card title="invalid_tweet_id" icon="message-circle">
        Tweet ID is empty or malformed. Extract the final numeric status ID
        before calling tweet, media, or article endpoints.
      </Card>

      <Card title="invalid_username" icon="users">
        Username or user path value is empty or invalid. Send a username without
        the `@` prefix, or send a numeric user ID where supported.
      </Card>

      <Card title="invalid_user_id" icon="users">
        User lookup input is invalid or does not resolve. Check the username or
        numeric user ID before retrying.
      </Card>

      <Card title="invalid_tool_type" icon="database">
        Extraction tool type is not recognized. Use one of the 23 valid tool
        types from [Create Extraction](/api-reference/extractions/create).
      </Card>

      <Card title="invalid_format" icon="file-text">
        Export format is unsupported. Use `csv`, `json`, `md`, `md-document`,
        `pdf`, `txt`, or `xlsx`.
      </Card>

      <Card title="invalid_params" icon="circle-alert">
        Export query parameters are invalid. Check the `format` and `type`
        values for that export endpoint.
      </Card>

      <Card title="missing_query" icon="search">
        Required search query is missing. Add the `q` parameter before calling
        search or community endpoints.
      </Card>

      <Card title="missing_ids" icon="list">
        Required multi-ID query is missing. Provide comma-separated numeric IDs
        in the `ids` parameter.
      </Card>

      <Card title="missing_params" icon="circle-alert">
        Required query parameters are missing. Check the endpoint docs; follower
        checks require both source and target.
      </Card>

      <Card title="too_many_ids" icon="list">
        Too many IDs were requested at once. Split requests into groups of 100
        IDs or fewer.
      </Card>

      <Card title="unsupported_field" icon="circle-x">
        Request body contains a field this endpoint does not accept. For tweet
        posts, send public media URLs in `media`, not uploaded media IDs.
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Authentication errors (401)">
    Missing or invalid credentials. Check your API key or session.

    <CardGroup cols={2}>
      <Card title="unauthenticated" icon="key-round">
        API key or bearer token is missing or invalid. Send `x-api-key` or
        regenerate a revoked key.
      </Card>

      <Card title="x_auth_failure" icon="refresh-cw">
        Connected X account session expired or was invalidated. Re-authenticate
        the account from the [dashboard](https://xquik.com/dashboard).
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Billing & subscription errors (402)">
    Subscription or payment issue. See [Billing & Usage](/guides/billing) for plan details.

    <CardGroup cols={2}>
      <Card title="no_subscription" icon="badge-x">
        No active plan. Start billing from the
        [dashboard](https://xquik.com/dashboard) or call
        [Subscribe](/api-reference/account/subscribe).
      </Card>

      <Card title="subscription_inactive" icon="badge-alert">
        Subscription is inactive. Reactivate billing from the
        [dashboard](https://xquik.com/dashboard).
      </Card>

      <Card title="no_addon" icon="archive">
        Legacy monitor add-on state. Check billing status; current plans include
        unlimited monitor slots.
      </Card>

      <Card title="payment_failed" icon="credit-card">
        Payment processing failed. Update the payment method from the
        [dashboard](https://xquik.com/subscription).
      </Card>

      <Card title="no_credits" icon="coins">
        No credit balance is available. Check balance with
        [Get Account](/api-reference/account/get), then top up or subscribe.
      </Card>

      <Card title="insufficient_credits" icon="wallet-cards">
        Balance is below the required operation cost. Check
        [Get Account](/api-reference/account/get), then
        [Top Up Credits](/api-reference/credits/topup).
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Permission errors (403)">
    Action not allowed under current plan or limits.

    <CardGroup cols={2}>
      <Card title="api_key_limit_reached" icon="key-round">
        The account already has 100 active API keys. Revoke an active key
        before creating another.
      </Card>

      <Card title="monitor_limit_reached" icon="users">
        Legacy monitor slot limit. Check billing status; current plans include
        unlimited monitor slots.
      </Card>

      <Card title="dm_not_permitted" icon="message-circle">
        DM history requires a connected account that participates in the
        conversation. Use a participating account or reconnect it from the
        [dashboard](https://xquik.com/dashboard).
      </Card>

      <Card title="account_needs_reauth" icon="refresh-cw">
        Connected X account session needs re-authentication. Reconnect the
        account from the [dashboard](https://xquik.com/dashboard), then retry.
      </Card>

      <Card title="account_restricted" icon="shield-alert">
        Connected X account is locked, suspended, recovering, or temporarily
        blocked. Resolve account health on x.com or wait before retrying.
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Not found errors (404)">
    The requested resource does not exist, is unavailable to this API key, or
    is not the expected X object type.

    <CardGroup cols={2}>
      <Card title="not_found" icon="search-x">
        Generic resource lookup failed. Verify the ID belongs to your account
        and has not been deleted.
      </Card>

      <Card title="account_not_found" icon="users">
        Connected X account was not found for this user. Call
        [List X Accounts](/api-reference/x-accounts/list) and use a valid
        connected account.
      </Card>

      <Card title="user_not_found" icon="users">
        X username or numeric user ID does not resolve. Confirm the username
        with the user or try a different handle.
      </Card>

      <Card title="tweet_not_found" icon="message-circle">
        Tweet ID does not resolve. Check the numeric tweet ID; the tweet may
        have been deleted.
      </Card>

      <Card title="no_media" icon="image">
        Tweet exists but has no downloadable media attachments. Use a tweet
        that contains media.
      </Card>

      <Card title="article_not_found" icon="file-text">
        Tweet ID is valid but is not an X Article. Ask for an X Article URL or
        use a normal tweet or thread endpoint.
      </Card>

      <Card title="draft_not_found" icon="file-text">
        Draft ID does not exist. Verify the draft ID or create a new draft.
      </Card>

      <Card title="style_not_found" icon="pen-line">
        Writing style ID was not found. Analyze tweets first with
        [Analyze Style](/api-reference/styles/analyze).
      </Card>

      <Card title="no_cached_style" icon="pen-line">
        No cached writing style exists for username lookup. Analyze tweets
        first with [Analyze Style](/api-reference/styles/analyze).
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Conflict errors (409)">
    A monitor with the same target already exists. Treat the response as a
    handoff to the existing monitor instead of retrying creation.

    <CardGroup cols={2}>
      <Card title="monitor_already_exists" icon="copy-check">
        Duplicate account or keyword monitor. List existing monitors, reuse the
        monitor ID, or update event types with
        [Update Monitor](/api-reference/monitors/update) or
        [Update Keyword Monitor](/api-reference/monitors/update-keyword).
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Validation errors (422)">
    Write validation failed. Change the account, target, content, DM
    permission, or media input before retrying.

    <CardGroup cols={2}>
      <Card title="x_account_feature_required" icon="lock-keyhole">
        Account capability is missing. Use an account with the required
        capability or adjust the request.
      </Card>

      <Card title="x_account_suspended" icon="shield-alert">
        Connected X account is suspended or restricted. Resolve account status
        on x.com before sending more writes from it.
      </Card>

      <Card title="x_account_protected" icon="lock">
        Target account is protected. Request access first or choose a target
        account that the connected account can interact with.
      </Card>

      <Card title="x_duplicate_action" icon="copy-check">
        Operation is already complete. Do not retry unchanged; check the target
        state before sending anything again.
      </Card>

      <Card title="x_dm_not_allowed" icon="message-circle">
        Recipient does not accept DMs from this account. Use a permitted
        connected account or ask the recipient to allow messages.
      </Card>

      <Card title="x_target_not_found" icon="search-x">
        Tweet or user target does not exist. Verify the ID or username before
        sending another request.
      </Card>

      <Card title="x_content_too_long" icon="message-circle-warning">
        Content exceeds the character limit. Shorten the text or use an account
        that supports the requested content length.
      </Card>

      <Card title="x_rejected" icon="circle-x">
        X rejected the write without a specific reason. Change the request,
        wait 2-3 minutes after rapid attempts, then retry changed content.
      </Card>

      <Card title="media_download_failed" icon="image">
        Public media URL could not be downloaded. Fix the HTTPS URL or pass the
        file via multipart/form-data. Do not retry the same URL.
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Unconfirmed write (202)">
    The write action was dispatched, but final confirmation is still pending.

    <CardGroup cols={2}>
      <Card title="x_write_unconfirmed" icon="clock">
        Action may have completed but could not be confirmed. The response
        includes `status: "pending_confirmation"`, `writeActionId`,
        `charged: false`, and `retryable: false`.
      </Card>

      <Card title="Recovery" icon="circle-check">
        Store `writeActionId`, call [Get Write Action Status](/api-reference/x-write/get-write-action-status), and do not retry-send while status is `pending_confirmation`.
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Rate limit errors (429)">
    Request rate exceeded. See [Rate Limits](/guides/rate-limits) for tier details.

    <CardGroup cols={2}>
      <Card title="rate_limit_exceeded" icon="timer">
        Xquik tier or action limit was reached. Wait the `Retry-After` seconds
        from the response; JSON also includes `retryAfter` when available.
      </Card>

      <Card title="login_cooldown" icon="clock">
        A recent login attempt triggered cooldown. Wait `retryAfterMs` or the
        `Retry-After` header before reconnecting or reauthenticating.
      </Card>

      <Card title="x_rate_limited" icon="gauge">
        X throttled the write. Wait 2-3 minutes, avoid rapid consecutive
        requests to the same account, then retry with backoff.
      </Card>

      <Card title="x_daily_limit" icon="calendar-x">
        Connected X account reached its daily posting limit. Wait 24 hours
        before retrying that account, or use another connected account.
      </Card>
    </CardGroup>
  </Accordion>

  <Accordion title="Server & service errors (500/502/503)">
    Transient failures. Retry with exponential backoff (max 3 attempts).

    <CardGroup cols={2}>
      <Card title="internal_error" icon="server-crash">
        Server error. Retry with backoff and
        [contact support](mailto:support@xquik.com) if it persists.
      </Card>

      <Card title="x_api_rate_limited" icon="timer-reset">
        Read service rate limited. Retry in a few minutes.
      </Card>

      <Card title="x_api_unavailable" icon="cloud-off">
        Read service temporarily unavailable or busy. Respect `Retry-After`
        when present, otherwise retry with backoff.
      </Card>

      <Card title="x_api_unauthorized" icon="key-round">
        Read service authentication failed. Retry later and
        [contact support](mailto:support@xquik.com) if it persists.
      </Card>

      <Card title="x_write_failed" icon="circle-x">
        Write action failed unexpectedly. Retry the request and
        [contact support](mailto:support@xquik.com) if it persists.
      </Card>

      <Card title="x_write_ambiguous" icon="activity">
        Write action completion could not be confirmed. Verify the result
        manually before sending anything again.
      </Card>

      <Card title="x_transient_error" icon="rotate-ccw">
        Write service timeout or temporary failure. Retry with backoff.
      </Card>
    </CardGroup>
  </Accordion>
</AccordionGroup>

## Write confirmation recovery

Because `202` is a successful HTTP status, check `response.status` before
generic `response.ok` handling. This keeps pending tweet and reply writes out of
your normal success path.

<Steps>
  <Step title="Branch on the pending write response">
    If `response.status === 202` and `error === "x_write_unconfirmed"`, store `writeActionId`, `status`, `charged`, `chargedCredits`, and `retryable`.
  </Step>

  <Step title="Poll the write action">
    Poll `GET /api/v1/x/write-actions/{id}` until `status` is `success` or `failed`.
  </Step>

  <Step title="Persist the final ID">
    Only persist `tweetId` or `messageId` after the status endpoint confirms success.
  </Step>

  <Step title="Avoid duplicate writes">
    Do not retry-send while the write action status is `pending_confirmation`.
  </Step>
</Steps>

## Retry with exponential backoff

Retry only on `429` and `5xx` responses. Use the `Retry-After` header first,
then exponential backoff with jitter. Stop after 3 attempts.

**Formula:** `delay = baseDelay * 2^attempt + random(0, jitter)`

```ts theme={null}
function retryDelayMs(response: Response, attempt: number): number {
  const retryAfter = response.headers.get("Retry-After");

  if (retryAfter) {
    return Number.parseInt(retryAfter, 10) * 1000;
  }

  return 1000 * 2 ** attempt + Math.floor(Math.random() * 1000);
}

function shouldRetry(response: Response): boolean {
  return response.status === 429 || response.status >= 500;
}
```

## Rate limit handling

When a request is rate limited, Xquik returns `429 Too Many Requests` with a
`Retry-After` header. Some JSON bodies also include `retryAfter` in seconds or
`retryAfterMs` in milliseconds for login cooldowns.

<CardGroup cols={2}>
  <Card title="HTTP status" icon="gauge">
    `429 Too Many Requests` means the request is rate limited or waiting on an
    account cooldown.
  </Card>

  <Card title="Retry-After header" icon="timer">
    The `Retry-After` header gives seconds to wait before sending the same
    request again.
  </Card>
</CardGroup>

<Steps>
  <Step title="Check the status">
    Branch on `response.status === 429` before normal success handling.
  </Step>

  <Step title="Prefer the header">
    Parse `Retry-After` as seconds. If it is missing, read `retryAfter` or `retryAfterMs` from the JSON body.
  </Step>

  <Step title="Wait the full duration">
    Do not send another request for the same operation until the wait expires.
  </Step>

  <Step title="Back off after another 429">
    If the same request returns another 429, apply exponential backoff and stop after 3 attempts.
  </Step>
</Steps>

## Best practices

<AccordionGroup>
  <Accordion title="Distinguish client errors from server errors">
    **4xx errors** (except 429) indicate a problem with your request. Fix the request before retrying. **5xx errors** and **429** are transient. Retry with backoff.
  </Accordion>

  <Accordion title="Log error codes for debugging">
    Always log the full error response including status code and error body. This makes it easy to diagnose issues in production.
  </Accordion>

  <Accordion title="Handle 409 gracefully">
    `monitor_already_exists` is not a failure. The monitor you need already exists. List monitors to find it instead of treating this as an error.
  </Accordion>

  <Accordion title="Set request timeouts">
    Set a 30-second timeout on all API requests. If a request hangs, retry it rather than waiting indefinitely.
  </Accordion>

  <Accordion title="Use idempotent operations">
    Creating a monitor for the same username returns `409`. Deleting a non-existent resource returns `404`. Both are safe to retry.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Rate Limits" icon="gauge" href="/guides/rate-limits">
    Detailed rate limit tiers and client-side rate limiting.
  </Card>

  <Card title="API Overview" icon="book" href="/api-reference/overview">
    Base URL, authentication, and API conventions.
  </Card>
</CardGroup>
