Skip to content

Streaming and Real-Time Data

Borough offers two mechanisms for receiving real-time data beyond standard polling:

  1. Listing stream (Pro+) — SSE stream that delivers cached data immediately, then live data via Decodo
  2. Persistent watchers (Business+) — Durable Object-backed subscriptions that poll on a schedule and emit change events

GET /v1/listing/{id} opens a Server-Sent Events stream for a single listing. The stream emits:

EventDescription
cachedImmediate response from D1 cache
liveFresh data fetched via Decodo Scraping API
errorLive fetch or parse could not complete; the payload includes a machine-readable error code such as fetch_failed
doneStream complete
Terminal window
curl -N -H "Authorization: Bearer BOROUGH-..." \
https://borough.qwady.app/v1/listing/4961849
event: cached
data: {"id":"4961849","price":3200,...}
event: live
data: {"id":"4961849","price":3150,...}
event: done
data: {}

The cached event arrives immediately. The live event may take 2-5 seconds depending on upstream response time. If the live fetch fails, an 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.

Watchers are long-lived subscriptions backed by Cloudflare Durable Objects. They support three watch types:

TypeMonitorsChange Events
listingA single listingPrice changes, status changes
buildingA building’s listingsNew listings added, listings removed
searchA search queryNew listings matching your filters
Terminal window
curl -X POST https://borough.qwady.app/v1/watchers \
-H "Authorization: Bearer BOROUGH-..." \
-H "Content-Type: application/json" \
-d '{"watchType":"listing","listingId":"4961849","pollInterval":600}'

Each poll costs one API request against your monthly quota.

TierMinimumDefault
Business300s (5 min)900s (15 min)
Internal60s (1 min)900s (15 min)

GET /v1/watchers/{id}/stream opens an SSE connection that emits change events:

EventDescription
connectedStream opened, includes watcher metadata
changeA change was detected (price drop, new listing, etc.)
heartbeatNo changes detected this poll cycle
reconnectStream duration limit reached — reconnect
stoppedWatcher was deactivated
errorStatus check failed
Terminal window
curl -N -H "Authorization: Bearer BOROUGH-..." \
https://borough.qwady.app/v1/watchers/abc-123/stream
event: connected
data: {"watcherId":"abc-123","watchType":"listing","targetId":"4961849","pollInterval":600}
event: heartbeat
data: {"timestamp":"2026-02-19T12:00:00.000Z"}
event: change
data: {"eventType":"price_drop","listingId":"4961849","oldValue":"3200","newValue":"3150"}
  • 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}

Watcher SSE streams have a 5-minute maximum duration. When the limit is reached, the server sends a reconnect event and closes the stream:

event: reconnect
data: {"reason":"Stream duration limit reached. Please reconnect."}

Clients should automatically reconnect when receiving this event. Each SSE event includes an id field, but note that streams restart from the current state rather than replaying missed events.

Each watcher alarm poll costs 1 API request toward your monthly quota and counts toward metered overage billing. A watcher polling every 15 minutes consumes approximately 2,880 requests/month. If your quota (including overage headroom) is exhausted, the watcher is automatically paused and a quota_exhausted event is broadcast.

Tier requirement: Business or Internal.

ScenarioRecommended
One-time fresh data for a listingBusiness tier regular endpoint, or listing stream (SSE) for Pro
Ongoing monitoring of a specific listingWatcher (listing type)
Alert when new units appear in a buildingWatcher (building type)
Alert when new listings match search criteriaWatcher (search type)
Webhook delivery to your serverWebhook subscription + watcher