> ## 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 account monitor API & real-time webhooks

> Monitor one X account every second. Track tweets, replies, quotes, reposts, mentions, media, links, and profile changes. Deliver signed webhook alerts.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="201" id="response-monitors-create-201">
      ```json theme={null}
      {
        "id": "42",
        "username": "elonmusk",
        "xUserId": "1234567890",
        "eventTypes": [
          "tweet.new"
        ],
        "isActive": true,
        "createdAt": "2025-01-15T12:00:00Z",
        "nextBillingAt": "2025-01-15T12:00:00Z"
      }
      ```
    </Tab>

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

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

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

    <Tab title="404" id="response-monitors-create-404">
      ```json theme={null}
      {
        "error": "user_not_found",
        "message": "X user not found. Check the username."
      }
      ```
    </Tab>

    <Tab title="409" id="response-monitors-create-409">
      ```json theme={null}
      {
        "error": "monitor_already_exists",
        "message": "Monitor already exists."
      }
      ```
    </Tab>

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

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

Create a Twitter account monitor for one known profile. Select tweet, profile,
or availability events. Store the monitor ID. Then connect signed webhooks.

<Callout icon="coins" color="#5c3327">
  **Requires 22 available credits.** The username lookup costs 1 credit. The first active monitor hour costs 21 credits.
</Callout>

<Note>
  Monitors are unlimited. Active monitors check every 1 second. Active monitor billing includes webhook and event deliveries.
</Note>

## Create a Twitter monitor for one account

Use this Twitter monitor API for continuous checks on one known profile.
Send the username without `@`. Choose only the required event types.
This API endpoint gives you one stable monitor ID. Use it to join events and
webhook deliveries.

Use `POST /monitors` for Twitter API monitoring from one username.
This tweet monitor covers selected posts, replies, quotes, reposts, and profile
changes. It does not search posts from every public account.

## Choose the right Twitter monitoring option

Choose one option for the required alert scope.

| Monitoring need | Xquik option | Result |
| - | - | - |
| Continuous changes from one known account | `POST /monitors` | Selected tweet and profile events from that username. |
| Specific keywords across many accounts | [Create Keyword Monitor](/api-reference/monitors/create-keyword) | Matching tweet events for one stored query. |
| Historical or on-demand tweet results | [Search Tweets](/api-reference/x/search-tweets) | One paginated result set without continuous alerts. |

Do not replace one option with another after collection starts.
Store the chosen monitor type with every alert.

## How do I monitor a Twitter account with an API?

Create one active monitor for each username requiring continuous checks.
Send the username without `@` and choose exact event types.
Xquik resolves the username to one stable X user ID.
Store both the monitor ID and resolved user ID.

Your application needs no open stream connection.
The account monitor checks selected changes every second.
Real-time Twitter alerts start after connecting a signed webhook.
Stored events remain available for later inspection through the Events API.

Use the monitor ID for updates, pauses, deletion, and event joins.
Use the X user ID for stable account joins.
Never use a display name as the account key.

## Which Twitter account activity can trigger alerts?

Select `tweet.new` for original posts from the monitored account.
Add `tweet.reply`, `tweet.quote`, or `tweet.retweet` for conversation activity.
Use format events for media, links, polls, mentions, hashtags, and long posts.
Each selected event type produces its own alerts.

Profile events cover names, usernames, bios, locations, URLs, avatars, and banners.
They also cover verification, protection, pinned posts, and account availability.
Use `profile.unavailable.changed` when account availability affects a workflow.
Keep previous and current profile values with the stored event.

Choose only events that trigger an action.
Extra event types create alerts that workers must still review.
Update the monitor when the required event set changes.
Do not infer unselected changes from tweet or profile counts.

## How do real-time Twitter alerts reach my application?

Create the account monitor before registering its delivery endpoint.
Then create an HTTPS webhook with the required event filters.
Save the one-time webhook secret in a secret manager.
Send a signed test before accepting production deliveries.

Verify `X-Xquik-Signature`, `X-Xquik-Timestamp`, and `X-Xquik-Nonce` first.
Compute the signature from the raw request body.
Reject invalid signatures before parsing or queuing the payload.
See [Webhook Verification](/webhooks/verification) for complete receiver examples.

Use `deliveryId` for delivery-level idempotency.
Use `streamEventId` for one-time monitor event processing.
Store the queue row before returning a successful receiver response.
Inspect [Webhook Deliveries](/api-reference/webhooks/deliveries) when alerts stop arriving.

## How do I monitor competitor Twitter account activity?

Create one account monitor for each competitor username.
Track new tweets, replies, quotes, reposts, links, and media.
Add profile events for bio, username, avatar, banner, and pinned-post changes.
Store each event type, timestamp, monitor ID, and X user ID.

This workflow records account changes.
It does not calculate sentiment, brand reputation, or share of voice.
Use a keyword monitor for mentions across unrelated accounts.
Use tweet search for a retrospective competitor query.

Keep competitor alerts separate from your own account alerts.
Route each monitor ID to its intended queue or workspace.
A competitor event then cannot trigger unrelated jobs.

## How do I monitor multiple Twitter accounts?

Create one monitor request per username.
Monitors are unlimited, but each active monitor has hourly billing.
Keep at least 22 credits before creating or restoring each monitor.
Store every returned monitor ID before creating the next request.

An active duplicate returns `409 monitor_already_exists`.
Use [List Monitors](/api-reference/monitors/list) to recover its stored ID.
Use [Update Monitor](/api-reference/monitors/update) to change events or active state.
Pause a monitor when you can. Do not create a replacement.

Store each resolved X user ID beside the current username.
The user ID stays the same when a username-change event arrives.
Review `nextBillingAt` before keeping large monitor sets active.

## What does an account monitor not track?

Account monitors do not emit follower-gained or follower-lost events.
They also exclude likes, bookmarks, and direct-message activity.
They do not return a complete historical timeline.
They do not search specific keywords across every account.

Use [Followers](/api-reference/x/followers) for paginated follower snapshots.
Use [Following](/api-reference/x/following) for paginated following snapshots.
Use [User Tweets](/api-reference/x/user-tweets) for timeline retrieval.
Use [Create Keyword Monitor](/api-reference/monitors/create-keyword) for matching queries.

Do not use aggregate counts in place of participant or relationship records.
Choose the endpoint that returns the required tweets, profiles, or relationships.

## How do I recover from monitor and webhook failures?

List account monitors before repeating an uncertain create request.
Reuse the stored monitor when the first request succeeded.
Retry the same username and event types only when no monitor exists.

Correct invalid usernames or event arrays after a `400` response.
Replace missing credentials after `401` authentication errors.
Add credits before retrying a `402 insufficient_credits` response.
Check the username after a `404 user_not_found` response.
Reuse the existing monitor after a `409` duplicate response.
Respect `Retry-After` before repeating a `429` request.

A webhook failure does not require a new monitor.
Fix the receiver, verify its signature code, and send another signed test.
Then inspect delivery attempts and join `streamEventId` to the stored event.

<CodeGroup>
  ```bash cURL theme={null}
  curl --fail-with-body -X POST https://xquik.com/api/v1/monitors \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Content-Type: application/json" \
    -d '{
      "username": "elonmusk",
      "eventTypes": ["tweet.new", "tweet.reply"]
    }' |
    jq -c '{
      monitor_id: .id,
      username: .username,
      x_user_id: .xUserId,
      event_types: .eventTypes,
      is_active: .isActive,
      created_at: .createdAt,
      next_billing_at: .nextBillingAt,
      verify_endpoint: "/api/v1/monitors/\(.id)",
      update_endpoint: "/api/v1/monitors/\(.id)",
      delete_endpoint: "/api/v1/monitors/\(.id)",
      events_endpoint: "/api/v1/events?monitorId=\(.id)",
      event_detail_endpoint_pattern: "/api/v1/events/{event_id}",
      webhooks_endpoint: "/api/v1/webhooks",
      deliveries_endpoint_pattern: "/api/v1/webhooks/{webhook_id}/deliveries"
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/monitors", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      username: "elonmusk",
      eventTypes: ["tweet.new", "tweet.reply"],
    }),
  });
  const monitor = await response.json();
  if (!response.ok) {
    throw new Error(monitor.message || "Twitter monitor creation failed.");
  }
  const monitorState = {
    monitor_id: monitor.id,
    username: monitor.username,
    x_user_id: monitor.xUserId,
    event_types: monitor.eventTypes,
    is_active: monitor.isActive,
    created_at: monitor.createdAt,
    next_billing_at: monitor.nextBillingAt,
    verify_endpoint: `/api/v1/monitors/${monitor.id}`,
    update_endpoint: `/api/v1/monitors/${monitor.id}`,
    delete_endpoint: `/api/v1/monitors/${monitor.id}`,
    events_endpoint: `/api/v1/events?monitorId=${monitor.id}`,
    event_detail_endpoint_pattern: "/api/v1/events/{event_id}",
    webhooks_endpoint: "/api/v1/webhooks",
    deliveries_endpoint_pattern: "/api/v1/webhooks/{webhook_id}/deliveries",
  };
  process.stdout.write(`${JSON.stringify(monitorState)}\n`);
  ```

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

  response = requests.post(
      "https://xquik.com/api/v1/monitors",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={
          "username": "elonmusk",
          "eventTypes": ["tweet.new", "tweet.reply"],
      },
  )
  monitor = response.json()
  if not response.ok:
      raise RuntimeError(monitor.get("message", "Twitter monitor creation failed."))
  monitor_state = {
      "monitor_id": monitor["id"],
      "username": monitor["username"],
      "x_user_id": monitor["xUserId"],
      "event_types": monitor["eventTypes"],
      "is_active": monitor["isActive"],
      "created_at": monitor["createdAt"],
      "next_billing_at": monitor["nextBillingAt"],
      "verify_endpoint": f"/api/v1/monitors/{monitor['id']}",
      "update_endpoint": f"/api/v1/monitors/{monitor['id']}",
      "delete_endpoint": f"/api/v1/monitors/{monitor['id']}",
      "events_endpoint": f"/api/v1/events?monitorId={monitor['id']}",
      "event_detail_endpoint_pattern": "/api/v1/events/{event_id}",
      "webhooks_endpoint": "/api/v1/webhooks",
      "deliveries_endpoint_pattern": "/api/v1/webhooks/{webhook_id}/deliveries",
  }
  print(json.dumps(monitor_state))
  ```

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

  import (
      "bytes"
      "encoding/json"
      "io"
      "log"
      "net/http"
      "os"
  )

  type Monitor struct {
      ID            string   `json:"id"`
      Username      string   `json:"username"`
      XUserID       string   `json:"xUserId"`
      EventTypes    []string `json:"eventTypes"`
      IsActive      bool     `json:"isActive"`
      CreatedAt     string   `json:"createdAt"`
      NextBillingAt string   `json:"nextBillingAt"`
  }

  type MonitorState struct {
      CreatedAt                  string   `json:"created_at"`
      DeleteEndpoint             string   `json:"delete_endpoint"`
      DeliveriesEndpointPattern  string   `json:"deliveries_endpoint_pattern"`
      EventDetailEndpointPattern string   `json:"event_detail_endpoint_pattern"`
      EventsEndpoint             string   `json:"events_endpoint"`
      EventTypes                 []string `json:"event_types"`
      IsActive                   bool     `json:"is_active"`
      MonitorID                  string   `json:"monitor_id"`
      NextBillingAt              string   `json:"next_billing_at"`
      UpdateEndpoint             string   `json:"update_endpoint"`
      Username                   string   `json:"username"`
      VerifyEndpoint             string   `json:"verify_endpoint"`
      WebhooksEndpoint           string   `json:"webhooks_endpoint"`
      XUserID                    string   `json:"x_user_id"`
  }

  func main() {
      body, _ := json.Marshal(map[string]interface{}{
          "username":   "elonmusk",
          "eventTypes": []string{"tweet.new", "tweet.reply"},
      })

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

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

      if resp.StatusCode < 200 || resp.StatusCode >= 300 {
          problem, readErr := io.ReadAll(resp.Body)
          if readErr != nil {
              log.Fatal(readErr)
          }
          log.Fatalf("Twitter monitor creation failed with %d: %s", resp.StatusCode, string(problem))
      }

      var monitor Monitor
      if err := json.NewDecoder(resp.Body).Decode(&monitor); err != nil {
          log.Fatal(err)
      }
      state := MonitorState{
          CreatedAt:                  monitor.CreatedAt,
          DeleteEndpoint:             "/api/v1/monitors/" + monitor.ID,
          DeliveriesEndpointPattern:  "/api/v1/webhooks/{webhook_id}/deliveries",
          EventDetailEndpointPattern: "/api/v1/events/{event_id}",
          EventsEndpoint:             "/api/v1/events?monitorId=" + monitor.ID,
          EventTypes:                 monitor.EventTypes,
          IsActive:                   monitor.IsActive,
          MonitorID:                  monitor.ID,
          NextBillingAt:              monitor.NextBillingAt,
          UpdateEndpoint:             "/api/v1/monitors/" + monitor.ID,
          Username:                   monitor.Username,
          VerifyEndpoint:             "/api/v1/monitors/" + monitor.ID,
          WebhooksEndpoint:           "/api/v1/webhooks",
          XUserID:                    monitor.XUserID,
      }
      if err := json.NewEncoder(os.Stdout).Encode(state); err != nil {
          log.Fatal(err)
      }
  }
  ```
</CodeGroup>

Each code example maps the response to one monitor row. Save the account IDs,
event filter, active state, next charge time, and monitor routes. The routes
cover updates, events, webhooks, and delivery checks.

## Account monitor handoff

Use `POST /monitors` for one X account. Send alerts to a queue, CRM,
warehouse, Slack, or an agent. It checks selected tweets and profile changes
every second.
Create the monitor first. Then create a signed webhook with
[`POST /webhooks`](/api-reference/webhooks/create). Call
[`POST /webhooks/{id}/test`](/api-reference/webhooks/test) before enabling
production alerts.

| Created monitor column | Response source | Setup rule |
| - | - | - |
| Monitor ID | `id` | Store this ID before configuring alerts. |
| X username | `username` | Store the normalized username without `@`. |
| X user ID | `xUserId` | Use this stable ID for account joins. |
| Event filter | `eventTypes` | Align webhook subscriptions with these event types. |
| Polling state | `isActive` | Run alert checks only for active monitors. |
| Creation time | `createdAt` | Store this timestamp with each monitor audit. |
| Billing checkpoint | `nextBillingAt` | Review available credits before this time. |

<CardGroup cols={2}>
  <Card title="Monitor ID" icon="fingerprint">
    Store `id` as `monitor_id`. Verify state with
    [Get Monitor](/api-reference/monitors/twitter-account-monitor-status).
    Pause or resume with [Update Monitor](/api-reference/monitors/update). Call
    [Delete Monitor](/api-reference/monitors/delete-twitter-account-monitor)
    only when tracking should stop permanently.
  </Card>

  <Card title="Stored account" icon="user">
    Store `username` after trimming the `@` prefix. Store `xUserId` for stable
    joins, deduplication, and account mapping.
  </Card>

  <Card title="Event filter" icon="funnel">
    Store `eventTypes`. Keep [List Webhooks](/api-reference/webhooks/list)
    subscriptions aligned so expected account activity delivers.
  </Card>

  <Card title="Active state" icon="clock">
    Read `isActive` and `nextBillingAt` before enabling alerts or estimating
    hourly monitor cost.
  </Card>

  <Card title="Stored event join" icon="link">
    Read `monitorType: "account"`, `monitorId`, and `username` from
    [List Events](/api-reference/events/list). Use them to join stored events
    to the account. Use [Get Event](/api-reference/events/get) for one event.
  </Card>

  <Card title="Webhook delivery join" icon="webhook">
    Use `deliveryId` for receiver idempotency and
    [List Deliveries](/api-reference/webhooks/deliveries) for delivery
    attempts. Join `streamEventId` to event IDs, and do not use `x_event_id` as the
    delivery join key. Store `eventType`, `occurredAt`, and `data` with the
    job.
  </Card>
</CardGroup>

### What should a webhook receiver save?

Save the monitor ID, username, user ID, event type, event time, and delivery ID.
Use the monitor ID to group alerts for one account. Use the delivery ID to stop
the same job twice. Keep the event ID for later checks. These fields support
replay, audits, retries, and alert routing.

Active account monitors check every 1 second. Each active hour costs 21 credits.
You need 22 available credits to create or restore a monitor. That total includes a 1-credit username lookup and the first active hour. Pause the monitor through
[Update Monitor](/api-reference/monitors/update) (`PATCH /monitors/{id}`). Set
`{ "isActive": false }` when alerts should stop.

## Headers

<ParamField header="x-api-key" type="string" required>
  Send your Xquik API key. Create one in the [Xquik 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="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

## Body

<ParamField body="username" type="string" required>
  Send an X username with 1-15 letters, numerals, or underscores. Xquik removes
  a leading `@` before validation.
</ParamField>

<ParamField body="name" type="string">
  Your own label for the monitor, 1 to 80 characters. Every event the monitor produces carries it as `monitorName`, so you can route events from the payload. Xquik normalizes whitespace.
</ParamField>

<ParamField body="eventTypes" type="string[]" required>
  Array of event types to subscribe to. At least 1 required. See [Valid Event Types](#valid-event-types) below.
</ParamField>

## Valid event types

Choose only the exact event types in the goal map below.

### Match event types to monitor goals

| Monitor goal | Event types | Stored signal |
| - | - | - |
| New posts and conversations | `tweet.new`, `tweet.reply`, `tweet.quote`, `tweet.retweet` | Original posts, replies, quotes, or reposts from one profile. |
| Tweet content formats | `tweet.media`, `tweet.link`, `tweet.poll`, `tweet.mention`, `tweet.hashtag`, `tweet.longform` | Posts containing the selected format or reference. |
| Profile text changes | `profile.name.changed`, `profile.username.changed`, `profile.bio.changed`, `profile.location.changed`, `profile.url.changed` | Previous and current profile text values. |
| Profile image changes | `profile.avatar.changed`, `profile.banner.changed` | Old and new avatar or banner references. |
| Profile state changes | `profile.verified.changed`, `profile.protected.changed`, `profile.pinned_tweet.changed`, `profile.unavailable.changed` | Verification, visibility, pinned post, or availability changes. |

<Warning>
  Account monitors do not emit follower-gained or follower-lost events. Use
  [Followers](/api-reference/x/followers) and
  [Following](/api-reference/x/following) for paginated relationship snapshots.
</Warning>

<CardGroup cols={2}>
  <Card title="tweet.new" icon="bell">
    Original tweet from the monitored account. Xquik uses it when no reply,
    quote, or retweet signal is present.
  </Card>

  <Card title="tweet.quote" icon="quote">
    Quote tweet from the monitored account. Include this when quote activity
    should create stored events and webhook deliveries.
  </Card>

  <Card title="tweet.reply" icon="message-circle">
    Reply from the monitored account. Include this when support routing,
    conversation tracking, or alerting needs replies.
  </Card>

  <Card title="tweet.retweet" icon="repeat-2">
    Retweet from the monitored account. Include this when repost activity should
    create stored events and webhook deliveries.
  </Card>
</CardGroup>

## Response

### 201 Created

<ResponseField name="id" type="string">
  Unique monitor ID.
</ResponseField>

<ResponseField name="username" type="string">
  Stored X username after trimming and removing the `@` prefix.
</ResponseField>

<ResponseField name="name" type="string">
  Your label for the monitor. Present when you set one.
</ResponseField>

<ResponseField name="xUserId" type="string">
  Resolved X user ID for the account.
</ResponseField>

<ResponseField name="eventTypes" type="string[]">
  Event types this monitor is subscribed to.
</ResponseField>

<ResponseField name="isActive" type="boolean">
  Whether the monitor is active.
</ResponseField>

<ResponseField name="createdAt" type="string">
  Xquik records the creation time in ISO 8601 format.
</ResponseField>

<ResponseField name="nextBillingAt" type="string">
  Next hourly credit charge time. New active monitors are due immediately.
</ResponseField>

```json theme={null}
{
  "id": "7",
  "username": "elonmusk",
  "xUserId": "44196397",
  "eventTypes": ["tweet.new", "tweet.reply"],
  "isActive": true,
  "createdAt": "2026-02-24T10:30:00.000Z",
  "nextBillingAt": "2026-02-24T10:30:00.000Z"
}
```

### 400 Invalid input

```json theme={null}
{ "error": "invalid_input", "message": "Invalid input. Check the request body." }
```

Invalid username format or missing/invalid `eventTypes` array.

### 401 Missing API key

```json theme={null}
{
  "error": "unauthenticated",
  "message": "Authentication required. Provide a valid API key or bearer token."
}
```

Missing or invalid API key or OAuth bearer token.

### 402 Payment required

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

Keep at least 22 credits available before sending this request. The API may return
`insufficient_credits` when the balance is too low.

### 404 User not found

```json theme={null}
{ "error": "user_not_found", "message": "X user not found. Check the username." }
```

Xquik could not find that username. Check the spelling.

### 409 Duplicate

```json theme={null}
{ "error": "monitor_already_exists", "message": "Monitor already exists." }
```

An active monitor already tracks this X account. Use
[Update Monitor](/api-reference/monitors/update) to change event types instead.

### 429 Rate limited

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

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

<Info>
  Xquik reactivates a previously deleted monitor with new event types. An active
  duplicate returns `409`.
</Info>

<Note>
  **Next steps.**

  * [List Monitors](/api-reference/monitors/list) to view account monitors.
  * [Get Monitor](/api-reference/monitors/twitter-account-monitor-status) to fetch one monitor.
  * [Update Monitor](/api-reference/monitors/update) to pause or resume checks.
  * [Create Webhook](/api-reference/webhooks/create) to receive events.
  * [List Webhooks](/api-reference/webhooks/list) to check subscriptions.
  * [List Events](/api-reference/events/list) to audit stored events.
  * [Get Event](/api-reference/events/get) to inspect one event.
  * [List Deliveries](/api-reference/webhooks/deliveries) to inspect webhook attempts.
</Note>


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