Skip to main content
Read this once before you call anything. Most integration failures are not the wrong endpoint. They are the right endpoint called with the wrong idea of what the platform does.

A watchlist is a standing job, not a search query

OutX watches LinkedIn and Reddit for you. A watchlist is a saved monitoring job: you say what to look for, and OutX keeps collecting matching posts on a schedule (fetchFreqInHours) until you pause or delete it. You do not get results back from the call that creates a watchlist. You create the job, wait, then read its feed with GET /api-posts?watchlist_id=.... Four types, one per endpoint. Pick by what you are tracking, not by platform alone: One watchlist covers one platform. “Track this on LinkedIn and Reddit” is two create calls. Full comparison: Choose a watchlist type.

What happens after a create returns 201

The response comes back before the work is done. In order:
1

The watchlist row exists

You get id and slug immediately. The id never changes. The slug only changes if you rename the watchlist.
2

Keywords and labels are written

In prompt mode this happens in the background, seconds after the response. In keywords mode your keywords are stored during the call, and OutX fills in a missing objective or label set in the background.
3

Collection tasks start

Each keyword gets a task that runs on the fetch cycle. LinkedIn keyword watchlists also backfill recent matching posts right away, so they are usually non-empty within minutes.
4

Posts are scored and labeled (keyword and Reddit only)

On a keyword or Reddit watchlist, every collected post is scored for relevance against the watchlist’s objective, then classified into one of your intent labels. A post that has not been through this step yet has an empty tags array.People and company watchlists have no intent labels, so their posts are never classified. Their tags come back as "na" and stay that way.
An empty feed minutes after create is normal, not an error. So is a post with empty tags on a keyword or Reddit watchlist. Neither means the watchlist is broken. There, "na" in tags is the real “no match” signal and empty means “not classified yet”.On a people or company watchlist, never wait for tags. Those types have no intent labels, so every post is tagged "na" by design. Read the posts themselves.
After a prompt-mode create, poll GET on the same endpoint you created with, using the watchlist id, until keywords is no longer empty. A keyword watchlist polls /api-keyword-watchlist and a Reddit one polls /api-reddit-watchlist. People and company watchlists have no keywords and no prompt: poll /api-posts instead, or read profiles / companies on their GET ?id= response to confirm the members landed.

Prompt mode vs keywords mode

Keyword and Reddit watchlists accept two body shapes on create. Send one or the other, never both.
  • Prompt mode (recommended). Send prompt: one sentence describing what you want to see. OutX reads it into topic, audience and signal, then generates the keywords, the intent labels and the relevance objective for you. This is the path the product itself uses and the one tuned for feed quality.
  • Keywords mode. Send keywords: you supply the exact terms, with optional required_keywords and excluded_keywords per term. Use it when you already know the exact strings to match.
Prompt mode ignores the direct-mode fields. On a prompt-mode create, labels, objective, description and slack_webhook_url are not read. OutX writes the objective itself, from the prompt. Of the other three, only labels and slack_webhook_url can be set afterwards with a PUT. objective and description are accepted on a keywords-mode create only. Update accepts neither, so a prompt-built watchlist cannot be given a hand-written objective through the API.
A good prompt names three things: what the posts are about, who is posting, and what makes a post worth seeing. “Ops managers at 3PL companies complaining about their warehouse software” works. “Find me buyers” does not, and is refused (see below).

Updating a watchlist

PUT on the same URL, with id in the body. Which of two things happens depends on whether you send prompt.

Sending a new prompt regenerates the whole watchlist

This is the part agents get wrong. A PUT with a new prompt does not edit anything you name. It throws away the current keywords and labels and generates a new set from the new prompt, in the background. You cannot patch one keyword through the prompt path. To change one keyword, use the keywords field instead, which replaces the set you send (or adds to it with append: true). The response tells you only that the work started:
It carries no keywords and no labels, because they have not been generated yet. There is no completion flag to poll. The old keywords stay in place while the new set is generated, so “keywords is not empty” is true the whole time and tells you nothing. The reliable check: read GET ?id=... before the PUT and keep the keyword_tracking[].id values, then poll until every id in the response is one you have not seen and the count stops changing between polls. Rows are created one at a time, so an unchanged count across two polls is what says the swap finished.
A prompt-mode update does not backfill. The new keywords start collecting on the next fetch cycle.On a LinkedIn keyword watchlist, a keywords patch does backfill recent matching posts, so patch keywords instead when you need the feed to refill immediately. Reddit watchlists never backfill, on create or on update: every Reddit feed fills from its next fetch cycle onward.

Everything else is a patch

Send only the fields you want to change: name, fetchFreqInHours, keywords, labels, slack_webhook_url, disable. Omitted fields are untouched. Sending keywords alone never overwrites labels. A paused keyword or Reddit watchlist rejects updates with 409. The one request that gets through is an explicit re-enable, { "id": "...", "disable": false } in patch mode. Prompt mode has no such exception, so re-enable in its own call, then send the new prompt. Pausing or resuming any watchlist type stops or restarts all of its collection jobs, and shows up on the type’s GET as disabled, with disabledAt carrying the timestamp on the list response.

Retrying safely

Send idempotency_key on every create. It is a string you choose, up to 128 characters, unique per logical create (a UUID is ideal). If a second request arrives with the same key within about two minutes, OutX returns the watchlist the first one made instead of creating a second one.
A deduplicated response is a 201 carrying created: false and deduplicated: true, with the existing watchlist’s id, name and slug. Treat created: false as success, not as an error.
This is best effort, not a transaction. The lookup and the insert are separate steps, so two genuinely simultaneous identical creates can still both go through. Fire retries one at a time rather than in parallel, and read created on the response rather than assuming.
OutX also dedupes without a key: a create is matched against watchlists the same team made in the last couple of minutes with the same defining fields. Keyword and Reddit creates in keywords mode go further, and return an existing watchlist of that type whose keyword set is exactly the same, at any age. That one answers 200 with created: false. Sending your own key is more predictable, so send one.

When a prompt is not good enough

Before anything is created, OutX checks the prompt. A prompt with no subject in it, a bare profile link, an unfilled [PLACEHOLDER], or something too short to build from is refused with 422 and nothing is created. The same check runs on a prompt-mode update, so a bad prompt cannot wipe a working watchlist.
When question is present, one answer is all that is missing. Relay that question to your user word for word, put their answer into the prompt, and retry. Do not guess a topic on their behalf: a guessed topic produces a confident watchlist about the wrong thing. When question is absent, rewrite the prompt using example as the shape to copy.

Checking what OutX assumed

A prompt-mode create returns two extra fields describing how your sentence was read:
  • interpretation: the slots OutX pulled out (topic, audience, signals, competitors, use_case, excluded, and refined_prompt, the prompt rewritten as one clear sentence).
  • assumed: the slot names OutX filled in by inference because your prompt did not state them.
Show refined_prompt and assumed to your user when they matter. To reject assumptions outright, send strict: true and the create fails instead of guessing: 422 prompt_not_specific_enough listing the inferred slots in missing, or 503 interpretation_unavailable if the reading itself could not run. Both leave nothing created.

Collection runs through the Chrome extension

OutX runs through the Chrome extension installed on your browser. It works in the background while you browse, and it uses your active LinkedIn session, so OutX does not take your cookies, passwords, or save any credentials. That makes the extension a hard dependency for the API, not just for the app. The extension must be installed and must have been active within the last 48 hours. Otherwise every call, on every endpoint, returns 403 Plugin installation required (the full message is on the error codes page). A 403 of that kind is not an API key problem, and nothing you change in the request will fix it. The fix is to install the extension, sign in to LinkedIn in the same browser, and keep the browser open.

Limits worth knowing before you build

  • Watchlist count is capped by plan, and all four types count against the same cap. A create over the cap returns 402 naming your limit. Check remaining quota first with GET /api-team.
  • Labels are forward only. A post is classified once, when it is first enriched. Changing labels changes how future posts are classified and leaves already-collected posts with the tags they have.
  • Each endpoint only sees its own type. Asking /api-keyword-watchlist for a Reddit watchlist’s ID returns 404.
  • There is no sentiment field. Model sentiment as an intent label if you need it.

Next steps

Choose a watchlist type

The four types side by side, with a task-to-endpoint map

Quickstart

Key to first collected posts, end to end

Intent labels

How posts get classified and what default labels do

Error codes

Every status the API returns and how to recover