The problem this solves
MLS data (agent info, listing status, price history) and public record data (tax assessor info, ownership history, sale history) live in different systems. If you need both — say, an MLS search filtered by beds/baths/status, enriched with tax-assessor and ownership data — pulling the full MLS record for every result just to throw away most of the fields is wasteful. ids_only lets you run the MLS filter cheaply, get back just the REAPI property IDs (assessorId), and fetch full public-record detail only for the ids you actually want.
Flow: MLS Search (ids_only) → PropertyDetail / PropertyDetailBulk
ids_only) → PropertyDetail / PropertyDetailBulkStep 1 — filter in MLS Search, get IDs only:
POST /v3/MLSSearch
{
"city": "Austin",
"state": "TX",
"active": true,
"bedrooms_min": 3,
"ids_only": true
}Response:
{
"data": [203777375, 4753439, 41560455, ...],
"resultCount": 812,
"recordCount": 50,
"resultIndex": 0
}data is an array of REAPI property IDs (assessorId) — the same ID space used across every RealEstateAPI public-record endpoint.
Paging note: results are capped at 50 ids per response, same as a full-record search. Page through with resultIndex:
{ "city": "Austin", "state": "TX", "active": true, "bedrooms_min": 3, "ids_only": true, "resultIndex": 50 }Keep incrementing resultIndex by 50 until resultIndex + recordCount >= resultCount.
Step 2 — enrich with public-record data, one of two ways:
Single record:
POST /v2/PropertyDetail
{ "id": 203777375 }Bulk (up to 1000 ids per call):
POST /v2/PropertyDetailBulk
{ "ids": [203777375, 4753439, 41560455, ...] }This gives you the full public-record shape — tax assessor data, ownership, mortgage/lien info, sale history — for exactly the properties your MLS filter matched.
Alternative: public: true in the same MLS Search call
public: true in the same MLS Search callIf you don't need the full standalone public-record shape and are fine with the curated public-record subset embedded inline, skip the second round-trip entirely:
POST /v3/MLSSearch
{
"city": "Austin",
"state": "TX",
"active": true,
"bedrooms_min": 3,
"public": true
}Each returned MLS record now includes a public block alongside the MLS fields — one call, one response, no ID hand-off.
You can also request it via field selection instead of the boolean flag:
{ "..." : "...", "fields": ["listingPrice", "public"] }Which approach to use
Use ids_only + PropertyDetail/PropertyDetailBulk when... | Use public: true when... |
|---|---|
| You want the full public-record shape (more fields than the curated MLS-embedded subset) | The curated subset embedded in the MLS record is enough |
| You're building a two-stage pipeline (store IDs now, enrich later/elsewhere) | You want everything in a single response |
You need to batch enrichment independently of MLS paging (up to 1000 ids per PropertyDetailBulk call vs. 50 per MLS Search page) | You're fine being paged 50-at-a-time, matching your MLS Search cadence |
| You're deduping ids across multiple different MLS searches before enriching once | You're only running one MLS Search and want minimal round-trips |
Entitlements
Both paths are gated by the same public-record plan check. public: true (or a public.* fields selection) without an active public-record plan silently omits the block and returns a warnings entry explaining why — it does not error. PropertyDetail/PropertyDetailBulk calls without the right plan are gated at that endpoint directly. There's no entitlement difference between the two approaches — only an architecture/latency tradeoff.