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

# Create account monitor

> Monitor tweets from one X account and send real-time events to signed webhooks

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

<Callout icon="coins" color="#5c3327">
  **Requires 22 available credits** - 1 credit for the username lookup plus 21 credits for the first active monitor hour
</Callout>

<Note>
  Monitors are unlimited. Active monitors check every 1 second. Webhook and event deliveries are included in active monitor billing.
</Note>

<CodeGroup>
  ```bash cURL theme={null}
  curl -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();
  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()
  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"
      "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()

      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>

The cURL, Node.js, Python, and Go examples convert the created or reactivated
account monitor into one state row. Store `monitor_id`, `username`, `x_user_id`,
`event_types`, `is_active`, `next_billing_at`, `verify_endpoint`,
`update_endpoint`, `delete_endpoint`, `events_endpoint`,
`event_detail_endpoint_pattern`, `webhooks_endpoint`, and
`deliveries_endpoint_pattern` before routing alerts.

## Account monitor handoff

Use `POST /monitors` when a queue, CRM, warehouse, Slack alert, or agent needs real-time tweet alerts from one X account. Create the monitor first, then create a signed webhook with [`POST /webhooks`](/api-reference/webhooks/create) and test it with [`POST /webhooks/{id}/test`](/api-reference/webhooks/test).

<CardGroup cols={2}>
  <Card title="Monitor ID" icon="fingerprint">
    Store `id` as `monitor_id`. Use [Get Monitor](/api-reference/monitors/get)
    to verify state, [Update Monitor](/api-reference/monitors/update) to pause
    or resume, and [Delete Monitor](/api-reference/monitors/delete) only when
    the account should stop permanently.
  </Card>

  <Card title="Stored Account" icon="user">
    Store `username` after trimming the `@` prefix and `xUserId` for identity
    joins, dedupe, and downstream 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 burn.
  </Card>

  <Card title="Stored Event Join" icon="link">
    Use `monitorType: "account"`, `monitorId`, and `username` from
    [List Events](/api-reference/events/list) to join stored events back to the
    monitored account. Use [Get Event](/api-reference/events/get) for one
    event's full payload.
  </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; do not use `x_event_id` as the
    delivery join key. Store `eventType`, `occurredAt`, and `data` with the
    downstream job.
  </Card>
</CardGroup>

Active account monitors check every 1 second and cost 21 credits per active monitor-hour. Creation or reactivation requires 22 available credits: 1 credit for the username lookup plus 21 credits for the first active monitor hour. Pause with [Update Monitor](/api-reference/monitors/update) (`PATCH /monitors/{id}`) and `{ "isActive": false }` when the alert should stop.

## Headers

<ParamField header="x-api-key" type="string" required>
  Your API key. Session cookie authentication is also supported. Generate a key from the [dashboard](https://xquik.com/dashboard).
</ParamField>

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

## Body

<ParamField body="username" type="string" required>
  X username to monitor. 1-15 characters, alphanumeric and underscores only. The `@` prefix is automatically stripped if included.
</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

Valid account monitor types: `tweet.new`, `tweet.quote`, `tweet.reply`,
`tweet.retweet`, `tweet.media`, `tweet.link`, `tweet.poll`, `tweet.mention`,
`tweet.hashtag`, `tweet.longform`, `profile.avatar.changed`,
`profile.banner.changed`, `profile.name.changed`, `profile.username.changed`,
`profile.bio.changed`, `profile.location.changed`, `profile.url.changed`,
`profile.verified.changed`, `profile.protected.changed`,
`profile.pinned_tweet.changed`, `profile.unavailable.changed`.

<CardGroup cols={2}>
  <Card title="tweet.new" icon="bell">
    Original tweet from the monitored account. Used 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

<Tabs>
  <Tab title="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="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 currently active.</ResponseField>
    <ResponseField name="createdAt" type="string">ISO 8601 timestamp of when the monitor was created.</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"
    }
    ```
  </Tab>

  <Tab title="400 Invalid Input">
    ```json theme={null}
    { "error": "invalid_input", "message": "Invalid username format or event types" }
    ```

    Invalid username format or missing/invalid `eventTypes` array.
  </Tab>

  <Tab title="401 Unauthenticated">
    ```json theme={null}
    { "error": "unauthenticated", "message": "Missing or invalid API key" }
    ```

    Missing or invalid API key.
  </Tab>

  <Tab title="402 Payment Required">
    ```json theme={null}
    { "error": "insufficient_credits", "message": "Insufficient credits" }
    ```

    At least 22 available credits are required for the username lookup and first active monitor hour. Possible errors include `no_credits` and `insufficient_credits`.
  </Tab>

  <Tab title="404 User Not Found">
    ```json theme={null}
    { "error": "user_not_found", "message": "X user not found" }
    ```

    The specified X username does not exist or could not be resolved.
  </Tab>

  <Tab title="409 Duplicate">
    ```json theme={null}
    { "error": "monitor_already_exists", "message": "Monitor already exists." }
    ```

    An active monitor already exists for this resolved X account. Use [Update Monitor](/api-reference/monitors/update) to change event types instead.
  </Tab>

  <Tab title="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.
  </Tab>
</Tabs>

<Info>
  If a monitor for the same account was previously deleted, it will be silently reactivated with the new event types instead of creating a duplicate.
</Info>

<Note>
  **Next steps:** [List Monitors](/api-reference/monitors/list) to see all your monitors, [Get Monitor](/api-reference/monitors/get) to fetch details, [Update Monitor](/api-reference/monitors/update) to pause or resume, [Create Webhook](/api-reference/webhooks/create) to receive events, [List Webhooks](/api-reference/webhooks/list) to check subscriptions, [List Events](/api-reference/events/list) and [Get Event](/api-reference/events/get) to audit stored events, or [List Deliveries](/api-reference/webhooks/deliveries) to inspect webhook attempts.
</Note>
