Data Freshness
Overview
Section titled “Overview”Borough caches data in a D1 database and refreshes it on a schedule. Every API response includes freshness metadata so you always know how old the data is and whether a refresh has been triggered.
Response metadata
Section titled “Response metadata”Every response includes these fields in meta:
| 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 |
freshnessThreshold | integer | Max allowed age in minutes before refresh triggers |
refreshTriggered | boolean | Whether this request triggered a background refresh |
Response headers
Section titled “Response headers”Two headers are included on every response:
X-Data-Age: 2026-02-16T14:30:00ZX-Data-Source: cachedSource values
Section titled “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) |
When 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
Section titled “Freshness thresholds by tier”Paid tiers trigger automatic background refreshes when data exceeds these age thresholds:
Search results
Section titled “Search results”| Tier | Threshold |
|---|---|
| Starter | 2 hours |
| Pro | 1 hour |
| Business | 30 minutes |
Listing details
Section titled “Listing details”| Tier | Threshold |
|---|---|
| Starter | 30 minutes |
| Pro | 15 minutes |
| Business | 10 minutes |
Building details
Section titled “Building details”| Tier | Threshold |
|---|---|
| Starter | 6 hours |
| Pro | 3 hours |
| Business | 2 hours |
Free tier behavior
Section titled “Free tier behavior”Free-tier requests always serve cached data and never trigger background refreshes. The freshnessThreshold and refreshTriggered fields are null for free-tier responses.
Cached data is refreshed on a fixed schedule regardless of API traffic:
| Data type | Schedule |
|---|---|
| Search index | Every 6 hours |
| Listing details | Daily |
| Building details | Every 2 days |
| Area boundaries | Weekly |
| Market snapshots | Daily |
How async refresh works
Section titled “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"
This means you never wait for a refresh — you always get a response immediately. The tradeoff is that one response may contain slightly older data.
Live-first data (Business / Internal)
Section titled “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
This applies to:
GET /v1/property/{id}GET /v1/property/by-urlGET /v1/building/{id}
Search, market, and area endpoints always serve from cache regardless of tier.
Best practices
Section titled “Best practices”- Check
meta.sourceto know if you’re reading stale data - For time-sensitive applications, use Pro or Business tier for tighter freshness thresholds
- Business tier gets live data on property and building detail — no need for SSE streams for single lookups
- If you need guaranteed-fresh data on Pro, use the listing stream endpoint for live SSE delivery