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

# Update Reddit Watchlist

> Patch fields (name, fetchFreq, keywords, labels, slack webhook, disable) or regenerate the entire keyword set from a new prompt.

Modify an existing Reddit watchlist without losing its ID or collected posts. Every field is optional, send only the properties you want to change.

The endpoint accepts two body shapes. Either patch fields (documented below) or send a new `prompt` to have OutX regenerate the entire keyword set in the background ([Prompt mode](#prompt-mode) at the bottom of this page).

<Note>
  **Plugin requirement.** Like all `/api-reddit-watchlist` methods, updates require at least one team member to have had the OutX browser extension active within the last 48 hours, otherwise the request returns `403 Plugin installation required`. Teams with global data sharing enabled are exempt.
</Note>

## Request Body (patch mode)

<ParamField body="id" type="string" required>
  Watchlist ID to update.
</ParamField>

<ParamField body="name" type="string">
  New watchlist name.
</ParamField>

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

<ParamField body="keywords" type="array">
  Patch the tracked keywords on the watchlist. Accepts the same shape as the [Create endpoint](/api-reference/watchlist/reddit/create), simple strings or advanced keyword objects with `required_keywords`, `excluded_keywords` (NOT), and `include_all_required` (AND vs OR over the required keywords).

  **Simple format:**

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

  **Advanced format:**

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

  By default this replaces the set: the watchlist's existing keywords and associated `reddit_tracking` tasks are deleted and recreated from the new list (set `append: true` to add instead). Updating keywords does **not** change existing labels. Omit the field to leave keywords untouched.
</ParamField>

<ParamField body="append" type="boolean" default="false">
  When `true`, the supplied `keywords` are **added** to the existing set instead of replacing it. Existing keyword tracking rows and tasks are kept, and only keywords whose primary keyword is not already on the list (case-insensitive) are created. Labels are left untouched unless `labels` is also provided.
</ParamField>

<ParamField body="labels" type="array">
  Replace the custom labels on the watchlist. Same shape as Create.

  ```json theme={null}
  [
    { "name": "buying intent", "description": "Threads asking for tool recommendations" },
    { "name": "competitor", "description": "Competitor mentions" }
  ]
  ```

  Labels are only changed when this field is sent. Updating `keywords` alone leaves your existing labels untouched, so a keyword edit will never wipe a hand-built label set. Omit `labels` to leave them as they are.
</ParamField>

<ParamField body="disable" type="boolean">
  Set to `true` to pause tracking, `false` to resume.
</ParamField>

<ParamField body="slack_webhook_url" type="string | null">
  Update or clear the Slack webhook URL for this watchlist. Pass `null` to clear.
</ParamField>

## Semantics

* **Keyword replacement is wipe-and-recreate (default).** Existing `keyword_tracking` rows and their `reddit_tracking` tasks are deleted, then new ones are created from the payload. Posts already collected are **not** deleted, they remain attached to the watchlist and visible via the Posts API.
* **Append mode keeps what you have.** With `append: true`, existing keywords and tasks are kept and only the new, not-yet-present primary keywords are added.
* **Labels are preserved unless you send `labels`.** Updating `keywords` alone never overwrites existing labels. To change labels, pass a `labels` array.
* **Keyword replacement only deletes `reddit_tracking` tasks.** Other task types on the same watchlist are not removed by a keyword update. (`disable` is broader: pausing or resuming a watchlist applies to *all* of its tasks regardless of type.)
* **Partial updates are safe.** Sending only `{ "id": "...", "name": "new name" }` changes just the name; keywords, labels, and tasks are untouched.

<RequestExample>
  ```bash Rename and change frequency theme={null}
  curl -X PUT \
    "https://api.outx.ai/api-reddit-watchlist" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Updated Reddit Watchlist",
      "fetchFreqInHours": 12
    }'
  ```

  ```bash Update keywords and labels theme={null}
  curl -X PUT \
    "https://api.outx.ai/api-reddit-watchlist" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "keywords": [
        {
          "keyword": "crm",
          "required_keywords": ["self-hosted"],
          "excluded_keywords": ["salesforce"]
        },
        "indie hacker"
      ],
      "labels": [
        { "name": "buying intent", "description": "Threads asking for tool recommendations" },
        { "name": "founder-post", "description": "Posts from indie founders" }
      ]
    }'
  ```

  ```bash Pause the watchlist theme={null}
  curl -X PUT \
    "https://api.outx.ai/api-reddit-watchlist" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "disable": true
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.outx.ai/api-reddit-watchlist", {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      id: "550e8400-e29b-41d4-a716-446655440000",
      keywords: [
        {
          keyword: "crm",
          required_keywords: ["self-hosted"],
          excluded_keywords: ["salesforce"],
        },
      ],
      labels: [{ name: "buying intent", description: "Tool recommendation threads" }],
    }),
  });
  ```

  ```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',
  }

  # Update keywords and labels
  payload = {
      'id': '550e8400-e29b-41d4-a716-446655440000',
      'keywords': [
          {
              'keyword': 'crm',
              'required_keywords': ['self-hosted'],
              'excluded_keywords': ['salesforce'],
          }
      ],
      'labels': [
          {'name': 'buying intent', 'description': 'Tool recommendation threads'},
      ],
  }

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

<ResponseExample>
  ```json Metadata-only update theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Updated Reddit Watchlist",
    "fetchFreqInHours": 12,
    "disable": false,
    "updated": true,
    "message": "Watchlist updated successfully"
  }
  ```

  ```json Keywords + labels update theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "updated": true,
    "message": "Watchlist updated successfully",
    "keywords": ["crm", "indie hacker"],
    "results": [
      {
        "success": true,
        "keyword": "crm",
        "keyword_id": "660e8400-e29b-41d4-a716-446655440001"
      },
      {
        "success": true,
        "keyword": "indie hacker",
        "keyword_id": "660e8400-e29b-41d4-a716-446655440002"
      }
    ],
    "labels": [
      { "key": "buying intent", "description": "Tool recommendation threads" },
      { "key": "founder-post", "description": "Posts from indie founders" }
    ]
  }
  ```
</ResponseExample>

## Response Fields

<ResponseField name="id" type="string">
  Watchlist ID that was updated.
</ResponseField>

<ResponseField name="name" type="string">
  Updated watchlist name (only present when `name` was in the request).
</ResponseField>

<ResponseField name="fetchFreqInHours" type="number">
  Updated fetch frequency (only present when `fetchFreqInHours` was in the request).
</ResponseField>

<ResponseField name="disable" type="boolean">
  Current active/disabled status (only present when `disable` was in the request).
</ResponseField>

<ResponseField name="keywords" type="array">
  Array of primary keywords after the update (only present when `keywords` was in the request).
</ResponseField>

<ResponseField name="results" type="array">
  Per-keyword creation result (only present when `keywords` was in the request). Each entry has `success`, `keyword`, and either `keyword_id` or `error`.
</ResponseField>

<ResponseField name="labels" type="array">
  Labels persisted on the watchlist (only present when `labels` or `keywords` was in the request).
</ResponseField>

<ResponseField name="updated" type="boolean">
  Whether the update was successful.
</ResponseField>

<ResponseField name="message" type="string">
  Success message.
</ResponseField>

## Error Responses

| Status Code | Error Message                                                             | Description                                                                                                              |
| ----------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| 400         | Missing required parameter: id                                            | Watchlist ID is required                                                                                                 |
| 400         | No valid update fields provided                                           | Body did not include any updatable fields                                                                                |
| 400         | keywords array is required and must not be empty                          | `keywords` was passed but empty or not an array                                                                          |
| 400         | No valid keywords provided after cleaning                                 | All keywords were empty strings after normalization                                                                      |
| 400         | Invalid fetchFreqInHours. Allowed values: 1, 3, 6, 12, 24, 48, 72 (hours) | Unsupported fetch frequency                                                                                              |
| 400         | disable must be a boolean value                                           | `disable` sent as a non-boolean                                                                                          |
| 400         | Name cannot be empty                                                      | `name` was an empty or whitespace-only string                                                                            |
| 401         | Missing API Key / Invalid API Key                                         | Missing or invalid `x-api-key` header                                                                                    |
| 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. |
| 404         | Watchlist not found or access denied                                      | Watchlist does not exist, is not a Reddit list, or is not yours                                                          |

See [Error Codes](/api-reference/errors) for the full list.

## Prompt mode

Replace the prompt on an existing Reddit watchlist. OutX wipes the existing keywords and labels and regenerates them from the new prompt in the background. Use this when you want to redirect a watchlist to a different angle without recreating it.

<Note>
  If you send `prompt` together with patch fields (`name`, `keywords`, `labels`, `disable`, `fetchFreqInHours`, `slack_webhook_url`), the patch fields are silently ignored, `prompt` takes precedence. Unlike create (POST), update does not return an error when both are sent.
</Note>

### Request Body

<ParamField body="id" type="string" required>
  Watchlist ID to update.
</ParamField>

<ParamField body="prompt" type="string" required>
  New natural-language prompt. OutX regenerates keywords and labels from this, replacing the current set.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X PUT \
    "https://api.outx.ai/api-reddit-watchlist" \
    -H "Content-Type: application/json" \
    -H "x-api-key: YOUR_API_KEY" \
    -d '{
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "prompt": "Track Reddit threads about Postgres-based vector databases and indie projects building with pgvector"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.outx.ai/api-reddit-watchlist", {
    method: "PUT",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      id: "550e8400-e29b-41d4-a716-446655440000",
      prompt:
        "Track Reddit threads about Postgres-based vector databases and indie projects building with pgvector",
    }),
  });

  const result = await response.json();
  console.log(result.message);
  ```

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

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

  payload = {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "prompt": "Track Reddit threads about Postgres-based vector databases and indie projects building with pgvector",
  }

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

  result = response.json()
  print(result["message"])
  ```
</RequestExample>

<ResponseExample>
  ```json Response theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "prompt": "Track Reddit threads about Postgres-based vector databases and indie projects building with pgvector",
    "updated": true,
    "message": "Prompt updated. Keywords and labels are being regenerated in the background."
  }
  ```
</ResponseExample>

Same wipe-and-recreate semantics as a `keywords` patch: existing `keyword_tracking` rows and pending `reddit_tracking` tasks are deleted, but historical posts remain attached to the watchlist.

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="What properties can I update on a Reddit watchlist?">
    `name`, `fetchFreqInHours`, `keywords`, `labels`, `disable`, and `slack_webhook_url`, any combination. Every field except `id` is optional; unspecified fields are left unchanged.
  </Accordion>

  <Accordion title="What happens to my existing keywords when I update them?">
    When you pass a `keywords` array, the API deletes the watchlist's existing `keyword_tracking` rows and their associated `reddit_tracking` tasks, then creates new ones from your payload. The watchlist ID stays the same, and previously collected posts remain accessible via the Posts API.
  </Accordion>

  <Accordion title="Does updating a Reddit watchlist reset existing collected data?">
    No. Changing the name, fetch frequency, keywords, or labels does not delete posts that have already been collected. If you update `fetchFreqInHours`, the new interval takes effect from the next scheduled fetch cycle.
  </Accordion>

  <Accordion title="Can I update labels without changing keywords?">
    Yes. Send only `id` and `labels`. The existing keywords and their tasks are untouched.
  </Accordion>

  <Accordion title="Do new or changed labels re-label posts I already collected?">
    No. Each post is classified into a label once, when it is first enriched, so updating or adding `labels` only changes how *future* posts are classified, already-classified posts keep their tags. See [how intent labels are calculated](/api-reference/watchlist/keyword/create#how-intent-labels-are-calculated).
  </Accordion>
</AccordionGroup>
