Watch the pricing page
An agent can GET a page once. What it can't do is keep watching one for
months and wake up only when something changes. A watch is that missing half:
you hand us a source and a rule for what counts as interesting, we poll it
politely and diff each result, and we fire a webhook the moment your rule matches.
This rung introduces the fourth primitive — reacting to the world changing,
rather than to a clock or a person — plus match rules and the change history that
lets you tune them.
The story
A competitive-intel agent needs to know when a rival's pricing page changes — but
it can't sit and refresh the page every few minutes forever. So it registers a
watch on the pricing URL, scoped to the price element and a rule that fires only
when a currency figure appears, polling every fifteen minutes. When the price
moves, a watch.changed webhook wakes the agent with the new excerpt.
Solve it
Go to Watches → New watch. Pick the url source type, paste the pricing
page URL, add a CSS selector to scope the diff to the price element, choose a
match rule, and set a poll interval. On save you land on the watch's detail page,
where its change history will accumulate.
POST /v1/watches/ with the url, an optional css_selector, a match_rule, a
webhook_url, and a poll_interval (an ISO-8601 duration, clamped up to your
tier's floor).
curl https://aigears.example.com/v1/watches/ \
-H "Authorization: Bearer aigears_live_..." \
-H "Idempotency-Key: rival-pricing-watch-1" \
-H "Content-Type: application/json" \
-d '{
"source_type": "url",
"url": "https://rival.example.com/pricing",
"css_selector": "#price",
"match_rule": {"kind": "regex", "pattern": "\\$[0-9]+"},
"webhook_url": "https://hooks.example.com/aigears",
"poll_interval": "PT15M"
}'
The runnable version — create, inspect, pause/resume, delete — is
examples/python/watches_agent.py
and
examples/typescript/watchesAgent.ts:
watch = create_watch(
client,
url="https://rival.example.com/pricing",
webhook_url=webhook_url,
poll_interval="PT15M",
css_selector="#price",
)
"Watch rival.example.com/pricing and tell me when the price changes — check every 15 minutes."
watch_create(
source_type="url",
url="https://rival.example.com/pricing",
css_selector="#price",
match_rule={"kind": "regex", "pattern": "\\$[0-9]+"},
webhook_url="https://hooks.example.com/aigears",
poll_interval="PT15M",
)
→ { "id": "01J9Z8XKQR...", "status": "active",
"poll_interval_seconds": 900 }
Reading a change notification
When a poll finds a change your rule matched, we fire one watch.changed
webhook. Its payload is new-only and bounded: we store only a hash of each
source, so the old value literally doesn't exist for us to send, and the new
value is a capped excerpt (the changed region plus a bounded prefix), never
the whole page.
{
"event_type": "watch.changed",
"data": {
"watch_id": "01J9Z8XKQR...",
"source_type": "url",
"content_hash": "9f2b...",
"excerpt": "Pro plan — $79 / month",
"match": {"kind": "regex", "pattern": "\\$[0-9]+"}
}
}
The agent reads the excerpt and reacts. If it needs to diff against the previous price, it keeps that from the last event it received. For receiving and verifying the webhook, see Receiving webhooks.
Tuning the match rule
A watch records every change it detects — even ones your match_rule didn't
match. Only matched changes fire a webhook, but the unmatched ones are still
logged, so the history can tell you a source "changed 12 times, matched twice".
That gap is your tuning signal: read the history with watch_history(watch_id=...)
(the per-change log lives on MCP and the dashboard, not REST in v1), see the
changed-but-not-matched rows, and widen a rule that's too narrow — or tighten one
that fires on noise.
Variations
- Other sources. The same primitive watches an
rssfeed (fire on each new item) or ajson_endpoint(fire when ajsonpathvalue crosses a threshold), by switchingsource_type. - Private endpoints. A watch can carry auth
headers, stored encrypted, for a source behind an API key. - Quiet a noisy period.
watch_pausestops polling (and billing) without losing the config;watch_resumepicks it back up. See the Watches guide for the full behaviour.
Next rung
The renewals agent — the capstone, where all four primitives compose into one workflow.