Overview

The Create Saved Search API lets you set up automated property search alerts for CRM contacts. Define search criteria (city, price range, bedrooms, property type, etc.), choose a notification frequency, and the platform will automatically run the search on schedule — notifying the contact when new matching listings appear.

Each saved search stores a baseline snapshot of current results on creation, so subsequent runs can detect genuinely new listings rather than re-sending the entire result set.

💡 Pro Tip

Use the cities and property_sub_types array filters to create broader searches that cover multiple areas or property types in a single saved search — rather than creating separate searches for each.

How It Works

  1. Authentication — Validates your API key and establishes the user database connection
  2. Contact Validation — Confirms the contact exists in your CRM under the specified organization
  3. Filter Sanitization — Validates and sanitizes all search filters against the allowed filter set
  4. Idempotency Check — Rejects duplicate searches if the same contact already has a saved search with identical filters
  5. Limit Check — Enforces a maximum of 10 saved searches per contact
  6. Search Creation — Inserts the saved search record with calculated next-run schedule
  7. Signal Tracking — Records a reso_saved_search_created signal on the contact for engagement scoring
  8. Baseline Snapshot — Optionally executes the search immediately to capture the current matching listings as a baseline

Request

Endpoint: https://app.zyntrohq.com/apis/public/real_estate/createSavedSearch.php

Method: POST

Content-Type: application/json

Request Fields

FieldTypeRequiredDescription
api_keystringYesYour Zyntro API key
org_idstringYesOrganization UUID
brand_idintNoBrand ID. Defaults to 1
member_idstringNoMember UUID of the agent creating the search. Stored as ss_created_by_id
contact_idstringYesUUID of the CRM contact this search is for. Must exist under the specified org.
search_namestringYesHuman-readable name for the search (e.g., "Barrie Detached 3+ BR")
filtersobjectYesSearch criteria object. At least one valid filter is required. See filter fields below.
frequencystringNoHow often to run the search. One of: daily, every_3_days, weekly, every_2_weeks, monthly. Defaults to weekly
notification_emailstringNoEmail address for listing alerts. Defaults to the contact's primary email if not provided
created_bystringNoWho created the search: member or contact. Defaults to member
skip_baselineboolNoSet to true to skip the initial baseline search execution. Defaults to false

Filter Fields

FilterTypeDescription
citystringSingle city name
citiesarrayMultiple city names (e.g., ["Barrie", "Innisfil"])
postal_codestringPostal/ZIP code or prefix (e.g., "L4N")
property_typestringPrimary property type (e.g., "Residential", "Commercial")
property_sub_typestringSingle sub-type (e.g., "Detached")
property_sub_typesarrayMultiple sub-types (e.g., ["Detached", "Semi-Detached"])
transaction_typestringfor_sale or for_lease
min_pricenumberMinimum listing price
max_pricenumberMaximum listing price
min_bedsnumberMinimum number of bedrooms
max_bedsnumberMaximum number of bedrooms
min_bathsnumberMinimum number of bathrooms
max_bathsnumberMaximum number of bathrooms
min_sizenumberMinimum property size (sq ft)
max_sizenumberMaximum property size (sq ft)

💡 Pro Tip

When using both city and cities, the cities array takes precedence in the search execution. Use city for single-city searches and cities when covering a broader area. The same applies to property_sub_type vs property_sub_types.

Sample Request

{
  "api_key": "your_zyntro_api_key",
  "org_id": "your-org-uuid",
  "brand_id": 1,
  "member_id": "your-member-uuid",
  "contact_id": "contact-uuid",
  "search_name": "Barrie Detached 3+ BR under $1M",
  "filters": {
    "cities": ["Barrie", "Innisfil"],
    "property_type": "Residential",
    "property_sub_types": ["Detached", "Semi-Detached"],
    "transaction_type": "for_sale",
    "min_price": 500000,
    "max_price": 1000000,
    "min_beds": 3,
    "min_baths": 2
  },
  "frequency": "weekly",
  "notification_email": "[email protected]",
  "created_by": "member",
  "skip_baseline": false
}

Response

Success Response

{
  "status": "success",
  "message": "Saved search created",
  "data": {
    "uuid": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
    "name": "Barrie Detached 3+ BR under $1M",
    "filters": {
      "cities": ["Barrie", "Innisfil"],
      "property_type": "Residential",
      "property_sub_types": ["Detached", "Semi-Detached"],
      "transaction_type": "for_sale",
      "min_price": 500000,
      "max_price": 1000000,
      "min_beds": 3,
      "min_baths": 2
    },
    "frequency": "weekly",
    "notification_email": "[email protected]",
    "next_run_at": "2026-04-02 14:30:00",
    "baseline_results": 47
  }
}

Response Fields

FieldTypeDescription
uuidstringUnique identifier for the saved search. Use this to reference or manage the search later.
namestringThe search name as provided
filtersobjectThe sanitized filters that were stored (only valid filters are retained)
frequencystringThe notification frequency that was set
notification_emailstringEmail address where alerts will be sent
next_run_atstringScheduled date/time for the next search execution (Y-m-d H:i:s)
baseline_resultsintNumber of listings matching the filters at the time of creation. 0 if skip_baseline was true or no results found.

Error Responses

// Missing required fields
{"status": "error", "message": "api_key is required, contact_id is required"}

// Invalid API key
{"status": "error", "message": "Invalid API key"}

// Contact not found
{"status": "error", "message": "Contact not found"}

// No valid filters
{"status": "error", "message": "At least one valid filter is required"}

// Duplicate filters
{
  "status": "error",
  "message": "Duplicate search — contact already has a saved search with identical filters",
  "existing_uuid": "existing-search-uuid",
  "existing_name": "Existing Search Name"
}

// Maximum searches reached
{"status": "error", "message": "Contact has reached the maximum of 10 saved searches"}

Behavior Details

Idempotency

The API prevents duplicate saved searches. If a contact already has an active saved search with the exact same filter set, the request is rejected and the existing search UUID is returned. This means you can safely retry creation requests without worrying about duplicates.

Baseline Snapshot

By default, the API immediately executes the search against your MLS data and stores the matching listing IDs as a baseline. When the scheduled cron runs the search later, it compares new results against this baseline to identify genuinely new listings — so contacts only get notified about properties they haven't seen before.

Set skip_baseline to true if you want the first scheduled run to treat all matching results as new (useful for newly onboarded contacts who want to see everything).

Signal Tracking

Every saved search creation records a reso_saved_search_created signal on the contact's engagement timeline. This feeds into Zyntro's engagement scoring and segmentation intelligence — a contact who sets up saved searches is demonstrating active buyer intent.

Frequency Schedule

FrequencyNext Run
daily+1 day from creation
every_3_days+3 days from creation
weekly+1 week from creation (default)
every_2_weeks+2 weeks from creation
monthly+1 month from creation

Limits

  • Maximum 10 saved searches per contact (excluding deleted searches)
  • Only whitelisted filter keys are accepted — unknown keys are silently dropped
  • Null or empty filter values are stripped during sanitization

💡 Pro Tip

Use the created_by field to distinguish between agent-created and contact-created searches. When building a public-facing saved search form for buyers, set created_by to "contact" — this helps your team understand which searches were self-service vs agent-curated.

Best Practices

  • Name searches descriptively. "Barrie Detached 3+ BR under $1M" is far more useful than "Search 1" — both for your team and for the contact receiving alerts.
  • Start with weekly frequency. Daily alerts can overwhelm contacts in slower markets. Start weekly and let contacts request more frequent updates if they're actively buying.
  • Use array filters for flexibility. cities and property_sub_types let you cover broader criteria in a single search, reducing the number of saved searches needed per contact.
  • Don't skip baseline for existing contacts. The baseline prevents re-sending listings the contact may have already seen. Only skip it for brand-new contacts who want the full picture.
  • Let the duplicate check work for you. The API returns the existing search UUID when duplicates are detected — use this to redirect rather than error-handling.