CayIQ MCP Data API help

A code-accurate reference for search_listings. Feed statistics and examples below were verified against the production feed on 2026-08-28: about 16,800 listings, including 2,986 Active listings.

Using search_listings

Pass an object of optional filters to search_listings. CSV fields accept comma-separated values with optional surrounding spaces. Filters combine as AND conditions; multiple values in one CSV field match any listed value. Every response includes mls_attribution and idx_disclaimer; retain both when presenting listing data.

Your API key carries a county entitlement: the counties it is authorized for. Every tool response is limited to those counties on every call, whether or not you send the county parameter.

Regions vs counties

region is the MLS's MLSAreaMajor vocabulary, not a county field. Its roughly 65 values mix neighborhoods, towns, and some counties. It is useful for MLS area selection, but it is not a reliable county filter: most Beaufort County listings are tagged with a neighborhood rather than Beaufort.

County-level scoping belongs to CountyOrParish, exposed through the live county parameter. The production feed has the following Active counts:

CountyOrParish valueActive listingsUse
Beaufort2,329Valid value for the live county parameter.
Jasper565Valid value for the live county parameter.
Hampton27Valid value for the live county parameter.
Colleton9Valid value for the live county parameter.

Live The county parameter narrows results within your key's authorized counties; matching is case-insensitive. It can never widen your scope: counties outside your entitlement are ignored, and a request only for out-of-entitlement counties returns zero rows rather than an error. Your key sees only its authorized subset of the table above.

High-volume verified MLSAreaMajor examples

region valueListings in feedWhat it illustrates
Bluffton/General422Town/general MLS area
Hilton Head/General342Town/general MLS area
Jasper County267County-named MLS area
Sea Pines102Neighborhood MLS area
City of Beaufort59Municipality MLS area

These are the production values and counts verified for this reference. Fetch the current complete vocabulary with get_area_taxonomies rather than hard-coding a static region list; taxonomy results are limited to your authorized counties.

Search parameters

ParameterTypeRequiredFilters onAllowed/example valuesNotes/reliability
qtextNoAddress fields, city, ZIP/postal code, listing ID, and PublicRemarks.110 Shell Midden, 29928, 1052240617Case-insensitive; full addresses work across the separately stored street number, name, and unit fields.
transactionenumNoPropertyType.sale, rent, allOmitted preserves existing all-listings behavior. Sale excludes ResidentialLease; rent returns leases only.
statustext/CSVNoTrestle StandardStatus.Active,Pending; feed includes Active (2,986), Closed (13,008), Pending, ActiveUnderContract, and others.Use exact MLS status values. CSV is supported.
regiontext/CSVNoMLSAreaMajor.Sea Pines or Bluffton/General,Hilton Head/GeneralAbout 65 mixed MLS-area values. Not reliable for county scoping; see Regions vs counties.
countytext/CSVNoThe feed's clean county field (CountyOrParish).Beaufort,JasperLive Narrows within your key's authorized counties; case-insensitive. Never widens: out-of-entitlement counties are ignored, and asking only for them returns zero rows.
sub_areatext/CSVNoMLSAreaMinor subdivision.A current value from get_area_taxonomies261 distinct values; CSV is supported. Query the taxonomy tool for current spelling.
viewtext/CSVNoCSV-in-string View tokens.One or more current View tokens, comma-separatedAbout 98% populated (16,496). Match tokens, not a display label invented by the client.
styletext/CSVNoArchitecturalStyle.One or more current style tokens, comma-separatedAbout 71% populated (11,972); missing values are common.
amenitytext/CSVNoAssociationAmenities.One or more current amenity tokens, comma-separatedAbout 95% populated (16,015). This is the amenity field used by the server.
exteriortext/CSVNoExteriorFeatures.One or more current exterior-feature tokens, comma-separatedAbout 86% populated (14,383).
specialtyenumNoServer-defined specialty behavior.foreclosures, featured, soldforeclosures matches SpecialListingConditions Foreclosure/REO/BankOwned variants (about 31 listings; rare). sold means Closed status (13,008). featured means the calling consumer's tenant featured listings, in configured display order.
min_price
max_price
numberNoListPrice lower/upper bound.min_price: 500000, max_price: 1000000Prices are about 95% sanely populated. Apply client-side sanity bounds because occasional bad outliers can exist.
min_beds
min_baths
numberNoBedroomsTotal / stored bath value sourced from BathroomsFull for this feed.min_beds: 3, min_baths: 2Both are about 80% populated. Do not build on BathroomsTotalInteger: it is 0% populated. The API exposes the normalized bath value as bathrooms_total.
year_built_min
year_built_max
numberNoYearBuilt lower/upper bound.year_built_min: 2000, year_built_max: 2020About 89% populated.
sqft_minnumberNoLivingArea lower bound.sqft_min: 1800About 87% populated.
page
page_size
numberNoResult pagination, not listing fields.page: 2, page_size: 50Defaults are page 1 and 50 results. page_size is capped at 100.

Worked examples

Text, status, and MLS area

{
  "q": "oceanfront",
  "status": "Active,Pending",
  "region": "Sea Pines,Bluffton/General",
  "sub_area": "<a current MLSAreaMinor value>",
  "page": 1,
  "page_size": 25
}

County narrowing (within your entitlement)

{
  "status": "Active",
  "county": "Jasper",
  "min_beds": 3,
  "page_size": 50
}

Features and price

{
  "min_price": 500000,
  "max_price": 1000000,
  "min_beds": 3,
  "min_baths": 2,
  "sqft_min": 1800,
  "view": "<current View token>",
  "amenity": "<current AssociationAmenities token>",
  "exterior": "<current ExteriorFeatures token>"
}

Age, style, and specialty

{
  "year_built_min": 2000,
  "year_built_max": 2020,
  "style": "<current ArchitecturalStyle token>",
  "specialty": "foreclosures",
  "page_size": 100
}

Replace angle-bracket placeholders with exact tokens from current feed data. county values outside your key's entitlement are ignored rather than erroring.

Call the API from your server

Use the REST tool endpoint at https://api.cayiq.com/api/mcp/tools/<tool> from trusted server-side code. Send the one-time key in the Authorization: Bearer header. Do not put the key in browser JavaScript, a React client component, NEXT_PUBLIC_* environment variables, local storage, a URL, source control, a screenshot, or a support ticket.

Store the key in your deployment secret manager as CAYIQ_MCP_API_KEY. The examples query search_listings; replace the input object only with filters supported above. The county parameter can narrow a key’s scope but can never widen it.

Python

Install the dependency once

python -m pip install requests

Set the key in your server environment, then run this code

import os
import requests

BASE_URL = "https://api.cayiq.com/api/mcp"
API_KEY = os.environ["CAYIQ_MCP_API_KEY"]

def call_tool(tool: str, arguments: dict) -> dict:
    response = requests.post(
        f"{BASE_URL}/tools/{tool}",
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json",
        },
        json=arguments,
        timeout=30,
    )
    response.raise_for_status()
    return response.json()

result = call_tool("search_listings", {
    "status": "Active",
    "county": "Beaufort",
    "min_beds": 3,
    "page_size": 10,
})

# Log safe aggregates, not the credential.
print({"total": result.get("total"), "page": result.get("page")})

JavaScript (Node.js)

Create a local server-only .env file, add it to .gitignore, then run Node with --env-file

# .env (do not commit this file)
CAYIQ_MCP_API_KEY=<your one-time key>

# Run: node --env-file=.env search-listings.mjs
const BASE_URL = "https://api.cayiq.com/api/mcp";
const apiKey = process.env.CAYIQ_MCP_API_KEY;

if (!apiKey) {
  throw new Error("CAYIQ_MCP_API_KEY must be set in the server environment.");
}

async function callTool(tool, arguments_) {
  const response = await fetch(`${BASE_URL}/tools/${tool}`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(arguments_),
  });

  if (!response.ok) {
    throw new Error(`CayIQ MCP request failed with HTTP ${response.status}`);
  }
  return response.json();
}

const result = await callTool("search_listings", {
  status: "Active",
  county: "Beaufort",
  min_beds: 3,
  page_size: 10,
});

// Log safe aggregates, not the credential.
console.log({ total: result.total, page: result.page });

For protocol-native clients, the same bearer key also works with the JSON-RPC MCP endpoint at https://api.cayiq.com/api/mcp. Start with initialize, then call tools/list or tools/call. The REST examples above are the simplest way to validate a server integration.

Field reliability in responses

Build address displays from StreetName (100% populated) plus City (99.97% populated), and include other address components when available. Do not use UnparsedAddress; it is 0% populated in this feed. For bedrooms use BedroomsTotal (about 80%). For baths use BathroomsFull (about 80%), represented by the API's normalized bathrooms_total; BathroomsTotalInteger is 0% populated. The server returns its normalized fields in lower snake case, including street_name, city, bedrooms_total, and bathrooms_total.

Search, map, and bulk-export rows include an absolute primary_image_url when image media exists. get_listing also includes ordered images[] entries with URL, order, caption, media type, MIME type, and suggested filename. Follow redirects when downloading. URLs always use the CayIQ media proxy; raw OAuth-protected Cotality/Trestle URLs are never returned.