API reference
Create a watcher
POST /v1/watchers
Creates a watcher and schedules its first run. Returns the watcher object and, when notify has a webhook, webhook_secret.
Body
| Field | Type | |
|---|---|---|
target | object | Required. What to watch. Matching products |
conditions | object | Required. { "all": [...] } or { "any": [...] }, 1 to 10. Conditions |
where | object | Required. sites (1 to 10) and aggregate |
schedule | object | Required. every and until, optionally start_at and burst. Schedules |
notify | object | Where results go. Webhooks |
location | object | country, zip, radius, currency |
fetch | object | proxy and accept_site_terms |
then | object | A follow-up watcher. Follow-up watchers |
target
| Field | Type | |
|---|---|---|
query | string | Required. A URL, an identifier or words, by match |
match | string | Required. url, sku, exact, line, category, listing |
attributes | object | Variant filters, such as { "size": 10, "color": "Black" }. A list means any of them |
exclude | string[] | Phrases that drop a product, as whole words |
Condition
| Field | Type | |
|---|---|---|
field | string | Required. price, price_drop, availability, quantity, version, release_status, release_date, date, opens_at, seller, or an attribute |
op | string | Required. = != < <= > >= in not_in exists changed |
value | any | A number, "$19.99", "10%", a date, a status, or a list for in |
compare_to | string | first_snapshot or last_snapshot |
over | object | key (sizes, dates, items), require (all, any, min_n), n, same (site, seller) |
where
| Field | Type | |
|---|---|---|
sites | string[] | Required. Hosts, repos or URLs |
aggregate | string | each (default), best, first, dedupe |
schedule
| Field | Type | |
|---|---|---|
every | string | Required. "15m", "1h", "1d" |
until | string | Required. A date, "+30d", "after_first_match" or "never" |
start_at | string | First run, ISO 8601. UTC without an offset |
burst | object | near (release_date, opens_at), window, every |
notify
| Field | Type | |
|---|---|---|
channels | string[] | Required. ["webhook"] with an API key |
webhook | object | url (https) and events: matched, changed, field_found, blocked, clamped |
repeat | string | once, on_change (default), every_match |
cooldown | string | Shortest gap between sends. Default "6h" |
location and fetch
| Field | Type | |
|---|---|---|
location.zip | string | US ZIP. With radius, keeps places within that distance |
location.radius | string | "25mi" or "40km" |
location.country | string | US |
location.currency | string | USD |
fetch.proxy | string | auto (default) or off |
fetch.accept_site_terms | boolean | Required for sites whose robots.txt restricts the data. Sites |
Request
curl https://watcher-api-staging.manwhas.shop/v1/watchers \
-H "Authorization: Bearer $SNAG_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: wool-runner-10" \
-d '{
"target": { "query": "https://www.allbirds.com/products/mens-wool-runners", "match": "url", "attributes": { "size": 10 } },
"conditions": { "all": [{ "field": "availability", "op": "=", "value": "back_in_stock" }] },
"where": { "sites": ["allbirds.com"] },
"schedule": { "every": "1h", "until": "+30d" },
"notify": { "channels": ["webhook"], "webhook": { "url": "https://you.example/snag", "events": ["matched", "blocked"] } }
}'const watcher = await fetch('https://watcher-api-staging.manwhas.shop/v1/watchers', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SNAG_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'wool-runner-10',
},
body: JSON.stringify({
target: { query: 'https://www.allbirds.com/products/mens-wool-runners', match: 'url', attributes: { size: 10 } },
conditions: { all: [{ field: 'availability', op: '=', value: 'back_in_stock' }] },
where: { sites: ['allbirds.com'] },
schedule: { every: '1h', until: '+30d' },
notify: { channels: ['webhook'], webhook: { url: 'https://you.example/snag', events: ['matched', 'blocked'] } },
}),
}).then((response) => response.json());import os, requests
watcher = requests.post(
"https://watcher-api-staging.manwhas.shop/v1/watchers",
headers={"Authorization": f"Bearer {os.environ['SNAG_KEY']}", "Idempotency-Key": "wool-runner-10"},
json={
"target": {"query": "https://www.allbirds.com/products/mens-wool-runners", "match": "url", "attributes": {"size": 10}},
"conditions": {"all": [{"field": "availability", "op": "=", "value": "back_in_stock"}]},
"where": {"sites": ["allbirds.com"]},
"schedule": {"every": "1h", "until": "+30d"},
"notify": {"channels": ["webhook"], "webhook": {"url": "https://you.example/snag", "events": ["matched", "blocked"]}},
},
).json()
Response
201 Created
{
"watcher_id": "wch_dhjqcvaqnhrchsnv7gtc",
"kind": "availability",
"status": "active",
"mode": "test",
"parent_id": null,
"request": { "target": { "query": "https://www.allbirds.com/products/mens-wool-runners", "match": "url", "attributes": { "size": 10 } } },
"schedule": { "every": "1h", "next_run_at": "2026-11-04T19:38:44.390Z", "until": "2026-12-04T19:38:43.902Z" },
"clamped": [],
"warnings": [],
"created_at": "2026-11-04T19:38:43.902Z",
"last_run_at": null,
"first_match_at": null,
"last_snapshot": null,
"events": [],
"webhook_secret": "whsec_Qm9vcGllcy1hcmUtbm90LWEta2V5"
}request is shortened here; it holds the full body you sent. A broken rule returns 422 with every error at once. See Errors.