> ## 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 Keyword Monitor Status & Query Checks

> Get one keyword monitor's X query, tracked event types, active state, polling interval, creation time, and latest event checkpoint. See request fields.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="200" id="response-monitors-get-keyword-200">
      ```json theme={null}
      {
        "id": "21",
        "query": "xquik OR \"x api\"",
        "eventTypes": [
          "tweet.new"
        ],
        "isActive": true,
        "createdAt": "2025-01-15T12:00:00Z",
        "nextBillingAt": "2025-01-15T13:00:00Z"
      }
      ```
    </Tab>

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

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

    <Tab title="404" id="response-monitors-get-keyword-404">
      ```json theme={null}
      {
        "error": "not_found",
        "message": "Resource not found."
      }
      ```
    </Tab>

    <Tab title="429" id="response-monitors-get-keyword-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>

## Inspect One Twitter Keyword Monitor

Use this route when a workflow already stores one keyword monitor ID. It
returns the exact X search query, tracked tweet events, active state, creation
time, and next billing checkpoint. Use the list route when the ID is unknown.

Check `query` before routing new matches. It preserves the Twitter keyword
search that created the monitor. Check `eventTypes` before assuming replies,
quotes, reposts, or other tweet events are enabled.

| Single-monitor question      | Response field                      | Incident decision                                    |
| ---------------------------- | ----------------------------------- | ---------------------------------------------------- |
| Is this the intended search? | `id` and `query`                    | Stop if either value differs from the stored alert.  |
| Can it capture new tweets?   | `isActive`                          | Resume only when future polling is required.         |
| Which tweet events qualify?  | `eventTypes`                        | Compare the exact types with webhook subscriptions.  |
| When is the next charge?     | `nextBillingAt`                     | Confirm credits before the billing checkpoint.       |
| Where are matching tweets?   | `GET /events?keywordMonitorId={id}` | Inspect stored events separately from configuration. |

Store `id`, `query`, `eventTypes`, `isActive`, and `nextBillingAt` together.
Pass the same monitor ID to event filters, updates, deletion, and webhook
workflows. This keeps every Twitter monitor handoff tied to one tracked search.

Use this status check before pausing or editing a monitor. A successful read
does not prove a matching tweet exists. Read the events endpoint for captured
tweets, then open one event for its complete payload.

<Callout icon="circle-check" color="#16a34a">
  **Free** - does not consume credits
</Callout>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET https://xquik.com/api/v1/monitors/keywords/21 \
    -H "x-api-key: xq_YOUR_KEY_HERE" |
    jq -c '{
      keyword_monitor_id: .id,
      query: .query,
      event_types: .eventTypes,
      is_active: .isActive,
      next_billing_at: .nextBillingAt,
      update_endpoint: "/api/v1/monitors/keywords/\(.id)",
      delete_endpoint: "/api/v1/monitors/keywords/\(.id)",
      events_endpoint: "/api/v1/events?keywordMonitorId=\(.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 monitorId = "21";
  const response = await fetch(
    `https://xquik.com/api/v1/monitors/keywords/${monitorId}`,
    {
      method: "GET",
      headers: { "x-api-key": "xq_YOUR_KEY_HERE" },
    },
  );
  const monitor = await response.json();
  const monitorState = {
    keyword_monitor_id: monitor.id,
    query: monitor.query,
    event_types: monitor.eventTypes,
    is_active: monitor.isActive,
    created_at: monitor.createdAt,
    next_billing_at: monitor.nextBillingAt,
    update_endpoint: `/api/v1/monitors/keywords/${monitor.id}`,
    delete_endpoint: `/api/v1/monitors/keywords/${monitor.id}`,
    events_endpoint: `/api/v1/events?keywordMonitorId=${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

  monitor_id = "21"
  response = requests.get(
      f"https://xquik.com/api/v1/monitors/keywords/{monitor_id}",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
  )
  monitor = response.json()
  monitor_state = {
      "keyword_monitor_id": monitor["id"],
      "query": monitor["query"],
      "event_types": monitor["eventTypes"],
      "is_active": monitor["isActive"],
      "created_at": monitor["createdAt"],
      "next_billing_at": monitor["nextBillingAt"],
      "update_endpoint": f"/api/v1/monitors/keywords/{monitor['id']}",
      "delete_endpoint": f"/api/v1/monitors/keywords/{monitor['id']}",
      "events_endpoint": f"/api/v1/events?keywordMonitorId={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 (
      "encoding/json"
      "log"
      "net/http"
      "os"
  )

  type KeywordMonitor struct {
      ID            string   `json:"id"`
      Query         string   `json:"query"`
      EventTypes    []string `json:"eventTypes"`
      IsActive      bool     `json:"isActive"`
      CreatedAt     string   `json:"createdAt"`
      NextBillingAt string   `json:"nextBillingAt"`
  }

  type KeywordMonitorState struct {
      KeywordMonitorID           string   `json:"keyword_monitor_id"`
      Query                      string   `json:"query"`
      EventTypes                 []string `json:"event_types"`
      IsActive                   bool     `json:"is_active"`
      CreatedAt                  string   `json:"created_at"`
      NextBillingAt              string   `json:"next_billing_at"`
      UpdateEndpoint             string   `json:"update_endpoint"`
      DeleteEndpoint             string   `json:"delete_endpoint"`
      EventsEndpoint             string   `json:"events_endpoint"`
      EventDetailEndpointPattern string   `json:"event_detail_endpoint_pattern"`
      WebhooksEndpoint           string   `json:"webhooks_endpoint"`
      DeliveriesEndpointPattern  string   `json:"deliveries_endpoint_pattern"`
  }

  func main() {
      monitorID := "21"
      req, err := http.NewRequest("GET", "https://xquik.com/api/v1/monitors/keywords/"+monitorID, nil)
      if err != nil {
          log.Fatal(err)
      }
      req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")

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

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

The cURL, Node.js, Python, and Go examples convert the fetched keyword monitor
into one state snapshot row. Store `keyword_monitor_id`, `query`, `event_types`,
`is_active`, `next_billing_at`, `update_endpoint`, `delete_endpoint`,
`events_endpoint`, `event_detail_endpoint_pattern`, `webhooks_endpoint`, and
`deliveries_endpoint_pattern` before changing filters, pausing alerts, or
reconciling webhooks.

## State handoff

Use `GET /monitors/keywords/{id}` before changing routing, billing checks, or
alert state for one keyword monitor. The endpoint returns the current stored
monitor for your account only; deleted or cross-account IDs return `404`.

| Keyword monitor column | Response source | Decision rule                                       |
| ---------------------- | --------------- | --------------------------------------------------- |
| Monitor ID             | `id`            | Use this ID for updates, events, and deletion.      |
| X search query         | `query`         | Compare the stored query with the intended search.  |
| Tweet event filter     | `eventTypes`    | Align webhook subscriptions with these event types. |
| Polling state          | `isActive`      | Resume only when future tweet checks are required.  |
| Creation time          | `createdAt`     | Preserve the monitor configuration timestamp.       |
| Billing checkpoint     | `nextBillingAt` | Review credits before the next active charge.       |
| Missing monitor        | `404 not_found` | Stop changes for deleted or cross-account IDs.      |

<CardGroup cols={2}>
  <Card title="Current Filter" icon="funnel">
    Treat `query` and `eventTypes` as the active matching contract. Mirror
    `eventTypes` into [List Webhooks](/api-reference/webhooks/list) before
    relying on signed alerts.
  </Card>

  <Card title="Active State" icon="power">
    Use `isActive` to decide whether the monitor should poll and bill. Use
    [Update Keyword Monitor](/api-reference/monitors/update-keyword) to pause or
    resume it.
  </Card>

  <Card title="Billing Check" icon="coins">
    Read `nextBillingAt` before credit alerts, budget checks, or account
    handoffs. Paused monitors stay visible but do not add hourly monitor burn.
  </Card>

  <Card title="Event Join" icon="link">
    Use `id` as `keywordMonitorId` with
    [List Events](/api-reference/events/list) to reconcile stored events and
    webhook deliveries for this query. Use
    [Get Event](/api-reference/events/get) for one event's full payload.
  </Card>

  <Card title="Delivery Audit" icon="activity">
    Use [List Deliveries](/api-reference/webhooks/deliveries) when webhook
    delivery evidence must be retained. Join delivery `streamEventId` to event
    IDs. Do not use `x_event_id` as the delivery join key.
  </Card>

  <Card title="Delete Path" icon="trash-2">
    Use [Delete Keyword Monitor](/api-reference/monitors/delete-keyword) only
    when the query should stop permanently. Export event and delivery evidence
    first when support or audit workflows need history.
  </Card>
</CardGroup>

## Verify One Alert Before Incident Review

Inspect one stored monitor before investigating a missed or unexpected alert.
Start with the monitor ID recorded by the alerting system. A list response can
hide which row the workflow actually used.

Compare the returned `query` with the intended Twitter search expression.
Check capitalization, quoted phrases, exclusions, and operators. Store the
returned value as evidence. Do not reconstruct it from a dashboard label.

Next, compare `eventTypes` with the event under review. A monitor configured
only for `tweet.new` cannot explain an expected profile-change alert. Update
the filter only after recording its current value.

Read `isActive` before examining an empty event window. A paused monitor stays
available through this endpoint. It does not create future matching events.
Check `nextBillingAt` when the monitor should be active.

Use the returned ID to query stored events. Keep these outcomes separate:

* The monitor exists, but its query does not match the expected tweet.
* The query matches, but the required event type is absent.
* The event type exists, but the monitor is paused.
* The monitor is active, but no stored event matches the review window.
* A stored event exists, but its webhook delivery needs inspection.

Open the matching event before diagnosing webhook delivery. Then join its
event ID with `streamEventId` from delivery records. This separates search
matching from notification transport.

Finish with a compact incident note. Record the monitor ID, exact query,
active state, event types, event ID, and delivery result. That record lets
another operator repeat the check without listing every monitor.

## Diagnose One Keyword Monitor

Start with the returned monitor ID, query, event types, and active state. Check `nextBillingAt` and remaining credits before investigating a missing alert.

Run the exact query through tweet search. Relevant results confirm query coverage, not webhook delivery.

Inspect stored events by `keywordMonitorId`. Inspect delivery records by webhook ID. Keep `streamEventId` separate from each delivery ID.

Do not edit the monitor during diagnosis. Capture its previous state before any approved change.

## Prove a Keyword Alert With Stored Evidence

Build one evidence chain for the alert under review. Start with this endpoint's
monitor response. Preserve its ID, exact query, active state, and event types.

Run the exact query through [Tweet Search](/api-reference/x/search-tweets).
Save matching Tweet IDs and creation times. A search match proves query
coverage. It does not prove that a monitor stored an event.

Next, list stored events for the same keyword monitor ID. Match the expected
Tweet ID when the event payload exposes it. Preserve the event ID and event
timestamp. An event proves monitor ingestion. It does not prove webhook
delivery.

Finally, inspect deliveries for the subscribed webhook. Join each delivery's
`streamEventId` to the stored event ID. Record its status and attempt time. A
delivery record proves notification handling.

Keep three outcomes separate:

* Search found the tweet, but no monitor event exists.
* A monitor event exists, but no delivery references it.
* A delivery exists, but the receiving application rejected it.

Never report those outcomes as one generic alert failure. Each outcome needs a
different correction. Query changes affect matching. Monitor state affects
future event creation. Webhook work affects notification transport.

Record the investigation window in UTC. Compare tweet, event, and delivery
timestamps inside that window. Avoid using dashboard refresh time as evidence.

Finish with one durable incident record. Include monitor ID, query, Tweet ID,
event ID, webhook ID, and delivery result. Link every conclusion to a returned
field. This makes another operator's review repeatable.

## Distinguish Configuration Drift From Missing Tweets

Compare the returned query with the approved query character by character.
Check quoted phrases, exclusions, hashtags, usernames, and search operators.
One missing operator can change every matched tweet.

Compare `eventTypes` with the approved event scope. Keep the full returned
array. Do not summarize several values as a broad monitoring label.

Check `isActive` and `nextBillingAt` together. A stored monitor can remain
visible while paused. A future billing timestamp supports the next budget
review. Neither field proves that a specific tweet created an event.

Use [Update Account Monitor](/api-reference/monitors/update) only for account
monitors. Keyword monitors use their dedicated update route. Keep monitor types
separate when support tickets contain several IDs.

## Path parameters

<ParamField path="id" type="string" required>
  The unique keyword monitor ID. Returned when you [create a keyword monitor](/api-reference/monitors/create-keyword) or [list keyword monitors](/api-reference/monitors/list-keywords).
</ParamField>

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

## Response

### 200 OK

<ResponseField name="id" type="string">Unique keyword monitor ID.</ResponseField>
<ResponseField name="query" type="string">Normalized X search query.</ResponseField>
<ResponseField name="eventTypes" type="string[]">Subscribed event types.</ResponseField>
<ResponseField name="isActive" type="boolean">Whether the monitor is currently active.</ResponseField>
<ResponseField name="createdAt" type="string">ISO 8601 creation timestamp.</ResponseField>
<ResponseField name="nextBillingAt" type="string">Next hourly credit charge time for active monitor billing.</ResponseField>

```json theme={null}
{
  "id": "21",
  "query": "xquik OR \"x api\"",
  "eventTypes": ["tweet.new"],
  "isActive": true,
  "createdAt": "2026-02-24T10:30:00.000Z",
  "nextBillingAt": "2026-02-24T11:30:00.000Z"
}
```

### 400 Invalid ID

```json theme={null}
{ "error": "invalid_id", "message": "Invalid ID format." }
```

The provided monitor ID is not a valid format.

### 401 Unauthenticated

```json theme={null}
{ "error": "unauthenticated", "message": "Missing or invalid API key" }
```

Missing or invalid API key.

### 404 Not Found

```json theme={null}
{ "error": "not_found", "message": "Monitor not found" }
```

No keyword monitor exists with this ID, or it belongs to a different account.

### 429 Rate Limited

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

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

<Note>
  **Related:** [List Keyword Monitors](/api-reference/monitors/list-keywords), [Update Keyword Monitor](/api-reference/monitors/update-keyword), [Delete Keyword Monitor](/api-reference/monitors/delete-keyword), [List Events](/api-reference/events/list), [Get Event](/api-reference/events/get), [List Webhooks](/api-reference/webhooks/list), or [List Deliveries](/api-reference/webhooks/deliveries).
</Note>
