> ## 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 API & Real-time Tweet Alerts

> Create a 1-second keyword monitor for an X search query. Store matching tweet events and deliver selected events to signed webhooks. See event fields.

<Panel>
  <Tabs defaultTabIndex={0} sync={false}>
    <Tab title="201" id="response-monitors-create-keyword-201">
      ```json theme={null}
      {
        "id": "21",
        "query": "xquik OR \"x api\"",
        "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-keyword-400">
      ```json theme={null}
      {
        "error": "invalid_input",
        "message": "Invalid input. Check the request body."
      }
      ```
    </Tab>

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

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

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

Create a Twitter keyword monitor when one search query needs continuous tweet checks. Track brand mentions, handles, hashtags, products, campaigns, replies, reposts, links, or media. Store its ID, query, event types, billing time, and webhook destinations.

<Callout icon="coins" color="#5c3327">
  **Requires 22 available credits** - active keyword monitors bill 21 credits per hour
</Callout>

<Note>
  Keyword 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/keywords \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "xquik api",
      "eventTypes": ["tweet.new"]
    }' |
    jq -c '{
      keyword_monitor_id: .id,
      query: .query,
      event_types: .eventTypes,
      is_active: .isActive,
      created_at: .createdAt,
      next_billing_at: .nextBillingAt,
      verify_endpoint: "/api/v1/monitors/keywords/\(.id)",
      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 response = await fetch("https://xquik.com/api/v1/monitors/keywords", {
    method: "POST",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      query: "xquik api",
      eventTypes: ["tweet.new"],
    }),
  });
  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,
    verify_endpoint: `/api/v1/monitors/keywords/${monitor.id}`,
    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

  response = requests.post(
      "https://xquik.com/api/v1/monitors/keywords",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={"query": "xquik api", "eventTypes": ["tweet.new"]},
  )
  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"],
      "verify_endpoint": f"/api/v1/monitors/keywords/{monitor['id']}",
      "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))
  ```
</CodeGroup>

The cURL, Node.js, and Python examples convert the created or reactivated
keyword monitor into one state row. Store `keyword_monitor_id`, `query`,
`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.

## Keyword Monitor Handoff

Use `POST /monitors/keywords` when a queue, CRM, warehouse, Slack alert, or agent
needs 1-second checks for one X search query. Create the monitor first. Then
create a signed webhook with
[`POST /webhooks`](/api-reference/webhooks/create). Test it with
[`POST /webhooks/{id}/test`](/api-reference/webhooks/test).

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

  <Card title="Normalized Query" icon="search">
    Store `query`; Xquik includes it on keyword monitor events and signed
    webhook payloads.
  </Card>

  <Card title="Event Filter" icon="funnel">
    Store `eventTypes`; keep [List Webhooks](/api-reference/webhooks/list)
    subscriptions aligned so expected tweets deliver.
  </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: "keyword"`, `keywordMonitorId`, and `query` from
    [List Events](/api-reference/events/list) to join stored events back to the
    monitor. 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 audit
    rows. Join delivery `streamEventId` to event IDs. Do not use `x_event_id` as
    the delivery join key.
  </Card>
</CardGroup>

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

## How Do I Monitor Twitter Keywords With an API?

Use one focused query for each alert purpose.
First, write the exact words, phrases, handles, or hashtags requiring alerts.
Then select the tweet event types that should reach downstream workers.
Create the monitor and store its returned ID immediately.

Next, connect a signed webhook for the selected event types.
Send a signed test before accepting production alerts.
Store each event before returning a successful receiver response.
Use the event ID and delivery ID for separate idempotency checks.

This workflow helps applications monitor Twitter keywords without maintaining a stream connection.
The Twitter keyword monitor checks its stored query every second.
Matching tweets become stored events and signed webhook deliveries.
Use [List Events](/api-reference/events/list) when a webhook consumer needs recovery.

## How Do I Choose Twitter Keywords to Monitor?

Start with terms that represent one operational decision.
Support teams can watch product names, error phrases, or direct handles.
Campaign teams can watch campaign hashtags and reply language.
Developers can watch API names, integration phrases, or release mentions.

Prefer an exact phrase when word order changes meaning.
Use `OR` when any listed term should match.
Use a space when every listed term must appear.
Use a leading minus sign to exclude known noise.
Group mixed `OR` conditions with parentheses.

For example, monitor direct mentions with `@xquik`.
Monitor a phrase with `"x api"`.
Combine related terms with `(@xquik OR "xquik api")`.
Exclude reposts with `-is:retweet` when repost alerts add no value.

Test the proposed query with [Search Tweets](/api-reference/x/search-tweets) first.
Review returned tweets before enabling continuous keyword monitoring.
Narrow irrelevant matches before paying for an active monitor.
Never add undocumented operators merely to increase apparent coverage.

## How Do I Track Twitter Mentions and Brand Keywords?

Include the exact handle when direct mentions require action.
Add the brand name when plain-text mentions also matter.
Add specific product names only when workers own those alerts.
Keep unrelated brands in separate monitors and queues.

Tracking mentions requires stable evidence from every matched tweet.
Store the tweet ID, author ID, event type, query, and timestamp.
Keep `keywordMonitorId` beside each stored event.
This join shows which query matched the tweet.

The selected query monitors conversations across public matching tweets.
It does not calculate sentiment or brand reputation.
It also cannot reveal private tweets or direct messages.
Treat mentions of your brand as matched tweets, not inferred opinions.

## When Should I Use Keyword Alerts, Tweet Search, or Account Monitoring?

Choose the surface that matches the required time range and scope.

| Requirement                             | Use                                                      | Result                                             |
| --------------------------------------- | -------------------------------------------------------- | -------------------------------------------------- |
| Continuous matches across many accounts | Keyword monitor                                          | Stored matching tweet events and real time alerts. |
| Historical or on-demand query results   | [Search Tweets](/api-reference/x/search-tweets)          | One cursor-paginated tweet result set.             |
| Selected changes from one known account | [Create Account Monitor](/api-reference/monitors/create) | Tweet and profile events from that username.       |

A focused Twitter monitoring tool should not mix these three scopes.
Use Twitter search for backfill and investigation.
Use an account monitor for one known profile.
Use keyword alerts for continuous matches across public tweets.

Brand monitoring often needs both keyword and account monitors.
Keep their event IDs, monitor IDs, and queue routes separate.
That separation prevents one alert source from impersonating another.

## How Do Real-Time Tweet Alerts Reach My Application?

Create the keyword monitor before registering its webhook destination.
Subscribe the webhook to the same selected event types.
Then send a signed test to validate the receiver.

Verify every signature before parsing the request body.
Store `deliveryId` before queuing downstream work.
Store `streamEventId` before processing the matching tweet.
Return success only after the durable queue write completes.

The Events API provides recovery when live delivery fails.
The Deliveries API shows webhook attempts for one registered endpoint.
Use [Webhook Verification](/webhooks/verification) for receiver validation.
Use [List Deliveries](/api-reference/webhooks/deliveries) for delivery audits.

API access errors require different recovery actions.
Replace invalid credentials after a `401` response.
Add credits before retrying a `402` response.
Respect `Retry-After` before repeating a `429` request.

## How Do I Backfill Tweets Before Starting Keyword Monitoring?

Run the same query through Search Tweets before creating the monitor.
Page until the response reports no next page.
Store every tweet ID and its source query.
Record the newest collected tweet timestamp as the handoff boundary.

Then create the keyword monitor with the reviewed query.
Deduplicate backfill and monitor events by stable tweet ID.
Keep the stored monitor ID beside every continuous event.
Do not reuse a search cursor after changing the query.

A Twitter tracker must distinguish historical results from live alerts.
Search results answer an on-demand time range.
Monitor events represent continuous checks after activation.
Combining both sources without a boundary creates duplicate tweets.

## How Do I Monitor Multiple Keyword Groups?

Use one monitor when all terms share one alert action.
Combine those terms with explicit `OR` grouping.
Use separate monitors when terms require different owners or queues.
Separate monitors also preserve distinct query evidence.

Store each monitor ID, normalized query, event types, and billing time.
Pause obsolete monitors instead of creating uncertain duplicates.
List keyword monitors before repeating a timed-out create request.
A paused duplicate can reactivate with the submitted event types.

Review active monitors before each billing checkpoint.
Every active keyword monitor adds its hourly charge.
Pause queries that no longer trigger a real downstream action.
Do not broaden queries merely to generate more alerts.

## How Do I Keep Twitter Keyword Alerts Actionable?

Assign one owner and queue to each monitor ID.
Route alerts by query, event type, and matched tweet ID.
Keep support alerts separate from campaign or competitor alerts.
Define the required action before activating the monitor.

Review false matches from stored events at a regular interval.
Add exact phrases or exclusions when irrelevant tweets repeat.
Remove a term when it no longer supports an operational decision.
Keep the previous query beside every configuration change.

Do not delete evidence when a query changes.
Stored events explain why earlier alerts reached their original queue.
Record the change time and the responsible operator.
Use a new monitor when ownership or alert purpose changes completely.

Measure matched tweets, accepted alerts, rejected alerts, and processing failures.
Those counts reveal query precision without inventing sentiment scores.
Pause noisy monitors while operators correct their stored queries.
Resume only after a reviewed search returns useful tweets.

## What Does a Twitter Keyword Monitor Not Provide?

A keyword monitor does not return a complete historical archive.
It does not provide follower, following, like, or bookmark changes.
It does not verify giveaway follows, replies, or reposts by itself.
It does not calculate sentiment, reach, or engagement quality.

Use [Followers](/api-reference/x/followers) for follower snapshots.
Use [Following](/api-reference/x/following) for following snapshots.
Use focused tweet endpoints for replies, quotes, and retweeters.
Use Search Tweets when an operator needs historical matching tweets.

This endpoint remains a query-specific Twitter tracker with webhook delivery.
It stores concrete tweet matches instead of inferred marketing conclusions.

## 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="query" type="string" required>
  X search query to monitor. Whitespace is normalized. Maximum length is 512 characters.
</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 keyword monitor types: `tweet.new`, `tweet.quote`, `tweet.reply`,
`tweet.retweet`, `tweet.media`, `tweet.link`, `tweet.poll`, `tweet.mention`,
`tweet.hashtag`, `tweet.longform`.

<CardGroup cols={2}>
  <Card title="tweet.new" icon="bell">
    Matching tweet returned by the query. Used when no reply, quote, or
    retweet signal is present.
  </Card>

  <Card title="tweet.quote" icon="quote">
    Matching quote tweet returned by the query. Include this when quote
    activity should create keyword monitor events and webhook deliveries.
  </Card>

  <Card title="tweet.reply" icon="message-circle">
    Matching reply returned by the query. Include this when support routing,
    conversation tracking, or alerting needs replies.
  </Card>

  <Card title="tweet.retweet" icon="repeat-2">
    Matching retweet returned by the query. Include this when repost activity
    should create keyword monitor events and webhook deliveries.
  </Card>
</CardGroup>

## Response

### 201 Created

<ResponseField name="id" type="string">Unique keyword monitor ID.</ResponseField>
<ResponseField name="query" type="string">Normalized query being monitored.</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 creation timestamp.</ResponseField>
<ResponseField name="nextBillingAt" type="string">Next hourly credit charge time. New active monitors are due immediately.</ResponseField>

```json theme={null}
{
  "id": "21",
  "query": "xquik api",
  "eventTypes": ["tweet.new"],
  "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 query or event types" }
```

Missing query, query longer than 512 characters, or invalid `eventTypes`.

### 401 Unauthenticated

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

Missing or invalid API key.

### 402 Payment Required

```json theme={null}
{ "error": "insufficient_credits", "message": "Insufficient credits" }
```

At least 22 available credits are required before creating or reactivating an active keyword monitor. Possible errors include `no_credits` and `insufficient_credits`.

### 409 Duplicate

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

An active keyword monitor already exists for this normalized query. Use [Update Keyword Monitor](/api-reference/monitors/update-keyword) to change event types or pause it.

### 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>
  If a keyword monitor for the same query exists but is paused, creating it again reactivates that monitor with the new event types.
</Info>

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