Skip to main content

Installation

The SDK requires Node.js 22 or later.

Quick start

Configuration

The client accepts nothing (free tier, or BOROUGH_API_KEY from the environment), a string (API key), or a config object:

Resources

The client exposes resource modules following a consistent pattern:
The client also exposes listings.stream(), watchers, and webhooks. See Streams and watchers below and Webhook verification. Detail methods (listings.get, listings.getByUrl, buildings.get) report how the data was served in meta.source: cached, stale, or live. On Business, stale detail is fetched live before responding, and paid tiers queue a background refresh for stale data. Live fetches and refreshes draw on a shared live-fetch budget. When that budget is held for Borough’s scheduled updates, or live fetching is paused, these methods return cached data (source: "cached" or "stale") instead of live.

Streams and watchers

Listing stream (Pro+)

listings.stream(id) opens a server-sent event stream: a cached event with the stored record, then a live event with freshly fetched data, then done. The live fetch uses the same shared live-fetch budget. When that budget is held for scheduled updates or live fetching is paused, the stream sends an error event with code budget_exceeded or service_disabled in place of live, and the cached event stands.

Watchers (Business)

Watcher limits:
  • Creating a watcher past either cap throws QuotaExceededError (429 QUOTA_EXCEEDED); the message names the cap you hit. Resuming one with update(id, { active: true }) past a cap throws ValidationError (400).
  • A pollInterval below the minimum throws ValidationError.
  • A search watcher whose filters match more than 500 active listings throws ValidationError, both on create and when you resume it. On create, narrow it with areas, minPrice/maxPrice, beds, listingType, or buildingType; update cannot change filters, so to fix a resume, delete the watcher and create a narrower one. A running search watcher whose matches grow past 500 is paused.
  • Resuming a listing watcher whose pollInterval is below 3600 raises it to 3600.
  • Each poll counts as one request against your quota.

Watcher streams

watchers.stream(id) yields connected, change, heartbeat, reconnect, and stopped events. The server ends each stream about every 5 minutes, and the SDK reopens it by default with no limit on reconnects, resuming from the last event received. From SDK 0.8.0, a stream that closes without reconnect or stopped counts as a failed connection: it is retried with backoff, and after maxConsecutiveFailures (default 10) failed connections in a row the loop throws a ConnectionError. Every connection counts as one request against your quota, so a stream kept open around the clock costs about 12 requests an hour (about 8,640 per 30 days) on top of the polls. Pass maxReconnects to bound it, or abort signal to stop.

Error handling

The SDK throws typed errors that you can catch and handle:
Every error class extends BoroughError. The API error classes extend it through APIError, which carries code and status; ConnectionError and PaginationLimitError extend BoroughError directly:

Retries

The SDK automatically retries rate-limit errors (RateLimitError), 5xx responses, and network failures with exponential backoff. It does not retry QuotaExceededError, because waiting does not restore quota. Default: 2 retries, starting at 500ms. For a rate-limit error, the wait is at least the retryAfter value in the error body.

TypeScript

The SDK is fully typed. All request parameters and response types are exported:

Next steps