Knowledge > Products > WiseAI Realtor > VOW / Sold-Data Track
WiseAI Realtor — VOW / Sold-Data Track (Phase 5)
Design-first scoping spec. No code, no migrations. This is build-roadmap.md Phase 5 and step 3 of the backend-completeness-audit "Recommended sequence." It decides how WiseAI Realtor unlocks sold data — the gate to the entire HouseSigma-class consumer feature set.
This is product requirements, not legal advice. Every item tagged [LEGAL] needs counsel sign-off and every [verify with board] needs confirmation from the board / PropTx before a client goes live. Sold-data rules, the VOW agreement terms, the sold-history window, retention, and who holds the VOW licence are the brokerage's and counsel's call, not ours.
0. The one-paragraph problem
Every Canadian consumer who has used HouseSigma, Zoocasa, or Wahi now expects to see what a home sold for, the sold comparables nearby, the price/relisting history, the true cumulative days-on-market, and an automated home-value estimate. WiseAI Realtor cannot show any of it today, because our live listings come from CREA's DDF feed, which carries zero sold/historical data (DDF is active-listings only; see do-not-reinvent.md and backend-completeness-audit.md). Sold data legally requires a board VOW (Virtual Office Website) feed displayed behind a consumer registration gate. Activating that feed is its own track with three hard dependencies: a board VOW agreement (the brokerage's licence, not ours), a consumer-account identity layer (distinct from the agent RBAC), and a registration gate that is — uniquely — the consumer expectation, the legal mechanism, and our single biggest lead-capture engine all at once.
1. What & why — VOW vs IDX vs DDF
Three different data licences, three different capabilities. Getting these straight is the whole spec.
| DDF® (what we run today) | IDX (board active feed) | VOW (board, behind login) | |
|---|---|---|---|
| Source | CREA national pool (ddfapi.realtor.ca) | Local board / PropTx | Local board / PropTx |
| Content | Active listings only | Active listings only | Active + sold/off-market + sales history |
| Sold prices / history | None | None | Yes (this is the point) |
| Public display | Public OK (with attribution) | Public OK (with attribution) | Login + registration + relationship required |
| Mental model | Free national syndication | Public "advertising" site | Private "business" site that replicates one-on-one office service online |
| Our status | LIVE (PR #1064) | Not used (DDF covers active) | Greenfield — this track |
- IDX is an advertising surface: all active listings, public, no registration. CREA's DDF is effectively our national IDX-equivalent and is already live for Beckett (office
296475, 11 listings,source='ddf'). - VOW is a brokerage-services surface: it adds off-market and sales history (sold price + sold date), and precisely because that data is more sensitive it is not open to the public — the registrant must establish a consumer-broker relationship and agree to terms first. (Realtyna — IDX vs VOW; CREA Café — tech acronyms)
What sold data unlocks (the HouseSigma-class bar):
- Sold price on every recently sold home.
- Sold comparables — "what did similar nearby homes sell for" (the CMA-lite buyers want).
- Price & relisting history — list → price-drop → relist → terminate → sold, with each price.
- True cumulative days-on-market (defeats the relist-to-reset-DOM trick).
- AVM / automated home-value estimate — built on the sold comps (§7).
- Just-sold / price-drop alerts on a saved search (§4 of data-model.md).
Incumbents show deep history — Wahi advertises up to 21 years of sales history; HouseSigma 10+ years (finehomesandliving roundup). Note the gap vs the feed window in §6 — the live PropTx VOW feed exposes roughly 2 years of sold history; longer archives are accrued by retaining synced rows over time and/or supplementing with public land-registry data. [verify with board] whether multi-year retention/accumulation beyond the feed window is permitted under the VOW agreement before promising "10 years."
2. Legal basis & hard invariants
2.1 Why sold data may be shown at all — Competition Bureau v. TREB
For years the Toronto Real Estate Board forbade members from displaying sold prices online via VOWs (members could share by hand/email/fax, but not online). The Competition Bureau challenged this as an abuse of dominance. The Competition Tribunal ordered TREB to stop restricting the display and use of sold prices through VOWs; TREB's PIPEDA/privacy defence was rejected as a pretext for blocking disruptive competition; the Federal Court of Appeal upheld it; and on 2018-08-23 the Supreme Court of Canada denied leave to appeal, ending a seven-year saga and letting the order take effect. (Competition Bureau / Canada.ca — SCC won't hear appeal; McCarthy Tétrault; RECO)
The precise lesson — and it cuts both ways: the case made it permissible for members to display sold data through a VOW. It did not make sold data fully public. The VOW registration gate (login + terms + relationship) is exactly what makes the display lawful. HouseSigma, Zoocasa, and Wahi all gate it behind a free account for this reason. So the gate is not an optional UX nicety — it is the legal mechanism.
2.2 Hard invariants (do not violate)
- Sold data is NEVER public. It is displayed only to a registered, terms-accepted consumer in a broker-consumer relationship. There is no anonymous path to a sold price. (Architecturally: deny-by-default RLS; anon role can never read sold tables — §5.)
- Registration is real, per the VOW rules. A registrant must supply name + a valid email, and the brokerage must send a confirming email that the registrant agreed to the terms of use. The registrant gets a unique username/password (or modern auth equivalent), must acknowledge a lawful consumer-broker relationship, personal non-commercial use, and a bona fide interest in buying/selling/leasing. (NAR VOW policy §II.2; CREA mirrors this structure — CREA Café.)
- No scraping / no redistribution. Terms must prohibit copying, redistributing, or retransmitting the data except in connection with the registrant's own consideration of a specific property; commercial use is barred; throttling/anti-scraping is expected.
- Seller opt-out is honored. A seller who directs the listing brokerage to withhold the listing/address from the internet must not appear; opt-out forms are retained (NAR: ~1 year). (NAR VOW policy §II.5)
- Display obligations. Listing-brokerage "courtesy of" attribution stays on displayed records; confidential fields (e.g. cooperating-broker compensation, certain expired/withdrawn/pending data) are not shown; MLS®/REALTOR® trademark rules apply (see compliance-privacy-analytics.md §4).
- MLS audit rights. The terms must let the board/MLS access the VOW to verify rule compliance. Our registration + display must survive a board audit.
- Registrant record retention. Keep the registrant's name, email, and credentials record for at least 180 days after access expires (NAR §II.2.b) — reconcile with the consumer's PIPEDA/Law 25 deletion rights (§5 of identity-consent-model.md; the consent/suppression-proof retention carve-out applies).
- The VOW licence belongs to the BROKERAGE, not to us. VOW/IDX data rights are issued to the brokerage of record for specific domains; WiseAI/John is a vendor / authorized data recipient on the brokerage's agreement, exactly as with DDF. We never hold or resell the feed (§9 Q1). [LEGAL]
- Province/board scope, never hardcoded. Beckett is on PropTx (Ontario; supports IDX + VOW). Other provinces differ — Quebec runs on Centris/OACIQ and Saskatchewan/QC are excluded from CREA DDF; VOW availability, sold-display rules, and the sold window vary by board. Design the adapter board-agnostic (one board profile per tenant), the way DDF is per-tenant. [verify with board]
The triple identity of the gate (the spine of this whole track): the registration gate is (a) what consumers already expect from HouseSigma/Wahi, (b) the legal mechanism that makes sold display lawful (Competition Bureau v. TREB + VOW rules), and (c) our #1 lead engine — every registrant becomes a consented, tracked lead/contact. One mechanism, three payoffs. Build it as a first-class product surface, not a popup afterthought.
3. The registration gate
A consumer wants to see a sold price → they hit a soft gate (browse active/IDX freely; sold price + history + AVM blur until they register). Registration is fast and free, and it does three jobs at once (§2.2 triple identity).
3.1 What the gate collects (minimum, per VOW rules + CASL)
| Field | Why | Source rule |
|---|---|---|
| Name | VOW registrant identity | NAR/CREA VOW §II.2 |
| Valid email (verified) | VOW identity + the confirming email | NAR/CREA VOW §II.2 |
| Email confirmation (double opt-in) | "send an email confirming the registrant agreed to the terms" | NAR/CREA VOW §II.2 |
| Terms-of-use acceptance (versioned) | non-commercial use, bona fide interest, no-scraping | NAR/CREA VOW §II.2.c |
| Consumer-broker relationship acknowledgement | the legal hook that permits VOW access | NAR/CREA VOW §II.1 |
| CASL/PIPEDA consent (granular; QC → French + express) | the registrant becomes a contactable lead | identity-consent-model.md §3 |
| Phone (optional) | HouseSigma uses SMS-verify; optional for us | — |
Auth options: email+password, Google OAuth, or email OTP — same primitives as the agent side, but a separate identity space (§5). HouseSigma gates with a mobile number + SMS code (HouseSigma sign-up); email is the VOW-required minimum, phone is optional.
3.2 The gate as lead engine (do not under-build this)
- Every registrant is upserted into the contact spine (
re_contacts/local_business_contacts) via the existing identity resolver, withsource_category='saved_search',source_detail='vow_signup'— a value already reserved in the lead-source taxonomy (data-model.md §4). - Registration writes a consent event (
source='web_form'/double_optin, basis per identity-consent-model.md §3.1) — so the AI front office may follow up within consent, and the universal suppression gate governs it. - The new registrant is routed to an agent (Beckett: language/round-robin per auth-rbac.md §3.1) and fires the hot-lead push.
- Registrant behavioral signal is gold: saved searches, watched areas, and sold-comps they pull become lead-scoring inputs and "facts the AI may use" for the next conversation.
This is the highest-intent lead capture in the product — a registrant is actively pricing a purchase/sale. Treat the gate's analytics + routing as P0 of the track, not a follow-on.
4. Data model extension
Extends the re_* model in data-model.md (which already anticipated this in §1.11 re_saved_searches, §5.1 open-question #6, and Phase 3 "VOW/sold-data track"). This spec resolves open-question #6: a separate re_sold_listings table, not an extension of local_business_listings — because sold data has a different licence, a different feed, a different (deny-by-default) access regime, and far larger volume, and must never share a table the public site reads for active listings (leak risk).
4.1 New / extended entities
re_sold_listings — the synced sold dataset (deny-by-default; never anon-readable). Tenant-scoped because the licence is per-brokerage (mirrors per-tenant DDF storage).
| Column | Type | Notes |
|---|---|---|
id | uuid PK | |
business_id | uuid NOT NULL FK | the tenant whose VOW licence covers this row |
source | text NOT NULL DEFAULT 'vow' | enum: vow | public_registry (provenance) |
board | text NULL | which feed (proptx, …) — not hardcoded |
mls_number / vow_id | text NULL | board keys (UNIQUE (business_id, mls_number)) |
address / unit / city / region / postal_code | text NULL | + address_norm for comp matching |
latitude / longitude | numeric NULL | radius/polygon comp search |
property_type / beds / baths / sqft / lot_size / year_built | — | comparability attributes |
list_price / sold_price / sold_date / list_date | numeric / date | sold_price + sold_date are the unlock |
dom / cumulative_dom | integer NULL | true days-on-market |
listing_brokerage_name | text NOT NULL | "courtesy of" attribution (invariant §2.2.5) |
seller_withheld | boolean NOT NULL DEFAULT false | opt-out honored (invariant §2.2.4) — never display when true |
raw | jsonb | RESO payload (audit/debug) |
synced_at / created_at / updated_at | timestamptz |
Indexes: (business_id, sold_date DESC), (business_id, postal_code), geo index on (latitude, longitude), (business_id, mls_number).
re_price_history — per-property event log (list/relist/price-change/terminate/sold/back-on-market) powering the price-history chart and true cumulative DOM.
| Column | Type | Notes |
|---|---|---|
id | uuid PK | |
business_id | uuid NOT NULL FK | |
property_key | text NOT NULL | mls_number or address_norm |
event_type | text NOT NULL | enum: listed | price_change | relisted | terminated | expired | sold | leased | back_on_market |
price | numeric NULL | |
effective_date | date NOT NULL | |
source / raw | text / jsonb |
re_avm_estimates — automated estimate + confidence range (§7). Never "the value."
| Column | Type | Notes |
|---|---|---|
id | uuid PK | |
business_id | uuid NOT NULL FK | |
subject_listing_id | uuid NULL FK → local_business_listings(id) | when valuing one of our listings |
subject_key | text NULL | address_norm for "what's my home worth" |
estimate | numeric NOT NULL | the midpoint |
confidence_low / confidence_high | numeric NOT NULL | published range (trust signal) |
confidence_score | numeric NULL | 0–1 |
method | text NOT NULL DEFAULT 'comp_based' | enum: comp_based | third_party |
comps_used | jsonb | [{sold_listing_id, weight}] — explainability + the AVM facts-used receipt |
model_version | text NULL | |
disclaimer_version | text NOT NULL | the "not an appraisal" text shown (§7) |
computed_at | timestamptz |
re_consumer_accounts — the NEW consumer identity (distinct from agent realtor_users/realtor_memberships).
| Column | Type | Notes |
|---|---|---|
id | uuid PK | |
business_id | uuid NOT NULL FK | the tenant they registered with (VOW is per-brokerage) |
auth_user_id | uuid NULL FK → auth.users(id) | Supabase Auth, consumer space (§5) |
contact_id | uuid NULL FK → contact spine | every registrant is a lead (§3.2) |
email / email_verified_at | text / timestamptz | VOW-required confirmed email |
display_name | text NOT NULL | VOW-required name |
phone | text NULL | optional |
terms_version / terms_accepted_at | text / timestamptz | versioned ToU acceptance |
relationship_established_at / relationship_basis | timestamptz / text | the consumer-broker relationship hook |
status | text NOT NULL DEFAULT 'pending_verification' | enum: pending_verification | active | suspended | expired |
created_at / last_login_at | timestamptz | retain ≥180 days post-expiry (§2.2.7) |
re_saved_searches (extend the existing §1.11 table): add consumer_account_id uuid NULL FK → re_consumer_accounts(id) (the registrant who owns it; keep contact_id for the lead link). Alert types already include new_listing \| price_drop \| just_sold \| open_house \| back_on_market.
re_listing_alerts (new, optional — the alert/digest delivery log): id, business_id, saved_search_id, consumer_account_id, alert_type, listing_id|sold_listing_id, channel (email|sms|push), status, sent_at. One row per delivered alert → feeds the unified timeline + suppression audit.
4.2 Coexistence with active listings
- Active listings stay on DDF (
local_business_listings,source='ddf', already live). Do not dual-source active. - Sold lives in
re_sold_listings(source='vow'). The public site reads active fromlocal_business_listings; the gated sold UI readsre_sold_listings. - A comparable is a query, not a stored entity: given a subject property, select nearby recent
re_sold_listingsby geo radius/polygon + property-type + size band. (This is why the table isre_sold_listings, resolving the data-model'sre_sold_comparablesplaceholder name.) - Decision flag (§9 Q5): PropTx VOW can also serve active (IDX) — if a tenant ever consolidates onto one PropTx feed, the active source could move VOW-side. MVP keeps DDF for active + VOW for sold to avoid disrupting the live DDF sync. [verify with board] whether running DDF (CREA) and a board VOW concurrently is permitted/required.
5. Consumer auth — a separate identity space
The consumer account is a distinct identity type from the agent. auth-rbac.md governs agents (realtor_users + realtor_memberships, capability resolver, commission gates). A consumer is none of that — they log in only to see gated sold data + manage their own saved searches.
| Agent (auth-rbac.md) | Consumer (this track) | |
|---|---|---|
| Identity row | realtor_memberships → local_businesses | re_consumer_accounts → local_businesses |
| Auth | Supabase Auth | Supabase Auth (same primitive, separate space) |
| Can see | tenant CRM (scoped), maybe commissions | only: gated sold data for the tenant they registered with + their own saved searches + AVM |
| Can NEVER see | — | any agent CRM table, any other consumer, any commission/financial row |
| Role claim | role ∈ {agent, team_admin, …} | role = 'consumer' |
Design (recommended):
- One
auth.users, two membership tables, two resolvers. Agents resolveauth.uid()→realtor_memberships(existingrealtor_account_ids(uid)helper). Consumers resolveauth.uid()→re_consumer_accounts(a newconsumer_account(uid)helper). A uid is one or the other; never let a consumer claim resolve an agent capability (R1 below). - RLS is the load-bearing gate for sold data — unlike the agent CRM (which ships service-role + app-layer first per auth-rbac §3.3),
re_sold_listings/re_avm_estimatesmust be RLS-on from day one:anon→ no rows;authenticatedconsumer → onlybusiness_id = their account's business_idand only non-withheld rows; agents → their tenant's rows via the agent resolver. A single un-gated public read of a sold price is a VOW-rule + Competition-Bureau-precedent breach, not just a bug. - The public site never reads sold tables directly. Gated sold UI calls a server route that checks the consumer session; the AI front office only states a sold fact when it has a registrant context + a facts-used receipt (ai-guardrails.md §RULE 3 — HO-03 today defers "I don't have sold data"; once VOW ships, the AI may surface sold data only inside an authenticated registrant session, never to an anonymous chat visitor).
get_advisorssecurity lint must be clean on every new sold/consumer table before launch (multi-tenant table with RLS off = P0).
Security risks:
- R1 — privilege confusion across the shared
auth.users. A consumer email that matches an agent email must not auto-elevate. Resolvers are table-specific; therole='consumer'claim is a hint, the membership row is truth (mirrors auth-rbac R4). - R2 — service-role bypass. Cron/sync/voice use service-role and skip RLS; the per-tenant + non-withheld + relationship scoping must therefore also live in app code for any path that emits sold data (mirrors auth-rbac R2).
- R3 — registrant enumeration / credential stuffing. Rate-limit registration + login; the email confirmation (double opt-in) is mandatory; bind sessions per device.
- R4 — sold data egress. No bulk export endpoint for consumers; throttle sold queries; honor the no-scraping terms with per-account rate limits and bot defenses (compliance-privacy-analytics.md §3).
6. Feed integration — the VOW adapter as a sibling of DDF
The VOW feed is a sibling adapter of src/lib/real-estate/ddf/, not a rebuild. PropTx exposes data over the RESO Web API (OData/JSON, bearer-token, server-to-server) — the same shape ddf/client.ts already speaks (Repliers / PropTx data access; EVNE — RESO Web API). The existing client authenticates with OAuth2 client-credentials against CREA (identity.crea.ca, scope DDFApi_Read); the VOW adapter does the same against the board/PropTx token endpoint with a VOW scope and the brokerage's VOW credentials.
Proposed structure (mirrors ddf/):
| File (proposed) | Mirrors | Responsibility |
|---|---|---|
src/lib/real-estate/vow/client.ts | ddf/client.ts | RESO Web API client; separate VOW_* env (VOW_ENABLED, VOW_CLIENT_ID/SECRET, VOW_TOKEN_URL, VOW_API_BASE_URL, VOW_SCOPE); same BOM/CRLF cleanEnv() discipline; isVowConfigured() gate; throws VowNotAuthorizedError until enabled + credentialed (never fake feed access). |
vow/map.ts | ddf/map.ts | RESO sold Property → re_sold_listings + re_price_history rows. |
vow/sync.ts | ddf/sync.ts | Manual-safe diff — insert/update/expire only source='vow' rows; never touch manual or ddf. Honor seller_withheld. |
vow/reso-types.ts | ddf/reso-types.ts | RESO sold-status field types (close price, close date, status). |
| triggers | /api/real-estate/ddf-sync + /api/cron/ddf-sync | owner button + a slower cron (sold data changes less than active; daily is plenty) — /api/real-estate/vow-sync + /api/cron/vow-sync. |
Gating (mirrors DDF exactly): every live call gated on VOW_ENABLED=true + per-tenant metadata.vow.authorized=true (set only after the board approves the brokerage's VOW agreement for the specific domain). Inert and throwing until then. The PropTx agreements are DLA + IDX + VOW, submitted per domain (1–3 URLs per agreement), each routed to the broker of record for confirmation before PropTx processes it (RealtyNinja — PropTx data agreements; PropTx VOW data feed).
Sold-window reality: the PropTx VOW feed exposes sold searches ~2 years back (RealtyNinja). To approach the HouseSigma/Wahi multi-year archive, retain synced sold rows over time (and/or supplement with public registry data) — [verify with board] retention/accumulation is permitted under the agreement (some restrict how long feed data may be stored).
Storage / coexistence: sold rows are per-tenant (business_id, synced from that tenant's VOW credentials), matching DDF's per-tenant model and keeping licence isolation clean. A shared board-keyed sold pool with per-tenant authorization joins would be more storage-efficient but risks showing one brokerage's licensed data under another's domain — defer as an optimization with a licensing review (§9 Q6). [LEGAL]
7. AVM — comp-based, with a published confidence range
Stance: build the simplest defensible estimate, and show the range incumbents hide.
- Method (MVP): comp-based. Compute the estimate from the registrant-visible
re_sold_listingscomps (nearby, recent, same property-type, size band) — a transparent, explainable model whose inputs are exactly the sold comps the consumer can see. The spread of the comps naturally produces a confidence range; persist the comps + weights inre_avm_estimates.comps_usedfor explainability and as the AVM's facts-used receipt. Avoid a black-box proprietary model in MVP. A third-party AVM API is a later option (method='third_party') if accuracy demands it. (§9 Q4.) - Publish the confidence range as a trust signal. Incumbents tend to hide their accuracy; we show "estimated $X, range $low–$high, based on N recent comps" — honesty as differentiation (matches backend-completeness-audit.md "publish a confidence range — incumbents hide it").
- Never guarantee or assert a value — this binds the AI and the UI. Per ai-guardrails.md RULE 2: an automated estimate is not an appraisal and not a professional opinion of value. Every AVM surface (the
/api/real-estate/home-valueendpoint, any "what's my home worth" page, and any AI relay) MUST carry the mandatory disclaimer and the range, MUST NOT present a single point value as the value, and MUST defer to the agent's real CMA. The post-LLM belt hard-fails any AI valuation turn missing the "estimate, not an appraisal" disclaimer (guardrails scenario RA-02). The AVM is a lead magnet that routes to a human CMA, not a substitute for one.
8. Phased activation plan (with dependencies)
VOW activation is gated by the board agreement (external, slowest) and the consumer identity layer (depends on the auth + identity/consent specs). Sequence:
| Phase | Step | Depends on | Owner |
|---|---|---|---|
| 5.0 | Board application + VOW agreement — brokerage (Sutton/Beckett) submits PropTx DLA + IDX + VOW for the WiseAI-hosted domain(s); WiseAI listed as vendor/data recipient; broker-of-record confirms. [LEGAL] [verify with board] | nothing technical; this is the long pole | Founder + brokerage + counsel |
| 5.1 | VOW feed adapter — vow/client.ts + map.ts + sync.ts + reso-types.ts; re_sold_listings + re_price_history migration (founder-gated, additive, service-role-grant-only); inert until VOW_ENABLED + metadata.vow.authorized | 5.0; the re_* data-model migration (Phase 6 of build-roadmap) | Eng |
| 5.2 | Consumer identity + registration gate — re_consumer_accounts; consumer Supabase Auth space; RLS-on sold tables; terms/relationship/consent capture wired to the consent ledger; registrant → re_contacts lead + routing + hot-lead push | 5.1; auth-rbac.md (auth primitive) + identity-consent-model.md (consent ledger + suppression gate) | Eng |
| 5.3 | Gated sold UI — sold price + sold comps + price/relisting history + true DOM, behind the gate; brokerage attribution + seller-opt-out honored; soft-gate UX (blur → register) | 5.1 + 5.2 | Eng + Design (see VOW consumer mockups, task #18) |
| 5.4 | Saved searches + alerts — extend re_saved_searches (consumer link); re_listing_alerts; price-drop / just-sold alerts (new on this track) + watched-area digests. Alerts are consumer-requested + consent-gated; no cron campaign sends — alert delivery is transactional, still passes the universal suppression gate (identity-consent-model.md §4.4) | 5.1 + 5.2 (+ 5.3 for sold alerts) | Eng |
| 5.5 | AVM — comp-based estimate + confidence range over re_sold_listings; re_avm_estimates; wire /api/real-estate/home-value; disclaimer + belt enforcement | 5.1 (sold data) + 5.3 | Eng |
| 5.6 | Compliance + board-audit hardening — registrant record retention (≥180d) vs PIPEDA/Law-25 deletion; no-scraping throttles + anti-bot; MLS audit-access path; Canadian-region data residency; counsel/brokerage sign-off | all above | Founder + counsel |
Critical path: 5.0 (board agreement) is the long pole and is not an engineering task — start it first and in parallel. Engineering 5.1→5.5 can be built inert behind the gate before 5.0 returns, exactly as DDF was built inert before authorization.
9. Open items needing founder / counsel / board
- [LEGAL] Who holds the VOW licence + applies? Confirm the brokerage (Sutton/Beckett) holds the IDX/VOW agreement and lists WiseAI/John as the authorized vendor/data recipient for the hosted domain(s) — we cannot hold or resell the feed. Who drives the PropTx application (broker of record must confirm)?
- [LEGAL] VOW agreement terms — sold-display obligations, seller opt-out handling, "courtesy of" attribution, the no-commingling / no-redistribution clauses, MLS audit-access, and how they constrain our UI + AI. Counsel + brokerage review before any registrant sees a sold price.
- [verify with board] Sold-history window + retention — PropTx VOW feed is ~2 years; can we retain/accumulate synced rows (or supplement with public registry) to reach the 10–21-year archive consumers expect, or is retention capped? Sets the honest promise on the sold UI.
- AVM method + liability — comp-based (recommended, explainable) vs a third-party AVM API; how the disclaimer + confidence range bound liability; do we ever show an AVM for a home the consumer doesn't own (privacy optics)? [LEGAL] on the "what's my home worth" flow for non-owners.
- Alert scope in MVP — which alert types ship first (new-listing is DDF-only and cheapest; price-drop/just-sold need VOW), default frequency caps, and confirming alert delivery is "transactional/consumer-requested," not a campaign send (no-cron-sends rule).
- [LEGAL] Sold-storage model — per-tenant copies (recommended, clean licence isolation) vs a shared board-keyed pool (storage-efficient, licence-risky). Confirm concurrent DDF (CREA active) + board VOW (sold) operation is permitted, or whether a tenant must consolidate onto one PropTx feed.
- Data residency — VOW + consumer PII in the shared Supabase instance; confirm Canadian-region hosting posture for this data class (ties to compliance-privacy-analytics.md + the audit's "Canadian-region hosting decision").
- Province expansion — Beckett is PropTx/Ontario; the adapter must stay board-agnostic for future provinces (QC = Centris/OACIQ, different rules; SK/QC excluded from DDF). Don't bake Ontario assumptions into the sold schema or the gate copy.
10. See also
- data-model.md — the
re_*tables this extends; resolves its §5.1 open-question #6 (separatere_sold_listings) and Phase-3 "VOW/sold-data track" line. - auth-rbac.md — agent identity; the consumer space here is deliberately separate.
- identity-consent-model.md — the consent ledger + universal suppression gate every registrant + alert passes through.
- ai-guardrails.md — the AVM "not an appraisal" disclaimer (RULE 2) and sold-fact honesty (RULE 3, HO-03) the AI must obey; sold facts only inside an authenticated registrant session.
- backend-completeness-audit.md — the Canadian feature bar + the sold-data/VOW caveat this track closes.
- compliance-privacy-analytics.md — per-client legal/footer, anti-bot, Canadian hosting.
- build-roadmap.md — this is Phase 5.
Sources
- NAR — Virtual Office Websites Policy (Handbook on Multiple Listing Policy) — the canonical VOW registration/terms/display structure CREA mirrors.
- CREA Café — 5 real estate tech acronyms demystified (DDF/IDX/VOW).
- Realtyna — Difference Between IDX and VOW and What is VOW in Real Estate.
- Competition Bureau / Government of Canada — Supreme Court will not hear TREB's appeal (2018-08-23).
- McCarthy Tétrault — The End of a 7-Year Saga: SCC refuses leave to appeal in the TREB abuse case.
- RECO — Supreme Court declines to hear TREB's appeal: what it means.
- PropTx — VOW Data Feed agreement and IDX Data Feed agreement; PropTx MLS Rules (eff. 2024-12-02).
- RealtyNinja — How to fill out the PropTx/TRREB IDX (DLA/IDX/VOW) data agreements — DLA+IDX+VOW; VOW unlocks sold ~2yr; per-domain URLs; broker-of-record confirmation.
- Repliers — PropTx / board data access (RESO Web API); EVNE — Real Estate Data Integrations: MLS/IDX/RESO Web API.
- HouseSigma — How to register an account (free, phone+SMS gate); Fine Homes & Living — Best home-search sites (Wahi up to 21yr sold history).
- Existing code grounding the adapter:
churchwiseai-web/src/lib/real-estate/ddf/client.ts(RESO Web API OAuth2 client-credentials),ddf/map.ts,ddf/sync.ts(manual-safe diff).