Documentation Index
Fetch the complete documentation index at: https://qwady.wiki/llms.txt
Use this file to discover all available pages before exploring further.
Borough offers two mechanisms for receiving real-time data beyond standard polling:
- 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 |
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.
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
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}'
Poll intervals
Each poll costs one API request against your monthly quota.
| 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 |
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"}
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 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.
Quota impact
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. 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 a quota_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.