← back to Homesonspec
CA builders: recon spec doc (collectors/BUILDERS.md) — turnkey extraction specs for Pulte/TriPointe/TaylorMorrison/Meritage; all 6 builders plain-curl/no-anti-bot/per-community-phone
ca4ba1d737923497ce85a88b353edefaf32bc3ce · 2026-07-22 23:37:13 -0700 · Steve
Files touched
Diff
commit ca4ba1d737923497ce85a88b353edefaf32bc3ce
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 22 23:37:13 2026 -0700
CA builders: recon spec doc (collectors/BUILDERS.md) — turnkey extraction specs for Pulte/TriPointe/TaylorMorrison/Meritage; all 6 builders plain-curl/no-anti-bot/per-community-phone
---
collectors/BUILDERS.md | 43 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/collectors/BUILDERS.md b/collectors/BUILDERS.md
new file mode 100644
index 0000000..a3abed5
--- /dev/null
+++ b/collectors/BUILDERS.md
@@ -0,0 +1,43 @@
+# Builder adapter recon (CA inventory) — 2026-07-23
+
+All 6 top CA builders recon'd. **All are plain-curl, HTTP 200, no anti-bot, no browser needed.**
+Each carries a per-community sales phone. Adapters are CA-scoped via an env var.
+
+| Builder | key | status | source shape |
+|---|---|---|---|
+| Lennar | lennar-site | ✅ built | per-community `__NEXT_DATA__` Apollo (LENNAR_STATE_FILTER) |
+| D.R. Horton | dr-horton-site | ✅ built+verified | per-community `var model = {…}` blob (DRHORTON_STATE) |
+| KB Home | kb-home-site | ✅ built+verified | ONE feed `/move-in-ready` → `var allMIRs=JSON.parse("…")` double-decode |
+| Pulte | pultegroup-site | ⬜ TODO | clean JSON API (has lat/lon!) |
+| Tri Pointe | tri-pointe-site | ⬜ TODO | Next.js RSC `__next_f` `"display_price"` objects |
+| Taylor Morrison | taylor-morrison-site | ⬜ TODO | Sitecore `data-fed-ref="fedmodel"` per /available-homes |
+| Meritage | meritage-homes-site | ⬜ TODO | Next.js `__NEXT_DATA__` per /state/ca/ page (has lat/lon!) |
+
+## Pulte (pultegroup-site) — JSON API, CLEANEST (do next)
+- Communities: `GET https://www.pulte.com/api/community/getcommunities?brand=Pulte&state=California&pageSize=1000000&pageNumber=0`
+- Homes per region: `POST https://www.pulte.com/api/qmi/inventorysearch` body `{"StateName":"California","RegionName":"<region>","BrandName":"Pulte"}`. CA regions: Bay Area, Los Angeles, Orange County, Palm Springs, Riverside County, Sacramento, San Bernardino County.
+- Home fields: `price/priceDiscount/finalPrice, bedrooms, bathrooms/halfBaths/totalBaths, squareFeet, garages, floors, address.{street1,city,state,zipCode} (strip whitespace), dateAvailable, salesPhoneNumber, communityName, communityId, communityLatitude/Longitude, inventoryPageURL`.
+- Status: `dateAvailable` "Available Now" → MOVE_IN_READY. HAS lat/lon (community-level). Adapter fetch() should POST per region (LiveFetcher may need a POST variant — or fetch the getcommunities GET + per-community `GET /api/plan/qmiplans?communityId=`).
+
+## Tri Pointe (tri-pointe-site) — Next.js RSC
+- Sitemap index `https://www.tripointehomes.com/sitemap.xml` → `sitemap-communities.xml`; CA communities = `<loc>` paths starting `/ca/` (73). URL: `/ca/{county}/{community}`.
+- Per community page: unescape RSC (`.replace('\\"','"')`), brace-match each object containing `"display_price":\d+`.
+- Fields: `display_price/min_price, min_bedrooms, min_bathrooms, min_sq_feet, min_garage, min_stories, home_status/availability_status/tpg_status, move_in_date, floor_plan, homesite, plan_type, address, cities[], zip_code, submarket, state_alpha_2_code`.
+- Phone: community `"phone":"949.432.9284"` or JSON-LD `LocalBusiness.telephone`.
+
+## Taylor Morrison (taylor-morrison-site) — Sitecore fedmodel
+- Sitemap index `https://www.taylormorrison.com/sitemap-index.xml` → CA `https://www.taylormorrison.com/ca/sitemap.xml` (601). Community = 4-seg `/ca/{metro}/{city}/{community}`; drop suffix pages + `*-community-group-page`.
+- Per community: fetch `{community}/available-homes`, regex `data-fed-ref="fedmodel">(\{…\})</script>`, JSON.parse, walk `availableHomesList.sections[*].homes[]`.
+- Fields: `address, city, state, zip, homeSite, price, wasPrice, bed, fullBath, halfBath, totalBath, garages, sqft, availabilityStatus ("1"=available), readyDate, isComingSoon, floorPlan, viewHomeLink.Url, photo.Src`.
+- Phone: community JSON-LD `telephone`. (SoCal grouped communities 302-redirect → resolve leaf.)
+
+## Meritage (meritage-homes-site) — Next.js __NEXT_DATA__
+- Sitemap `https://www.meritagehomes.com/sitemap.xml`; CA = `/state/ca/` (403), 3 regions. 2-seg `/state/ca/{region}/{slug}`: slug=street-address → HOME page; slug=name → COMMUNITY page.
+- Home page `__NEXT_DATA__` path `props.pageProps.componentProps.{guid}.data.lotSearch.lotData` (find the componentProps child with `.data.lotSearch.lotData`).
+- Home fields: `priceSpec, monthlyPrice, bedrooms, fullBathrooms, halfBathrooms, squareFootage, garages, stories, address1/city/state/zip, latitude/longitude, status ("Inventory"), constructionStage, completionEstimated, lot_number, imageUrls, communities.targetItems[].communityId`. HAS lat/lon.
+- Community page path `...data.communitySearch.communityData` → `metroPhoneNumber` (sales phone), lat/long, price/bed/bath ranges, totalQmis.
+
+## Notes
+- Register each in `apps/workers/src/cli.ts` ADAPTERS + add workspace dep in `apps/workers/package.json`.
+- SourceRegistry rows exist for all (inactive). To ingest: activate + set collectionMethod=CRAWL, deploy adapters to Kamatera, run `pnpm --filter @spechomes/workers pipeline -- --adapter=<key>` with the state env.
+- Pulte/Meritage give lat/lon → homes appear on the map. KB/DR-Horton/TriPointe/TaylorMorrison lack per-home geo in v1 (search/lists only) — geocoding is a follow-up.
← 65775ba Add KB Home adapter (3rd builder) — single-feed (var allMIRs
·
back to Homesonspec
·
Add Pulte adapter (4th builder) — JSON API (getcommunities + 7478696 →