Overview
Borough caches data in a D1 database and refreshes it on a schedule. Every API response includes baseline freshness metadata so you can see how old the data is and how it was served. Freshness-sensitive endpoints may also include refresh-decision metadata when tier-based refresh logic applies.Response metadata
Freshness-aware JSON responses include these baseline fields inmeta:
| Field | Type | Description |
|---|---|---|
dataAge | string | When the data was last refreshed (ISO 8601 timestamp) |
source | string | How the data was served: cached, stale, or live |
| Some freshness-sensitive endpoints additionally include: |
| Field | Type | Description |
|---|---|---|
freshnessThreshold | integer | Max allowed age in minutes before refresh triggers |
refreshTriggered | boolean | Whether this request triggered a background refresh |
Response headers
Two freshness headers are also included on metered JSON/v1 responses:
Source values
| Value | Meaning |
|---|---|
cached | Data is within the freshness threshold for your tier |
stale | Data exceeds the threshold — a background refresh has been queued |
live | Fetched live from the source just now (Business/Internal tiers on property and building detail) |
source is stale, the API still returns the data immediately. The refresh happens asynchronously — your next request will get fresh data.
Freshness thresholds by tier
Paid tiers trigger automatic background refreshes when data exceeds these age thresholds:Search results
| Tier | Threshold |
|---|---|
| Starter | 8 hours |
| Pro | 8 hours |
| Business | 8 hours |
Listing details
| Tier | Threshold |
|---|---|
| Starter | 30 minutes |
| Pro | 15 minutes |
| Business | 10 minutes |
Building details
| Tier | Threshold |
|---|---|
| Starter | 6 hours |
| Pro | 3 hours |
| Business | 2 hours |
Free tier behavior
Free-tier requests always serve cached data and never trigger background refreshes. On freshness-sensitive endpoints,freshnessThreshold and refreshTriggered are null for free-tier responses.
Cached data is refreshed on a fixed schedule regardless of API traffic:
| Data type | Schedule |
|---|---|
| Rental search index | Every 6 hours |
| Sale search index | Every 8 hours |
| Listing detail sweeps | Every 12 hours |
| Building details | Every 3 days |
| Area boundaries | Weekly |
| Broadband enrichment | Monthly |
| Market snapshots | Daily at 05:00 UTC |
How async refresh works
When a paid-tier request hits stale data:- The API returns the stale data immediately with
"source": "stale" - A background job is triggered to fetch fresh data from the source
- The fresh data is written to the database
- Your next request returns the updated data with
"source": "cached"
Live-first data (Business / Internal)
Business and Internal tier requests for property detail and building detail endpoints get live data automatically:- If cached data is older than 5 minutes (listings) or 30 minutes (buildings), the API fetches fresh data from the source synchronously
- The live data is returned immediately with
"source": "live" - The fresh data is also written back to the cache, keeping it warm for all tiers
- If the live fetch fails or times out (8-10 seconds), the API falls back to cached data with the standard async refresh behavior
GET /v1/property/{id}GET /v1/property/by-urlGET /v1/building/{id}
Listing availability
Search endpoints (/v1/search/rentals, /v1/search/sales) and GET /v1/building/{id}/listings?status=ACTIVE return only listings that are currently on the market. When a listing comes off the market, Borough sets its status to OFF_MARKET, removes it from active search results, and records a listing.expired event in the listing’s history (GET /v1/property/{id}/history). Webhook subscribers receive the same listing.expired event.
Availability is reconciled against the source on each search refresh — rentals every 6 hours, sales every 8 hours — so a listing that leaves the market is reflected within roughly that window. A property detail lookup (GET /v1/property/{id}) still resolves for an off-market listing, so check data.status to confirm availability rather than assuming a successful response means the unit is active.
Best practices
- Check
meta.sourceto know if you’re reading stale data - For time-sensitive detail lookups, use Pro or Business tier for tighter listing/building freshness thresholds
- Business tier gets live data on property and building detail — no need for SSE streams for single lookups
- If you need the freshest available Borough path on Pro, use the listing stream endpoint for live SSE delivery. Like any live fetch, it still depends on upstream availability and response time.