- Listing stream (Pro+) — SSE stream that delivers cached data immediately, then live data via Decodo
- Persistent watchers (Business+) — Durable Object-backed subscriptions that poll on a schedule and emit change events
Listing Stream (SSE)
GET /v1/listing/{id} opens a Server-Sent Events stream for a single listing. The stream emits:
| Event | Description |
|---|---|
cached | Immediate response from D1 cache |
live | Fresh data fetched via Decodo Scraping API |
error | Live fetch or parse could not complete; the payload includes a machine-readable error code such as fetch_failed |
done | Stream complete |
error event is emitted with an error code and message, and the stream closes.
This is a short-lived stream — it completes after delivering cached + live data (typically under 10 seconds).
Tier requirement: Pro, Business, or Internal.
Persistent Watchers
Watchers are long-lived subscriptions backed by Cloudflare Durable Objects. They support three watch types:| Type | Monitors | Change Events |
|---|---|---|
listing | A single listing | Price changes, status changes |
building | A building’s listings | New listings added, listings removed |
search | A search query | New listings matching your filters |
Creating a watcher
Poll intervals
Each poll costs one API request against your active quota window.| Tier | Minimum | Default |
|---|---|---|
| Business | 300s (5 min) | 900s (15 min) |
| Internal | 60s (1 min) | 900s (15 min) |
Streaming watcher changes
GET /v1/watchers/{id}/stream opens an SSE connection that emits change events:
| Event | Description |
|---|---|
connected | Stream opened, includes watcher metadata |
change | A change was detected (price drop, new listing, etc.) |
heartbeat | No changes detected this poll cycle |
reconnect | Stream duration limit reached — reconnect |
stopped | Watcher was deactivated |
error | Status check failed |
Managing watchers
- List:
GET /v1/watchers - Detail:
GET /v1/watchers/{id} - Pause/resume:
PATCH /v1/watchers/{id}with{"active": false}or{"active": true} - Change interval:
PATCH /v1/watchers/{id}with{"pollInterval": 600} - Delete:
DELETE /v1/watchers/{id}
Stream duration limit
Watcher SSE streams have a 5-minute maximum duration. When the limit is reached, the server sends areconnect event and closes the stream:
id field, but note that streams restart from the current state rather than replaying missed events.
Quota impact
Each watcher alarm poll costs 1 API request toward your active quota window and counts toward metered overage billing. A watcher polling every 15 minutes consumes approximately 2,880 requests per 30 days. Listing watchers also make a live Decodo fetch on each poll. Building and search watchers diff Borough’s cached D1 index instead, so they do not hit Decodo on every cycle. If your quota (including overage headroom) is exhausted, the watcher is automatically paused and aquota_exhausted event is broadcast.
Tier requirement: Business or Internal.
Choosing the Right Approach
| Scenario | Recommended |
|---|---|
| One-time fresh data for a listing | Business tier regular endpoint, or listing stream (SSE) for Pro |
| Ongoing monitoring of a specific listing | Watcher (listing type) |
| Alert when new units appear in a building | Watcher (building type) |
| Alert when new listings match search criteria | Watcher (search type) |
| Webhook delivery to your server | Webhook subscription + watcher |
Business and Internal tiers get live-first data automatically on
GET /v1/property/{id} and GET /v1/building/{id} — no SSE stream needed for single lookups. The regular endpoint returns "source": "live" when data is fetched fresh. See Data Freshness for details.