Skip to main content
Many flippers buy through a fresh LLC per deal, so one buying operation appears as several investor ids with short histories. The buyer signal ties them back together and says where each operation is in its cycle.

Operators

Every list row and match row carries investor.operator_id and investor.n_operator_members. The first is the id of the operation the investor belongs to: the member with the most purchases. The second is how many ids the operation spans. Shared mailing addresses (deed and tax bill) and shared names link the ids. buyer_signal.merge_confidence says how strong the link is. MERGED_WEAK is a shared mailing address alone, for example a mailbox store. Rows that share an operator_id are one buyer. Collapse them in the table. Contact them once. Three rules follow. If you skip them, the table is wrong:
  • The API ranks and pages each id on its own, so an operator with three ids can appear three times and across pages. Keep the row whose id equals operator_id as the visible one. Treat the others as its aliases.
  • Counts and scores are per id. The API never sums them per operator.
  • operator_id is the busiest member’s id, so it can move to another member after a data refresh. Group by it within one response. Store the investor ids, not the operator id.
An investor with no links is its own operator of 1.

The buyer_signal block

The block is on the profile and on every match row. It carries ids and numbers only, and the API serves it to every key:
array
Every id of the operation.
string
The first that applies. FRESH_CASH: the operator sold something in the last 60 days, so cash is back. For repeat flippers the next purchase usually comes within a month. LOADED: the operator holds three or more houses and sold nothing in 180 days. DORMANT: no purchase in a year and no sale in the last 60 days. STEADY: the rest.
mixed
The cycle facts behind that state. days_since_last_resale is the operator’s last sale of a house it held, an older holding’s exit included.
number | null
The fitted probability that the operator buys at least one house in the 180 days after the data end date. Null when the operator bought nothing in three years, or never bought. That window is longer than the DORMANT cycle state: an operator that last bought fourteen months ago is dormant and still carries a probability. w_activity scores a null at the measured rate at which such operators bought again. That parameter’s own description states the rate.
All the “days since” values are the operator’s, not the single id’s.

The activity weight

w_activity on /v1/buyers/match runs 0 to 1 and defaults to 0. It multiplies each score by activity_p_180 raised to that power: w_activity=1 ranks by expected purchases, 0.5 softens it.
The row shows base_score (the reasons) and activity_multiplier, so score = base_score × activity_multiplier. reasons[] and meta.weights do not change. Any change of w_activity starts a new ranking, so the cursor is no longer valid. The unregistered tail (include_unregistered=true) stays on the base_score scale: w_activity does not apply to it.
The shape above is real. The values are examples until a recording at the golden point carries the signal. On a market that does not have the signal yet, buyer_signal is null. There every investor is its own operator of 1, and w_activity scales every score by the same dormant rate. So the order does not change.