Skip to main content

Off-market lead generators

An off-market lead generator is a saved, area-based scanner (outcodes or a drawn polygon) that surfaces properties not currently listed for sale but showing seller-motivation signals: long ownership duration, equity gained since last sale, high motivation score, serial-investor ownership, or negative equity. Each matched property carries a lead classification — hot, warm, standard, or low — plus enrichment badges for company-owned, distressed-company, and silently-pulled (recently delisted) properties. The workflow is: create a lead generator over your target area, then query its /properties endpoint with filters and sorting to pull ranked leads. The /counts endpoint gives the classification breakdown for the area. Required scope: leads:read Cost: 1 request per call Available on: Starter, Professional, Business
The number of lead generators you can hold at once is capped by your plan. Creating one beyond the cap returns 403 — delete an existing generator first. Each generator is tied to the account that created it.

List your lead generators

GET /api/v1/off-market-lead-generators
Returns all active off-market lead generators for the authenticated account, plus your plan limit and remaining headroom.

Request

curl https://api.propaideals.co.uk/api/v1/off-market-lead-generators \
  -H "Authorization: Bearer paid_..."
import requests

res = requests.get(
    "https://api.propaideals.co.uk/api/v1/off-market-lead-generators",
    headers={"Authorization": f"Bearer {API_KEY}"},
)
body = res.json()
print(f"{body['count']} generators, {body['remaining']} slots remaining")

Response

{
  "lead_generators": [
    {
      "id": "8c1f6a2e-3b4d-4e5f-9a0b-1c2d3e4f5a6b",
      "name": "Manchester city centre",
      "selected_outcodes": ["M1", "M4"],
      "polygon_wkt": null,
      "search_criteria": {
        "min_ownership_years": 10,
        "min_motivation_score": 60
      },
      "map_center_lat": 53.4808,
      "map_center_lng": -2.2426,
      "map_zoom": 13.0,
      "alert_enabled": false,
      "alert_id": null,
      "last_checked_at": "2026-06-10T09:14:02Z",
      "new_since_last_check": 4,
      "classification_counts": null,
      "is_active": true,
      "created_at": "2026-05-02T11:30:00Z",
      "updated_at": "2026-06-10T09:14:02Z"
    }
  ],
  "count": 1,
  "limit": 10,
  "remaining": 9
}
FieldTypeDescription
lead_generatorsarrayYour active lead generators (fields per object as above)
countintegerNumber of generators returned
limitintegerMaximum allowed on your plan
remainingintegerHow many more you can create

Create a lead generator

POST /api/v1/off-market-lead-generators
Either selected_outcodes or polygon_wkt must be provided (a 400 is returned if both are missing). Returns 201 with the created generator.

Request

curl -X POST https://api.propaideals.co.uk/api/v1/off-market-lead-generators \
  -H "Authorization: Bearer paid_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Manchester city centre",
    "selected_outcodes": ["M1", "M4"],
    "search_criteria": {
      "min_ownership_years": 10,
      "min_motivation_score": 60
    }
  }'
import requests

res = requests.post(
    "https://api.propaideals.co.uk/api/v1/off-market-lead-generators",
    headers={"Authorization": f"Bearer {API_KEY}"},
    json={
        "name": "Manchester city centre",
        "selected_outcodes": ["M1", "M4"],
        "search_criteria": {"min_ownership_years": 10},
    },
)
lg = res.json()
print(f"Created lead generator {lg['id']}")
ParamTypeRequiredDescription
namestringYesName for the generator (1–100 chars)
selected_outcodesstring[]One of theseOutcode strings, e.g. ["EH1", "EH2"] (normalised to uppercase)
polygon_wktstringOne of theseWKT geometry for a custom drawn area
search_criteriaobjectNoDefault off-market filter criteria (ownership years, motivation, yield, etc.) applied to every /properties call
map_center_latfloatNoSaved map centre latitude (−90 to 90)
map_center_lngfloatNoSaved map centre longitude (−180 to 180)
map_zoomfloatNoSaved map zoom level (1–22)
alert_enabledbooleanNoEnable alert notifications (default false)

Response

Same object shape as a single entry in the list response above (201 Created).

Get a lead generator

GET /api/v1/off-market-lead-generators/{lg_id}
Returns a single lead generator by UUID, including its classification counts.

Request

curl https://api.propaideals.co.uk/api/v1/off-market-lead-generators/8c1f6a2e-3b4d-4e5f-9a0b-1c2d3e4f5a6b \
  -H "Authorization: Bearer paid_..."
import requests

res = requests.get(
    f"https://api.propaideals.co.uk/api/v1/off-market-lead-generators/{lg_id}",
    headers={"Authorization": f"Bearer {API_KEY}"},
)
lg = res.json()
print(f"{lg['name']}: {lg['classification_counts']}")
ParamTypeRequiredDescription
lg_idUUID (path)YesThe lead generator ID. A non-UUID returns 400; an unknown ID returns 404

Response

Same object shape as the list response, with classification_counts populated:
{
  "id": "8c1f6a2e-3b4d-4e5f-9a0b-1c2d3e4f5a6b",
  "name": "Manchester city centre",
  "selected_outcodes": ["M1", "M4"],
  "classification_counts": {
    "hot": 18,
    "warm": 64,
    "standard": 211,
    "low": 95
  },
  "is_active": true,
  "created_at": "2026-05-02T11:30:00Z"
}

Search off-market properties

GET /api/v1/off-market-lead-generators/{lg_id}/properties
The core search endpoint. Returns properties within the generator’s area matching its saved search_criteria, with any query parameters below applied as per-request overrides. Results are paginated (max 100 per page).

Request

curl "https://api.propaideals.co.uk/api/v1/off-market-lead-generators/8c1f6a2e-3b4d-4e5f-9a0b-1c2d3e4f5a6b/properties?classification=hot&sort_by=motivation_score&min_ownership_years=15&limit=20" \
  -H "Authorization: Bearer paid_..."
import requests

res = requests.get(
    f"https://api.propaideals.co.uk/api/v1/off-market-lead-generators/{lg_id}/properties",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={
        "classification": "hot",
        "sort_by": "motivation_score",
        "min_ownership_years": 15,
        "limit": 20,
    },
)
body = res.json()
for prop in body["properties"]:
    print(f"{prop['full_address']} — owned {prop['years_owned']}y, "
          f"motivation {prop['motivation_score']}")
ParamTypeRequiredDescription
lg_idUUID (path)YesThe lead generator ID
classificationstringNoSingle classification filter: hot, warm, standard, low
sort_bystringNomotivation_score, ownership_duration, gross_yield, equity_gained, transaction_count, newest, oldest, price_asc, price_desc, estimate_asc, estimate_desc
pageintegerNoPage number (default 1)
limitintegerNoResults per page (1–100, default 20)
min_ownership_yearsintegerNoMinimum years owned
min_motivation_scorefloatNoMinimum motivation score
min_yieldfloatNoMinimum gross yield (%)
serial_investment_onlybooleanNoOnly properties with multiple historic sales (serial investors)
underwater_onlybooleanNoOnly properties estimated below their last sold price
min_priceintegerNoMinimum last sold price (£)
max_priceintegerNoMaximum last sold price (£)
min_bedroomsintegerNoMinimum bedrooms
max_bedroomsintegerNoMaximum bedrooms
property_typesstringNoComma-separated property types
lead_classificationsstringNoComma-separated classifications, e.g. hot,warm

Response

{
  "properties": [
    {
      "id": "4f3a2b1c-9d8e-4a7b-8c6d-5e4f3a2b1c0d",
      "full_address": "12 Example Street, Manchester, M1 4AB",
      "postcode": "M1 4AB",
      "outcode": "M1",
      "property_type": "Terraced",
      "bedrooms": 3,
      "bathrooms": 1,
      "last_sold_date": "2008-03-14",
      "last_sold_price": 124000.0,
      "years_owned": 18,
      "sale_estimate_current": 215000.0,
      "equity_gain_pct": 73.4,
      "rent_estimate_current": 1150.0,
      "gross_yield_pct": 6.4,
      "motivation_score": 82.0,
      "lead_classification": "hot",
      "historic_sales_count": 1,
      "is_serial_investment": false,
      "is_underwater": false,
      "latitude": 53.4794,
      "longitude": -2.2453,
      "rm_tenure": "Freehold",
      "rm_price_trajectory": null,
      "is_company_owned": true,
      "company_name": "Example Holdings Ltd",
      "company_status": "active",
      "is_distressed_company": false,
      "silent_pull_tier": "recent",
      "thumbnail_image_url": "https://..."
    }
  ],
  "total": 18,
  "page": 1,
  "limit": 20,
  "has_more": false
}
FieldTypeDescription
idUUIDOff-market property record ID
full_address / postcode / outcodestringAddress fields
property_type / bedrooms / bathroomsmixedBasic attributes
last_sold_dateISO dateDate of last recorded sale
last_sold_pricefloatLast sold price (£)
years_ownedintegerYears since the last sale
sale_estimate_currentfloatCurrent estimated sale value (£)
equity_gain_pctfloat% gain between last sold price and current estimate
rent_estimate_currentfloatEstimated monthly rent (£)
gross_yield_pctfloatEstimated gross yield (%)
motivation_scorefloatComposite seller-motivation score
lead_classificationstringhot / warm / standard / low
historic_sales_countintegerNumber of recorded historic sales
is_serial_investmentbooleanOwner has bought/sold repeatedly
is_underwaterbooleanCurrent estimate below last sold price
latitude / longitudefloatCoordinates
rm_tenurestringTenure where known (e.g. Freehold)
rm_price_trajectorystringPrice trajectory signal where known
is_company_ownedbooleanPresent when matched to a company-owned title
company_name / company_statusstringOwning company details (when company-owned)
is_distressed_companybooleanOwning company shows distress signals (when company-owned)
silent_pull_tierstringPresent when the property was recently delisted without selling
thumbnail_image_urlstringListing image where available
total / page / limit / has_moremixedPagination metadata
The company-ownership and silent-pull fields are best-effort enrichments — they are only present on rows where a match was found. Under heavy load the search degrades gracefully: you may receive an empty page with "degraded": true rather than an error; retry shortly.

Get classification counts

GET /api/v1/off-market-lead-generators/{lg_id}/counts
Returns the property count breakdown by lead classification for the generator’s area — useful for sizing an area before pulling pages of leads.

Request

curl https://api.propaideals.co.uk/api/v1/off-market-lead-generators/8c1f6a2e-3b4d-4e5f-9a0b-1c2d3e4f5a6b/counts \
  -H "Authorization: Bearer paid_..."
import requests

res = requests.get(
    f"https://api.propaideals.co.uk/api/v1/off-market-lead-generators/{lg_id}/counts",
    headers={"Authorization": f"Bearer {API_KEY}"},
)
counts = res.json()
print(f"HOT leads: {counts['hot']}")
ParamTypeRequiredDescription
lg_idUUID (path)YesThe lead generator ID

Response

{
  "hot": 18,
  "warm": 64,
  "standard": 211,
  "low": 95
}

Update or delete a lead generator

PUT /api/v1/off-market-lead-generators/{lg_id}
DELETE /api/v1/off-market-lead-generators/{lg_id}
PUT accepts the same fields as create — all optional, only provided fields are changed (a body with no fields returns 400). DELETE soft-deletes the generator (returns 204 No Content) and frees a slot against your plan cap.

Request

curl -X PUT https://api.propaideals.co.uk/api/v1/off-market-lead-generators/8c1f6a2e-3b4d-4e5f-9a0b-1c2d3e4f5a6b \
  -H "Authorization: Bearer paid_..." \
  -H "Content-Type: application/json" \
  -d '{"search_criteria": {"min_yield": 7.0}}'
import requests

requests.delete(
    f"https://api.propaideals.co.uk/api/v1/off-market-lead-generators/{lg_id}",
    headers={"Authorization": f"Bearer {API_KEY}"},
)

Response

PUT returns the updated lead generator object (same shape as create). DELETE returns 204 with no body.

Use cases

  • Direct-to-vendor sourcing — Pull hot leads with long ownership and high equity, then run letter or door-knock campaigns
  • BTL deal origination — Filter by min_yield to find off-market stock that pencils as a rental before it ever lists
  • Company-owned targeting — Surface is_company_owned / is_distressed_company titles for portfolio acquisition approaches
  • Failed-listing follow-upsilent_pull_tier flags properties recently withdrawn without selling — motivated vendors with a known asking-price anchor
  • Lead generators — On-market scanners over live listings with the same saved-search model
  • Properties — Search and retrieve live on-market property records