> ## Documentation Index
> Fetch the complete documentation index at: https://www.outx.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Reddit Watchlist

> Create a Reddit watchlist by specifying keywords directly or by describing what to track in plain English.

Track Reddit posts and comments containing specific keywords with the same filtering primitives as keyword watchlists. Useful for monitoring subreddit conversations, indie-hacker chatter, support requests, and competitor mentions across Reddit.

The endpoint accepts two body shapes. Pass either `keywords` (direct mode, documented below) or `prompt` (AI mode, documented in [Prompt mode](#prompt-mode) at the bottom of this page), not both.

<Note>
  **Plugin requirement.** API access requires at least one team member to have had the OutX browser extension active within the last 48 hours, otherwise requests return `403 Plugin installation required`. Teams with global data sharing enabled are exempt: the shared pool collects your data, so no local plugin is needed.
</Note>

## Request Body (direct keywords mode)

<ParamField body="name" type="string">
  Watchlist name. If not provided, a name will be auto-generated based on
  keywords.
</ParamField>

<ParamField body="keywords" type="array" required>
  Array of keywords to track on Reddit. Can be simple strings or advanced keyword objects with filtering rules.

  **Simple format:**

  ```json theme={null}
  ["self-hosted", "open source crm", "indie hacker"]
  ```

  **Advanced format with filters:**

  ```json theme={null}
  [
    {
      "keyword": "crm",
      "required_keywords": ["self-hosted", "open source"],
      "excluded_keywords": ["enterprise", "salesforce"],
      "include_all_required": false
    }
  ]
  ```
</ParamField>

<ParamField body="description" type="string">
  Optional description for the watchlist
</ParamField>

<ParamField body="labels" type="array">
  Custom labels (intent categories) used to classify matching posts. Same shape as keyword watchlists; see [how intent labels are calculated](/api-reference/watchlist/keyword/create#how-intent-labels-are-calculated).

  ```json theme={null}
  [
    {
      "name": "buying intent",
      "description": "Threads asking for tool recommendations"
    }
  ]
  ```
</ParamField>

<ParamField body="fetchFreqInHours" type="number" default="24">
  Fetch frequency in hours. Allowed values: `1, 3, 6, 12, 24, 48, 72`. Reddit watchlists default to `24` (less frequent than LinkedIn since Reddit threads update more slowly).
</ParamField>

<ParamField body="slack_webhook_url" type="string | null">
  Optional Slack incoming-webhook URL to receive a notification when new matching posts are found. Pass `null` to leave it unset.
</ParamField>

## Advanced Keyword Filtering

Each keyword can have additional filtering rules:

<ResponseField name="keyword" type="string" required>
  The primary keyword to search for in Reddit posts and comments
</ResponseField>

<ResponseField name="required_keywords" type="array">
  Context keywords used together with the primary keyword. How they combine is controlled by `include_all_required`.
</ResponseField>

<ResponseField name="excluded_keywords" type="array">
  None of these keywords should be present in the post (NOT logic)
</ResponseField>

<ResponseField name="include_all_required" type="boolean" default="true">
  Controls how `required_keywords` combine. `true` (default) means every required keyword must be present (AND logic). `false` means any one is enough (OR logic). OR usually matches far more posts and is what the AI prompt generator uses, so set `include_all_required` to `false` when a multi-term required list is matching almost nothing. Plain-string keyword entries always use the default (AND).
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST \
    "https://api.outx.ai/api-reddit-watchlist" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "name": "Self-hosted CRM Threads",
      "keywords": [
        {
          "keyword": "crm",
          "required_keywords": ["self-hosted", "open source"],
          "excluded_keywords": ["salesforce", "enterprise"]
        },
        "indie hacker crm"
      ],
      "description": "Track Reddit threads about self-hosted CRM tools",
      "labels": [
        {
          "name": "buying intent",
          "description": "Threads asking for tool recommendations"
        }
      ],
      "fetchFreqInHours": 12
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.outx.ai/api-reddit-watchlist", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      name: "Self-hosted CRM Threads",
      keywords: [
        {
          keyword: "crm",
          required_keywords: ["self-hosted", "open source"],
          excluded_keywords: ["salesforce", "enterprise"],
        },
      ],
      fetchFreqInHours: 12,
    }),
  });

  const data = await response.json();
  ```

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

  url = 'https://api.outx.ai/api-reddit-watchlist'
  headers = {
      'Content-Type': 'application/json',
      'x-api-key': 'YOUR_API_KEY'
  }
  payload = {
      'name': 'Self-hosted CRM Threads',
      'keywords': [
          {
              'keyword': 'crm',
              'required_keywords': ['self-hosted', 'open source'],
              'excluded_keywords': ['salesforce', 'enterprise']
          }
      ],
      'fetchFreqInHours': 12
  }

  response = requests.post(url, headers=headers, json=payload)
  ```
</RequestExample>

<ResponseExample>
  ```json Response (201 Created) theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Self-hosted CRM Threads",
    "slug": "self-hosted-crm-threads-550e8400",
    "type": "reddit",
    "keywords": ["crm", "indie hacker crm"],
    "fetchFreqInHours": 12,
    "created": true,
    "results": [
      {
        "success": true,
        "keyword": "crm",
        "keyword_id": "660e8400-e29b-41d4-a716-446655440001"
      }
    ],
    "labels": [
      { "key": "buying intent", "description": "Threads asking for tool recommendations" }
    ]
  }
  ```

  ```json Response (200 OK, existing match) theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Self-hosted CRM Threads",
    "slug": "self-hosted-crm-threads-550e8400",
    "type": "reddit",
    "keywords": ["crm", "indie hacker crm"],
    "fetchFreqInHours": 12,
    "created": false,
    "labels": [
      { "key": "buying intent" }
    ]
  }
  ```
</ResponseExample>

## Idempotency

POST is idempotent on the keyword set. If your team already has a Reddit watchlist whose primary keywords match the request exactly (order-insensitive, lower-cased, trimmed), the existing watchlist is returned with:

* HTTP status **200 OK** (instead of **201 Created**)
* `created: false`
* The existing watchlist's `fetchFreqInHours` and `labels` are returned, your request's values are ignored for the duplicate match.

Use this to safely retry creations without hitting the plan-watchlist limit. The plan check is only applied when a brand-new watchlist would be created.

## Response Fields

<ResponseField name="id" type="string">
  Unique identifier for the watchlist
</ResponseField>

<ResponseField name="name" type="string">
  Watchlist name
</ResponseField>

<ResponseField name="slug" type="string">
  URL-friendly slug for the watchlist
</ResponseField>

<ResponseField name="type" type="string">
  Always "reddit" for Reddit watchlists
</ResponseField>

<ResponseField name="keywords" type="array">
  Array of tracked keywords, normalized to lowercase and trimmed (e.g. `"CompetitorName"` is returned as `"competitorname"`).
</ResponseField>

<ResponseField name="fetchFreqInHours" type="number">
  Fetch frequency in hours
</ResponseField>

<ResponseField name="created" type="boolean">
  `true` when a new watchlist was created (status 201), `false` when an existing watchlist with the same keyword set was returned (status 200).
</ResponseField>

<ResponseField name="results" type="array">
  Array of keyword creation results
</ResponseField>

<ResponseField name="labels" type="array">
  Intent labels persisted on the watchlist, as `{ key, description }` objects. Returned when `labels` were supplied (or derived one-per-keyword when omitted).
</ResponseField>

## Error Responses

| Status Code | Error Message                                                                                       | Description                                                                                                              |
| ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| 400         | Either `keywords` array or `prompt` string is required                                              | No keywords or prompt was supplied                                                                                       |
| 400         | Provide either `keywords` or `prompt`, not both                                                     | Both modes were supplied at once                                                                                         |
| 400         | Invalid fetchFreqInHours. Allowed values: 1, 3, 6, 12, 24, 48, 72 (hours)                           | Fetch frequency was not one of the allowed values                                                                        |
| 401         | Missing API Key / Invalid API Key                                                                   | Invalid or missing API key                                                                                               |
| 402         | Your plan includes up to N watchlists. Upgrade... or delete an existing watchlist to add a new one. | Watchlist quota for your plan reached (counts keyword, people, company, and reddit watchlists together)                  |
| 403         | Plugin installation required                                                                        | No team member has had the OutX browser extension active in the last 48 hours. Exempt if global data sharing is enabled. |

## Use Cases

<AccordionGroup>
  <Accordion title="Track Buying Intent on Subreddits" icon="cart-shopping">
    Catch threads where people ask for tool recommendations:

    ```json theme={null}
    {
      "name": "CRM Buying Threads",
      "keywords": [
        {
          "keyword": "crm",
          "required_keywords": ["recommend", "looking for", "alternatives"]
        }
      ]
    }
    ```
  </Accordion>

  <Accordion title="Monitor Competitor Mentions" icon="magnifying-glass-chart">
    Watch for Reddit posts that name a competitor:

    ```json theme={null}
    {
      "name": "Competitor Mentions on Reddit",
      "keywords": [
        {
          "keyword": "CompetitorName",
          "excluded_keywords": ["partnership", "ad"]
        }
      ],
      "fetchFreqInHours": 12
    }
    ```
  </Accordion>

  <Accordion title="Find Indie Hacker Discussions" icon="code">
    Surface posts in indie-hacker spaces:

    ```json theme={null}
    {
      "name": "Indie Hacker Reddit",
      "keywords": ["indie hacker", "side project", "bootstrapped saas"]
    }
    ```
  </Accordion>
</AccordionGroup>

## Prompt mode

Skip the keyword brainstorming and let OutX generate keywords and intent labels for you. Send a single `prompt` field describing what you want to track in plain English. OutX creates the watchlist immediately and runs keyword and label generation in the background.

### Request Body

<ParamField body="prompt" type="string" required>
  Plain-English description of what to track on Reddit. URLs are allowed; OutX fetches page metadata to improve keyword quality.

  Examples:

  * `"Self-hosted CRM tools and competitors like NocoCRM, EspoCRM, Twenty"`
  * `"People asking for indie-friendly database hosting"`
  * `"Mentions of our product Acme on r/SaaS, r/indiehackers"`
</ParamField>

<ParamField body="name" type="string">
  Optional watchlist name. Auto-generated from the prompt if omitted.
</ParamField>

<ParamField body="fetchFreqInHours" type="number" default="24">
  Fetch frequency in hours. Allowed values: `1, 3, 6, 12, 24, 48, 72`.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST \
    "https://api.outx.ai/api-reddit-watchlist" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "prompt": "Track Reddit threads about self-hosted CRMs and indie SaaS founders looking for alternatives to Salesforce",
      "name": "Self-hosted CRM Reddit",
      "fetchFreqInHours": 24
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.outx.ai/api-reddit-watchlist", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      prompt:
        "Track Reddit threads about self-hosted CRMs and indie SaaS founders looking for alternatives to Salesforce",
      fetchFreqInHours: 24,
    }),
  });

  const result = await response.json();
  console.log("Watchlist created:", result.id);
  ```

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

  headers = {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
  }

  payload = {
      "prompt": "Track Reddit threads about self-hosted CRMs and indie SaaS founders looking for alternatives to Salesforce",
      "fetchFreqInHours": 24,
  }

  response = requests.post(
      "https://api.outx.ai/api-reddit-watchlist",
      headers=headers,
      json=payload,
  )

  result = response.json()
  print("Watchlist created:", result["id"])
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Self-hosted CRM Reddit",
    "slug": "self-hosted-crm-reddit-550e8400",
    "type": "reddit",
    "fetchFreqInHours": 24,
    "prompt": "Track Reddit threads about self-hosted CRMs and indie SaaS founders looking for alternatives to Salesforce",
    "created": true,
    "message": "Watchlist created. Keywords and labels are being generated in the background and will be available shortly."
  }
  ```
</ResponseExample>

Keywords and intent labels populate on the watchlist a few seconds after creation. Use [Get Reddit Watchlist](/api-reference/watchlist/reddit/get) to fetch the latest state.

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="How is a Reddit watchlist different from a keyword watchlist?">
    Both share the same keyword and label primitives. The difference is the source: keyword watchlists scan LinkedIn posts, Reddit watchlists scan Reddit posts and comments. The default fetch frequency is also less frequent (every 24h vs 12h for keyword watchlists) since Reddit threads update on a slower cadence.
  </Accordion>

  <Accordion title="Can I track specific subreddits?">
    Today, Reddit watchlists are keyword-driven and search across Reddit, not scoped to a subreddit list. To bias toward a subreddit, mention it in your prompt (`"Track posts in r/SaaS about ..."`) so the AI keyword generator picks up subreddit-specific vocabulary.
  </Accordion>

  <Accordion title="How soon does tracking start after I create a Reddit watchlist?">
    Tracking begins immediately after creation. OutX scans Reddit on the next fetch cycle, based on the `fetchFreqInHours` value you set. Default is `24` hours.
  </Accordion>

  <Accordion title="What happens when I hit my plan's watchlist limit?">
    When you reach the maximum number of watchlists allowed by your plan (across keyword, people, company, and reddit types combined), the API returns 402. You can either delete an existing watchlist to free up a slot, or upgrade your plan for higher limits.
  </Accordion>
</AccordionGroup>
