Snag Watcher Docs

API reference

Errors

JSON
{
  "error": { "code": "burst_needs_date", "message": "A burst near release_date needs something that gives that date: a release_date condition or attribute, or a site that reports it.", "field": "schedule.burst.near" },
  "errors": [{ "code": "burst_needs_date", "message": "...", "field": "schedule.burst.near" }]
}

error is the first problem. On a 422, errors lists all of them, so you can fix a request in one pass. field is the path in your body. A 422 can also carry a suggestion, a corrected request for you to check and send. See Suggestions.

Status codes

Statuscode
400bad_jsonThe body isn't JSON
401unauthorizedMissing, unknown or revoked key
403limit_reached1,000 active or paused watchers
404not_foundNo such watcher, or not yours
409watcher_finishedResuming a matched or expired watcher
409idempotency_conflictSame Idempotency-Key, different body
422see belowA rule failed
429rate_limitedOver 120 requests a minute. See Retry-After
500internalOur fault

Validation codes

Shape

code
invalid_requestA field is missing, misspelled or the wrong type
value_missingThe op needs a value
value_not_listin and not_in need a list
value_not_numberprice, price_drop and quantity need a number, "$20" or "10%"
value_not_dateDates look like 2026-12-15
value_unknownNot a status we know, for availability or release_status

Target and sites

code
match_query_shapeurl needs a full link on a listed site; sku needs an identifier
exact_needs_versionexact needs a version in the name; use line to follow every version
version_needs_lineversion conditions need match: line or category
site_unknownWe can't read that site
site_unavailableWe can read that site, but not on this server right now
site_cant_matchThat site doesn't support the match mode
site_not_reviewedWe don't support that site yet. Sites
site_terms_not_acceptedSet fetch.accept_site_terms for this site
recipe_not_learnedAt create: we couldn't learn how to read that page. message says why; field is the where.sites entry
recipe_input_missingThe page needs a value the watcher didn't give. message names it, such as location.zip
llm_budget_reachedYour account's monthly LLM budget is spent, so no new page can be learned until next month
recipe_deadWe gave up on that page after 3 relearns found nothing. Preview it again to retry
bad_stepsA browser step, locale, timezone, cookie or location can't be used. message says which
steps_submit_refusedA step would send a contact, sign-up, registration, subscription, checkout or application form, or post a form after filling more than one field, on a site we haven't reviewed. Search and lookup steps are fine. message says which step
field_unsupportedNone of the sites gives that field
target_fixedtarget can't be updated

Conditions

code
compare_to_needs_numericcompare_to works on numbers (price, quantity, a numeric attribute), or any field with changed; price_drop, price_change and price_move need it
percent_needs_compareA percentage needs compare_to
window_needs_durationcompare_to: window needs window, like "10m"
window_needs_comparewindow only works with compare_to: window
min_n_needs_nrequire: min_n needs n, no more than the values listed
over_needs_valuesover needs values: a size list, a date range or a listing
over_too_manyAt most 20 values under over
same_seller_needs_sitessame: seller needs two sites, or a site with several sellers
list_change_needs_itemsadded and removed read the whole list: use field items
items_needs_list_opField items takes op added or removed
list_change_aloneadded and removed compare with the last run by themselves; leave out compare_to, window and over
judge_needs_rulejudge needs the rule as a sentence in value, up to 300 characters
judge_alonejudge compares with the last run by itself; leave out compare_to, window and over
item_needs_judgeField item (the whole result) only works with op judge
judge_too_manyAt most 3 judged conditions on one watcher
judge_unavailableThis server has no LLM set up, so it can't check judged conditions

Location and schedule

code
zip_needs_usZIPs are US only
radius_needs_zipA radius needs a zip
radius_unreadableUse "25mi" or "40km"
currency_unsupportedUSD only
start_at_unreadablestart_at isn't a date
start_after_untilstart_at must be before until
until_unreadableA date, "+30d", "after_first_match" or "never"
until_in_pastuntil already passed
until_too_farAt most a year
burst_needs_dateA burst near a date needs something that gives that date
burst_needs_timeA burst needs at or near, not both
burst_at_unreadableburst.at needs a datetime
burst_faster_than_everyburst.every must be shorter than every

Notify and follow-ups

code
webhook_channel_without_configchannels has webhook but there's no notify.webhook
webhook_config_without_channelnotify.webhook is set but channels doesn't have webhook
webhook_needs_httpsWebhook URLs use https
channel_needs_sessionAPI keys use webhook
then_nestedA then can't hold another then
then_needs_single_matchthen needs until: after_first_match or aggregate: first

Check issues

A check that ran still lists issues on its snapshot when something about the read is worth knowing.

A check is blocked on a 429, on a 403 or 429 with x-ratelimit-remaining: 0 (GitHub), and on a 400 or 403 whose body says it's a rate limit (Stack Exchange's throttle_violation). retryAfterSeconds comes from Retry-After, then the rate limit's reset time, then an "in N seconds" in the site's message. On readers that ask for it (Jane App), a redirect that leaves the clinic's own address is not_found. Redirects are followed one hop at a time, at most 5, and robots.txt is checked on each host.

The common issues:

Issue
robots_disallowedrobots.txt disallows the page, or the site needs a terms review
recipe_missingNo recipe has been learned for this page. Preview the watcher, or create it again
recipe_learnedA recipe was learned on this check
recipe_learn_failedWe couldn't learn how to read the page
recipe_nothing_hereThe page has nothing like the target (a home page, an error page)
recipe_brokenThe recipe stopped finding its items. After 3 in a row it's learned again
selector_not_foundA page-change selector or list matched nothing. On the first read the check fails and the detail names up to three selectors that do match; after the selector has matched once, a miss is reported with the check still ok
region_emptyThe part of the page we read had no text
platform_unknownA store that isn't Shopify, WooCommerce, Squarespace, BigCommerce or Magento, on a line or category watch
not_shopify, not_woocommerce, not_squarespace, not_bigcommerce, not_magentoThe store isn't on that platform
no_product_cardsA store page from the right platform, but with no products we could read
listing_partly_read, variants_partly_readSome items or options couldn't be read
list_truncated, range_truncated, range_cappedMore results or days than one check reads; the rest are left out
time_zone_unknownThe site gave times without a zone we could work out
ticket_classes_unavailableEventbrite's ticket classes couldn't be read; the event itself was
csrf_token_missingOpenTable didn't hand out the token its availability call needs
unexpected_answerThe site's API answered in a shape we don't know, so nothing was read
empty_as_400, empty_as_404NHTSA or openFDA said "no results" with an error status
api_key_refusedThe site refused the server's key for it, or answered 400 saying the key is invalid or missing (NCBI, Stack Exchange). The detail has the site's own message
private_addressThe address resolves to a private or local network (localhost, 10.x, 192.168.x, 169.254.169.254, *.railway.internal), which the watcher doesn't fetch. Use a public address
usage_limitYour account used its daily browser runs with steps (200) or captcha solves (20). The detail gives the reset time, 00:00 UTC. The check is failed, not blocked, so it doesn't count toward a blocked event
captcha_not_allowedThe page showed a captcha and this server only solves them on reviewed sites
site_not_reviewedThe site waits on a terms review, so nothing was fetched
partial_data, partial_resultsThe site's answer covers only part of what it lists (a menu missing its group classes, OSV's first page)
query_refused, search_refusedThe open-data portal or USAspending refused the filter in attributes (a bad where, an unknown agency name)
radius_checked_after_fetchThe dataset keeps coordinates as text, so only the newest rows read were checked against the radius
ticket_types_not_readDICE: the event's price and status were read, its ticket types weren't
no_event_dateTito: the event's calendar file couldn't be read, so results have no date
list_emptyA page-change list that matched before matched nothing this time
format_changedThe link answered a PDF last time and a web page now, or the other way round. The result keeps its key, so it reads as a change
rdap_not_registrableRDAP: the name is under a registered domain (www.example.com), so it can't be registered itself. The detail names the domain to watch
rdap_unsupported_tldRDAP: IANA lists no RDAP server for that ending (.de, .io)
impact_unknownRoad work: closed_only is set, but the feed marks every event's impact unknown (WSDOT), so closures can't be picked out
feed_staleRoad work: the feed hasn't been updated in a long time
hours_not_readCivicRec facilities: the day is read, but not the hours
time_zone_defaultSimplePractice: the days were picked in New York time because time_zone wasn't set
price_missingA rental unit with no rent, or a rent of $0
filings_not_found, officers_not_foundCompanies House: the company has no filings or no officers on record; the company itself was read
nothing_listedMagic Eden: no listings and no floor. A mistyped symbol reads the same way, so check the symbol
seo_not_for_pdf, seo_not_for_listseo: true reads a page's tags, so it does nothing on a PDF or a list
summary_unavailablesummarize: true, but the server has no LLM or the summary failed. It's tried again at most once an hour
step_failedA browser step couldn't be done (nothing matched it, or it timed out). The detail names the step
not_a_pageThe link is a file download, not a page; watch it without browser: true
recipe_review_pendingA reader that waits on a terms review claims this page, so no recipe reads it either
recipe_input_missingThe recipe needs a value the watcher doesn't give, like location.zip
recipe_llm_budgetThe page needed relearning, but the LLM budget is spent
recipe_deadThe page was given up on after 3 relearns found nothing. The stored recipe still runs; preview again to retry learning