Skip to main content
A Watch polls a Source on a fixed interval, compares results to the previous snapshot, and emits webhook events when matches change. See Webhooks for payload shape, signatures, and event types. webhook_url is optional. Omit it and the watch still polls and records every match — read them with GET /v1/{source}/watches/{id}/events, which is free. See Reading matches without a webhook.

Lifecycle

Day-one backfill

A new watch starts empty: it emits nothing until its first tick finds something the second tick has not already seen. Pass backfill: true on create and it runs one immediate search and stores the results as its starting history, so GET /v1/{source}/watches/{id}/events answers with content straight away.
Three things are worth knowing before you use it. It costs one tick, at this Source’s rate (see Billing) — it is a real search of a real upstream, charged like any other poll. It notifies nobody. Seeded events fire no webhook. A backfill is context, not news, and a create that immediately POSTed fifty old items to your endpoint is how an integration gets switched off. Read them with the events endpoint instead. It runs just after the create returns. POST answers 201 with the watch as soon as the backfill is queued, rather than blocking on an upstream search — so the events appear a moment later, not in the response body. Events that came from a backfill carry "seeded": true. Everything the watch catches on its own ticks from then on is a normal event, delivered normally: the first scheduled tick compares against what the backfill saw, so nothing is emitted twice. The same knob exists at Query scale: backfill: true on POST /v1/queries runs one such search per enabled Source, charged one tick each at that Source’s rate. See History & backfill for what a Query starts with.

Match mode

Search platforms do not all match the way you would expect. Algolia searches Hacker News authors with typo-and-prefix tolerance, Reddit’s search is fuzzy, and YouTube ranks by relevance rather than text — so a watch on a distinctive brand name can return items that do not carry it anywhere. match is an optional body field on watch creation for the six Sources that take a query — X, Reddit, Youtube, Bluesky, Hacker News and RSS. It says how strictly a result must carry your query:
Filtering happens before an item is stored, so it applies to every surface at once: webhook deliveries, the events endpoint, and everything derived from them.
Under word and contains, an item whose text misses is still kept when one of its identities — the author’s handle, the subreddit, the channel — is exactly your query. A post by @nephia is not noise, whatever it happens to say.
Two things match does not touch. A leg with no query — a Youtube channel, a Bluesky author, an RSS feed_url, a Reddit subreddit on its own — has no term to be held to, so nothing is filtered. And Vinted watches do not take the field at all: catalog search is not a text match, and a listing titled “501” is a correct hit for “jean levis 501”. One leg runs the other way. A Reddit Watch in types: "comments" reads a listing, not a search, so a query on it is a filter we apply rather than a search the platform ran — and it applies under every match mode, platform included. Setting word or contains there tightens our filter; leaving match unset does not turn it off. A Watch in types: "all" runs both ways at once: its posts half is searched by Reddit, its comments half is filtered by us, under one match. That asymmetry is the platform’s, not a setting — match: "word" is what tightens both. The pull endpoints (GET /v1/{source}/search and friends) are unaffected — they return what the platform returned, as they always have.

Per-Source limits

These are the Source limits, not what your Account can actually do. Your plan applies its own floor and cap on top, and the stricter of the two wins:
  • Interval — effective minimum is max(plan minimum, source minimum). A Free account cannot create a 15s Vinted watch; its floor is 3600s.
  • Cap — the plan caps active watches account-wide across all Sources (1 on Free), checked before the per-Source numbers above.
See Limits — Watch entitlements for the per-plan figures. Either rejection is 400 with code VALIDATION.

Billing

Each poll tick charges 4 credits for X, Reddit, and Vinted; 5 credits for Youtube; 1 credit for Bluesky, Hacker News and RSS — before the poll runs. AI answers charges 100 credits per engine per run, after each engine answers, and an engine that errors is not charged. See Credits — Watch billing. When credits are insufficient, the watch is auto-paused with pausedReason: insufficient_credits. Polling does not resume automatically — call POST /v1/{source}/watches/{id}/resume after topping up. A watch created with backfill: true charges one extra tick at the same rate, for the one immediate search it runs. A watch created with an agent step (ai on the create body) charges that step on top of the tick — 1 credit per 25 events read — and its delivery waits for the reading, up to 120 seconds. The event is delivered either way: see Webhooks — Agent step on a watch.

Pause reasons

pausedReason tells you who stopped a watch and what unblocks it. resume re-checks your plan cap and interval, so it fails with 400 VALIDATION while the watch still exceeds them.

Activity log

GET /v1/{source}/watches/{id}/activity returns operational events for a watch: poll.completed, poll.failed, webhook.delivered, webhook.failed. Each entry includes creditsCharged, eventsEmitted, and delivery metadata where applicable.

Reading matches without a webhook

webhook_url is optional on create. A watch without one polls on the same interval, costs the same per tick, and records every match — it just does not push. Read what it caught:
This endpoint is free and works the same on every Source. It is also how you catch up after your endpoint was down — see Webhooks — Replay events.

Event types

See Webhooks — Event types for the canonical list.