Create watch

Save a watch so new matching articles surface later. Keyword watches (default, all plans) match the query as an exact phrase; semantic watches match by meaning (Max only). Optionally scope to one feed or folder, and deliver by email or webhook on a cadence. Returns the created watch.

post/create_watch

Request

  • Base URL: https://newsmind.app/api/v1
  • URL: https://newsmind.app/api/v1/create_watch
  • Auth: OAuth 2 (authorization code, authorization URL https://newsmind.app/oauth/authorize, token URL https://newsmind.app/oauth/token, scopes: mcp)

Request body

querystring required

What to watch for. For keyword watches: an exact phrase — words must appear adjacent and in order, so write it like a headline ('OLED iPad mini', not 'iPad mini OLED'). For semantic watches: a natural phrase describing the topic/product (order-insensitive).

labelstring

Optional display name (e.g. 'M5 Mac mini'). Returned as-is by list_watches, watch_summaries and matched_watches - null when unset, with no fallback there. Only the email digest substitutes the query when the label is empty.

kind'keyword' | 'semantic'

keyword (default, all plans) or semantic (Max only — matches by meaning). Semantic on a non-Max account returns max_required.

feed_idinteger

Optional: limit to one feed. Omit for all subscriptions.

folderstring

Optional: limit to feeds in this subscription folder. Omit for all subscriptions.

thresholdnumber

Semantic only: cosine similarity cutoff in (0,1]. Any value is settable — this is a dial, not a set of presets. Calibration from real data: below ~0.45 is effectively unfiltered (it sits under the median similarity of arbitrary articles and will match thousands); 0.55-0.60 is on-topic; above 0.70 is near-exact and starts missing paraphrases. The useful band is narrow and near the top. Default 0.55. The response includes threshold_preview — how many of this watch's matches each stricter cutoff would leave — so pick the next value from that rather than guessing.

delivery'in_session' | 'email' | 'webhook'

Where matches are delivered. in_session (default) = retrieved when you call get_watch_matches or get_new_articles. email = digest to the account email. webhook = POST to webhook_url. email and webhook default to a daily cadence when none is passed.

cadence'realtime' | 'weekdays' | 'daily' | 'weekly'

For email/webhook delivery: how often to send. weekdays = daily but Monday-Friday only (weekend matches ride Monday's digest). Defaults to daily when delivery is out-of-band.

delivery_hourinteger

Daily/weekly email or webhook delivery: hour of day to send, 0-23, in the account's timezone ('email me daily at 7am' → 7). Default 8 (08:00).

delivery_day'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday'

Weekly cadence only: weekday to send ('weekly on friday'). Default monday.

webhook_urlstring

Required when delivery='webhook': an https:// endpoint we POST match batches to. Must be a public host — loopback, private and link-local addresses are rejected.

require_termsstring[]

Words an article must ALSO carry to match (max 12). ANY one is enough, not all - ['missing','Columbus','Ohio State'] keeps anything mentioning any of them. Use this to disambiguate a name that points at more than one person or thing: a watch on 'Brian Shaffer' with require_terms ['missing'] keeps the missing-persons coverage and drops the baseball player's stats page and two unrelated obituaries. DO NOT append the word to query instead - the query is matched as an exact phrase, so 'Brian Shaffer missing' matches nothing at all. Changing this rebuilds the match set.

exclude_termsstring[]

Words that DEMOTE a match rather than dropping it (max 12). Matches still appear, sorted last and tagged user_excluded, so an over-broad guess is recoverable. Prefer require_terms when you know what you DO want.

Response

Success

watch_idinteger required
querystring required
labelstring nullable

Optional human-readable name. Returned as-is and null when unset; only the email digest substitutes the query.

feed_idinteger nullable

Optional scope to one feed.

folderstring nullable

Optional scope to a subscription folder.

kind'keyword' | 'semantic' required
thresholdnumber nullable

Semantic only: cosine similarity cutoff.

activeboolean required
delivery'in_session' | 'email' | 'webhook' required
cadence'realtime' | 'weekdays' | 'daily' | 'weekly' nullable
require_termsstring[] nullable

issue #23: OR-list an article must also carry. null = no filter.

exclude_termsstring[] nullable

issue #23: OR-list that demotes a match at read time. Never deletes.

delivery_hourinteger nullable

Digest delivery hour in the account's timezone; null = default 08:00.

delivery_daystring nullable

Weekly digests: weekday name; null = default monday.

webhook_urlstring nullable
created_atstring date-time required
backfilled_matchesinteger

create: in-window articles that already matched.

match_sourcesstring[]

create: publishers this watch already matched. Unrelated publishers suggest the query is ambiguous.

threshold_previewobject

Semantic only: cutoff -> surviving match count, for picking a stricter threshold from data.

rebackfilled_matchesinteger

update: match count after an edit that rebuilt the set.

rebackfilled_because'query' | 'threshold' | 'scope' | 'require_terms'

update: which edit rebuilt the match set.

zeroed_by'query' | 'threshold' | 'scope' | 'require_terms'

update: present when the edit emptied a watch that previously had matches - usually an over-narrow edit.

cadence_inertboolean

update: a cadence was set on an in_session watch, where it schedules nothing.

settled_backloginteger

update: pending matches settled rather than emailed when delivery is sped up (in_session to email, or to a faster cadence), so the first digest is not the slower setting's backlog. Still readable via get_watch_matches.

settled_backlog_messagestring

update: accompanies settled_backlog - what was dropped from email and where it is still readable.

okboolean
messagestring
errorstring

Set instead of a watch when the call was refused: max_required (semantic on a non-Max plan), invalid_webhook_url (not https, or a loopback/private/link-local host), watch_limit_reached, embedding_failed.

Changes

No recorded changes to this operation across all 1 revision of this API.