Skip to main content
Modify an existing keyword 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 at the bottom of this page).

Request Body (patch mode)

id
string
required
Watchlist ID to update.
name
string
New watchlist name.
fetchFreqInHours
number
New fetch frequency. Allowed values: 1, 3, 6, 12, 24, 48, 72.
keywords
array
Patch the tracked keywords on the watchlist. Accepts the same shape as the Create endpoint, 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:
["hiring", "remote work"]
Advanced format:
[
  {
    "keyword": "CTO",
    "required_keywords": ["hiring", "founder", "vp"],
    "excluded_keywords": ["recruiter", "spam"],
    "include_all_required": false
  }
]
By default this replaces the set: the watchlist’s existing keywords and associated keyword_tracking tasks are deleted and recreated from the new list (set append: true to add instead). Newly created keywords backfill recent matching posts from the existing pool in the background. Updating keywords does not change existing labels. Omit the field to leave keywords untouched.
append
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.
labels
array
Replace the custom labels on the watchlist. Same shape as Create.
[
  { "name": "hiring", "description": "Job postings" },
  { "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.
disable
boolean
Set to true to pause tracking, false to resume.
slack_webhook_url
string | null
Update or clear the Slack webhook URL for this watchlist. Pass null to clear.

Semantics

  • Keyword replacement is wipe-and-recreate (default). Existing keyword_tracking rows and their keyword_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.
  • New keywords backfill the existing pool. Whether replacing or appending, each newly created keyword backfills recent matching posts from OutX’s existing pool in the background, so it does not have to wait for the next live fetch to show results.
  • Labels are preserved unless you send labels. Updating keywords alone never overwrites existing labels. To change labels, pass a labels array.
  • Only keyword_tracking tasks are touched. Any other task types on the same watchlist are left alone.
  • Partial updates are safe. Sending only { "id": "...", "name": "new name" } changes just the name; keywords, labels, and tasks are untouched.
curl -X PUT \
  "https://api.outx.ai/api-keyword-watchlist" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Updated Watchlist Name",
    "fetchFreqInHours": 24
  }'
curl -X PUT \
  "https://api.outx.ai/api-keyword-watchlist" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "keywords": [
      {
        "keyword": "CTO",
        "required_keywords": ["hiring"],
        "excluded_keywords": ["recruiter", "spam"]
      },
      "founder"
    ],
    "labels": [
      { "name": "hiring", "description": "Job postings" },
      { "name": "founder-post", "description": "Posts from founders" }
    ]
  }'
curl -X PUT \
  "https://api.outx.ai/api-keyword-watchlist" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "disable": true
  }'
const response = await fetch("https://api.outx.ai/api-keyword-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: "CTO",
        required_keywords: ["hiring"],
        excluded_keywords: ["recruiter", "spam"],
      },
    ],
    labels: [{ name: "hiring", description: "Job postings" }],
  }),
});
import requests

url = 'https://api.outx.ai/api-keyword-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': 'CTO',
            'required_keywords': ['hiring'],
            'excluded_keywords': ['recruiter', 'spam'],
        }
    ],
    'labels': [
        {'name': 'hiring', 'description': 'Job postings'},
    ],
}

response = requests.put(url, headers=headers, json=payload)
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Updated Watchlist Name",
  "fetchFreqInHours": 24,
  "disable": false,
  "updated": true,
  "message": "Watchlist updated successfully"
}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "updated": true,
  "message": "Watchlist updated successfully",
  "keywords": ["cto", "founder"],
  "results": [
    {
      "success": true,
      "keyword": "cto",
      "keyword_id": "660e8400-e29b-41d4-a716-446655440001"
    },
    {
      "success": true,
      "keyword": "founder",
      "keyword_id": "660e8400-e29b-41d4-a716-446655440002"
    }
  ],
  "labels": [
    { "key": "hiring", "description": "Job postings" },
    { "key": "founder-post", "description": "Posts from founders" }
  ]
}

Response Fields

id
string
Watchlist ID that was updated.
name
string
Updated watchlist name (only present when name was in the request).
fetchFreqInHours
number
Updated fetch frequency (only present when fetchFreqInHours was in the request).
disable
boolean
Current active/disabled status (only present when disable was in the request).
keywords
array
Array of primary keywords after the update (only present when keywords was in the request).
results
array
Per-keyword creation result (only present when keywords was in the request). Each entry has success, keyword, and either keyword_id or error.
labels
array
Labels persisted on the watchlist (only present when labels or keywords was in the request).
updated
boolean
Whether the update was successful.
message
string
Success message.

Error Responses

Status CodeError MessageDescription
400Missing required parameter: idWatchlist ID is required
400No valid update fields providedBody didn’t include any updatable fields
400keywords array is required and must not be emptykeywords was passed but empty or not an array
400No valid keywords provided after cleaningAll keywords were empty strings after normalization
400Invalid fetchFreqInHours. Allowed values: 1, 3, 6, 12, 24, 48, 72 (hours)Unsupported fetch frequency
400disable must be a boolean valuedisable sent as a non-boolean
400Name cannot be emptyname was an empty or whitespace-only string
401Missing API Key / Invalid API KeyMissing or invalid x-api-key header
404Watchlist not found or access deniedWatchlist doesn’t exist, isn’t a keyword list, or isn’t yours
See Error Codes for the full list, including 403 (plugin not active) and 405 (wrong HTTP method).

Prompt mode

Replace the prompt on an existing 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.

Request Body

id
string
required
Watchlist ID to update.
prompt
string
required
New natural-language prompt. OutX will regenerate keywords and labels from this, replacing the current set.
curl -X PUT \
  "https://api.outx.ai/api-keyword-watchlist" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "prompt": "Track AI CRM tools, Salesforce alternatives, and enterprise sales automation"
  }'
const response = await fetch("https://api.outx.ai/api-keyword-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 AI CRM tools, Salesforce alternatives, and enterprise sales automation",
  }),
});

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

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

payload = {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "prompt": "Track AI CRM tools, Salesforce alternatives, and enterprise sales automation",
}

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

result = response.json()
print(result["message"])
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "prompt": "Track AI CRM tools, Salesforce alternatives, and enterprise sales automation",
  "updated": true,
  "message": "Prompt updated. Keywords and labels are being regenerated in the background."
}
Same wipe-and-recreate semantics as a keywords patch: existing keyword_tracking rows and pending tasks are deleted, but historical posts remain attached to the watchlist.

Frequently Asked Questions

You can update name, fetchFreqInHours, keywords, labels, disable, and slack_webhook_url, any combination. Every field except id is optional; unspecified fields are left unchanged.
When you pass a keywords array, the API deletes the watchlist’s existing keyword_tracking rows and their associated keyword_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.
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.
Yes. Send only id and labels. The existing keywords and their tasks are untouched.
No. Each post is classified into a label once, when it is first enriched. Updating or adding labels changes how future posts are classified but does not re-label posts that were already collected, they keep the tags they had. To re-classify recent posts against the new labels, those posts must be explicitly re-enriched (OutX re-runs classification over roughly the last 30 days). See How intent labels are calculated.
To add keywords without disturbing the rest, send just the new keywords with append: true, only the ones not already on the list (case-insensitive) are created. To remove a keyword, fetch the current set with GET /api-keyword-watchlist?id=…, then send the full desired list back without append (default replace).