Developers · MCP tool reference

Reference · MCP

MCP tool reference

All 77 tools the Greenfinch MCP endpoint offers, grouped by what they do. Call any of them with tools/call — see MCP connector for the protocol, authentication and refusal format.

How to read a tool card

The markers on each card say what a call does:

Read-onlyWritesCosts creditsUses a daily limitNeeds a per-user connectionNeeds an extra scope

The example results are illustrative — invented data with the real field names; long arrays are shortened. The list of tools, their arguments and their full descriptions is generated from the same tool registry the endpoint serves, so it matches what tools/list returns.

Find properties and save searches.

Read-only

Searches commercial properties in one of three ways: free text (address, city, owner, name), a location filter (county FIPS, ZIP, city or county name) plus any attribute filters, or a map bounding box. Use county or location mode to get a true match count and a category breakdown; use free text to find a specific property.

Cost
Free.
ArgumentTypeDescription
querystringFree-text search across address, city, owner, name.
boundsobject—
filtersobject—
limitintegerMax results, default 50, max 200.
cursorstringPagination cursor from a prior `query`-mode call.
offsetintegerRows to skip in a county/bounds search — page 2 of a ranked list is offset=limit.
sortBystring (one of 19)Every sort the app's property search offers — works in query mode AND county/bounds mode. Defaults to "relevance". Numeric and date sorts place properties with no value LAST in both directions; the text sorts (commonName, ownerName, address, city, owner) treat a missing value as the highest value, so it sorts last ascending and FIRST descending. "owner" sorts the vendor parcel feed's owner-of-record; "ownerName" sorts the assessor's owner name — different columns. "address" sorts the raw feed address, not the tidied address shown in results. One of: relevance, commonName, lotSqft, buildingSqft, totalUnits, contactCount, landscapableSqft, roofAreaSqft, buildingFootprintSqft, yearBuilt, numFloors, ownerName, propertyValue, updatedAt, lastEnrichedAt, lastSaleDate, address, city, owner.
sortOrder"asc" | "desc"—
verbosity"compact" | "full"compact (default): the decision fields — id, key, address/geo, owner, category, sizes, value, year, teaser. full: adds provenance/plumbing (parcel account numbers, cluster flags, assessor name variants). Rows are ~40% smaller compact; prefer it unless you need the plumbing.
41 nested fields(bounds, filters)
ArgumentTypeDescription
bounds.minLatrequirednumber—
bounds.maxLatrequirednumber—
bounds.minLonrequirednumber—
bounds.maxLonrequirednumber—
filters.categoriesstring[]—
filters.subcategoriesstring[]—
filters.countyFipsstring[]5-digit county FIPS codes to search, e.g. ["51760"] for Richmond City, VA. Exact county scoping — use this instead of `bounds` whenever the question is about a county.
filters.zipCodesstring[]—
filters.citiesstring[]—
filters.countiesstring[]State-qualified county slugs (e.g. "middlesex-nj") or legacy bare names. OR-combined with zipCodes/cities, then ANDed with every other filter — matches the app's location panel.
filters.buildingClassesstring[]—
filters.acTypesstring[]—
filters.heatingTypesstring[]—
filters.roofTypesstring[]—
filters.exteriorWallTypesstring[]—
filters.poolTypesstring[]—
filters.fenceTypesstring[]—
filters.garageTypesstring[]—
filters.minLotSqftnumber—
filters.maxLotSqftnumber—
filters.minBuildingSqftnumber—
filters.maxBuildingSqftnumber—
filters.minUnitsintegerDisplayed unit count — researched value when known, else the assessor's.
filters.maxUnitsinteger—
filters.minPropertyValuenumber—
filters.maxPropertyValuenumber—
filters.minYearBuiltnumber—
filters.maxYearBuiltnumber—
filters.minFloorsinteger—
filters.maxFloorsinteger—
filters.minBedroomsinteger—
filters.maxBedroomsinteger—
filters.minBathroomsnumber—
filters.maxBathroomsnumber—
filters.enrichmentStatus"researched" | "not_researched"—
filters.saleRecencyBucketsstring (one of 5)[]e.g. ["3_months", "over_a_year"] — sold or transferred within the last N (the newer of the Last Sold and Last Transfer dates). One of: 1_month, 3_months, 6_months, 12_months, over_a_year.
filters.organizationIdstringProperties linked to this organization. UUID.
filters.contactIdstringProperties linked to this contact. UUID.
filters.changedKinds"ownership_transfer" | "sale" | "manager_change"[]Only properties with a recorded change of one of these kinds: ownership_transfer (the county records a new owner, backed by a newer recorded transfer), sale (a newer sale date was recorded), manager_change (a later research pass found a different managing firm, judged a real change). Combine with changedWithinDays; call greenfinch_get_changes for the evidence. Available once change filters (signals) are switched on for Greenfinch; until then a call that passes this is refused with SIGNALS_NOT_ENABLED, never run without it.
filters.changedWithinDaysintegerOnly changes the product detected within this many days (1 to 3650). Alone, it matches any of the kinds above. Available once change filters (signals) are switched on for Greenfinch; until then a call that passes this is refused with SIGNALS_NOT_ENABLED, never run without it.
filters.leaseTypes"triple_net" | "gross" | "modified_gross" | "ground_lease"[]Only properties whose researched lease arrangement is one of these (triple_net = Triple-net, gross = Gross, modified_gross = Modified gross, ground_lease = Ground lease). Owner-occupied and sale-leaseback are not filterable: they describe who owns the property and are shown on its detail once its research is unlocked. Research records a lease type only when a source it read states it (a leasing flyer, listing or article), so most properties have none and never match; the property's detail carries the source. Available once the lease-type field is switched on for Greenfinch; until then a call that passes this is refused with LEASE_TYPE_NOT_ENABLED, never run without it.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_search_properties",
    "arguments": {
      "filters": {
        "countyFips": [
          "48085"
        ],
        "categories": [
          "Office"
        ],
        "minBuildingSqft": 20000
      },
      "sortBy": "buildingSqft",
      "sortOrder": "desc",
      "limit": 2
    }
  }
}
Example result
{
  "results": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000001",
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX",
      "zip": "75074",
      "county": "Collin",
      "lat": 33.0198,
      "lon": -96.6989,
      "owner": "Northgate Business Park LLC",
      "commonName": "Northgate Business Park",
      "assetCategory": "Office",
      "assetSubcategory": "Office Building",
      "totalParval": 18450000,
      "yearBuilt": 2004,
      "lotSqft": 217800,
      "buildingSqft": 96000,
      "numFloors": 4,
      "aiRationale": "Four-story multi-tenant office building on a landscaped campus with surface parking...",
      "enrichmentStatus": "completed"
    }
  ],
  "total_matching": 214,
  "has_more": true,
  "returned": 1,
  "offset": 0,
  "next_offset": 1,
  "next_cursor": null,
  "category_breakdown": [
    {
      "category": "Office",
      "count": 214,
      "withValue": 209,
      "totalValue": 1934500000
    }
  ],
  "sorted_by": {
    "field": "buildingSqft",
    "direction": "desc"
  },
  "searched_scope": {
    "scoped": true,
    "countyCount": 2,
    "states": [
      "TX"
    ]
  },
  "truncation_note": "Showing 1 of 214 matches. Ranked by buildingSqft (desc); pass offset=1 for the next page. Use total_matching, never the row count, when reporting how many exist."
}

Refusal codes

NO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDMISSING_QUERY_BOUNDS_OR_COUNTYAMBIGUOUS_SEARCH_MODEINVALID_CURSORCURSOR_SORT_MISMATCHSIGNALS_NOT_ENABLED
Full description(the text AI assistants read)

Search properties three ways: by free text (address/city/owner/name), by county (`filters.countyFips`, the exact way to ask 'what is in this county' — a lat/lon box around a county always spills into its neighbours), or by map bounds. Full parity with the in-app property search: every filter the dashboard's filter panel offers (property type, building class, HVAC, lot/building size, unit count, year built, floors, roof/wall type, assessed value, bedrooms/bathrooms/pool/fence/garage, ZIP/city/county, enrichment status, last-sale recency, linked organization/contact) and every ranking it offers via `sortBy` — including `relevance` (ICP fit × opportunity size × contact quality), the DEFAULT sort when `sortBy` is omitted, exactly like the app. `offset` pages a county/bounds search (page 2 is offset=limit); `cursor` pages a free-text `query` search. County/bounds responses carry `total_matching` — the true number of matches, which the returned page is capped below — plus `category_breakdown`. Returns the fields useful for qualification/disqualification rules (D25): asset category/subcategory, lot size, building size, year built, assessed value, and a teaser aiRationale (call greenfinch_get_property for the full write-up). Unmetered — like browsing the map in the app.

Read-onlyNeeds a per-user connection

Lists the connected user's saved property searches, the same ones shown in the app's search picker. Each entry shows which stored filters this API can apply and names any app-only filters it cannot.

Cost
Free.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_list_saved_searches",
    "arguments": {}
  }
}
Example result
{
  "searches": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000601",
      "name": "Collin office over $5M",
      "filters": {
        "categories": [
          "Office"
        ],
        "countyFips": [
          "48085"
        ],
        "minLotSqft": null,
        "maxLotSqft": null,
        "minPropertyValue": 5000000,
        "maxPropertyValue": null,
        "minYearBuilt": null,
        "maxYearBuilt": null
      },
      "unsupported_filters": [
        "zipCodes"
      ],
      "updated_at": "2026-09-10T20:14:00.000Z"
    }
  ]
}

Refusal codes

ACTING_USER_REQUIREDIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

The acting user's saved searches — the same list the app's search picker shows, so the rep and their agent share one definition of each patch. Each entry reports which stored filters the MCP can apply and names any app-only filters it cannot (`unsupported_filters`) — a run of such a search is BROADER than the app's, never silently different. Per-user connections only.

Read-only

Lists recorded changes (signals) newest first: a property changing hands, a newer recorded sale, a different managing firm, a person leaving the employer we showed, or a changed title or employer. Ask for one property's or one contact's changes, or leave both out for every change in your visible territory. Each change carries when it was detected, where it was seen, and the changed value before and after; a manager change's firm names are shown once you have unlocked the property, and exact sale and transfer dates need the premium plan. To find records that changed, filter greenfinch_search_properties or greenfinch_browse_contacts with changedKinds and changedWithinDays. Available once signals are switched on for your workspace.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
propertyIdstringProperty UUID: this property's changes.
contactIdstringContact UUID: this person's changes.
kindsstring (one of 6)[]Only these kinds. Default: every kind the subject can have. One of: ownership_transfer, sale, manager_change, contact_departure, contact_title_change, contact_employer_change.
changedWithinDaysintegerOnly changes detected within this many days (1 to 3650).
limitintegerMax rows, default 50, max 200.
offsetintegerRows to skip.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_changes",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "kinds": [
        "manager_change",
        "ownership_transfer"
      ],
      "changedWithinDays": 90
    }
  }
}
Example result
{
  "changes": [
    {
      "signal_id": "3f2a9c1e-0000-4000-8000-000000000041:manager_change",
      "subject_type": "property",
      "subject_id": "3f2a9c1e-0000-4000-8000-000000000011",
      "kind": "manager_change",
      "detected_at": "2026-09-18T04:12:30.000Z",
      "source": "research",
      "evidence": {
        "field": "property_manager",
        "before": "Harbor Point Management",
        "after": "Northgate Property Services",
        "change_evidence_date": "2026-08"
      }
    },
    {
      "signal_id": "3f2a9c1e-0000-4000-8000-000000000042:ownership_transfer",
      "subject_type": "property",
      "subject_id": "3f2a9c1e-0000-4000-8000-000000000011",
      "kind": "ownership_transfer",
      "detected_at": "2026-09-02T02:40:11.000Z",
      "source": "county_record",
      "evidence": {
        "field": "owner_of_record",
        "before": "EXAMPLE HOLDINGS LLC",
        "after": "SAMPLE REALTY PARTNERS LP",
        "owner_withheld": false,
        "recorded_date": "2026-07-21"
      }
    }
  ],
  "total_matching": 2,
  "returned": 2,
  "offset": 0,
  "next_offset": null,
  "subject_types_included": [
    "property"
  ],
  "scope": {
    "scoped": true,
    "countyCount": 2,
    "states": [
      "TX"
    ]
  }
}

Refusal codes

SIGNALS_NOT_ENABLEDKIND_NOT_FOR_SUBJECTFEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDOUT_OF_TERRITORYNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

Recorded changes (signals), newest first, with the true total: a property changing hands (ownership_transfer), a newer recorded sale (sale), a different managing firm found by research (manager_change), a person leaving the employer we showed (contact_departure), a changed title (contact_title_change) or employer (contact_employer_change). Pass propertyId or contactId for one record's changes, or neither for every change in your visible territory. Filter by `kinds` and `changedWithinDays`. Each row carries the kind, when Greenfinch detected it, where it was seen, and the evidence: the changed field's value before and after (owner names are withheld on properties whose owner is suppressed; a manager change's firm names are withheld until you reveal the property, and exact sale and transfer dates need the premium plan — the change itself is still listed, marked manager_withheld / dates_withheld). To FIND records with a change, use greenfinch_search_properties or greenfinch_browse_contacts with `changedKinds` / `changedWithinDays`. Unmetered.

Properties

Read and unlock property detail.

WritesUses a daily limit

Fetches one property's full detail: address, size, age, category, assessed value, ownership and management (when unlocked), the full AI write-up, and its contacts. Read researchState first: it tells you whether to start research, unlock the property, or read the contacts directly.

Cost
No credits. Contacts your organization can see only through its geographic subscription (not through a purchase) count against the daily contact-disclosure limit; if that limit is used up they come back masked instead.
Daily limit
Counts toward the daily contact-reveal limit.
ArgumentTypeDescription
idrequiredstringProperty UUID or property key.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_property",
    "arguments": {
      "id": "3f2a9c1e-0000-4000-8000-000000000001"
    }
  }
}
Example result
{
  "property": {
    "id": "3f2a9c1e-0000-4000-8000-000000000001",
    "address": "1200 Commerce Pkwy",
    "city": "Plano",
    "state": "TX",
    "zip": "75074",
    "county": "Collin",
    "lat": 33.0198,
    "lon": -96.6989,
    "lotSqft": 217800,
    "buildingSqft": 96000,
    "yearBuilt": 2004,
    "yearBuiltDetail": {
      "basis": "per_building",
      "oldest": 1998,
      "newest": 2004,
      "primaryBuildingBasis": "area",
      "buildings": 3,
      "buildingsTotal": 3
    },
    "numFloors": 4,
    "numFloorsDetail": {
      "basis": "per_building",
      "max": 4,
      "areaWeightedMean": 3.51,
      "primaryBuilding": 4,
      "primaryBuildingBasis": "area",
      "buildings": 3,
      "buildingsTotal": 3
    },
    "effectiveYearBuilt": 2015,
    "effectiveYearBuiltDetail": {
      "basis": "per_building",
      "oldest": 2009,
      "newest": 2015,
      "primaryBuildingBasis": "area",
      "buildings": 2,
      "buildingsTotal": 3
    },
    "heatingType": "Rooftop Package Unit",
    "heatingTypeDetail": {
      "basis": "per_building",
      "buildings": 3,
      "buildingsTotal": 3,
      "areaShare": 1,
      "values": [
        {
          "value": "Rooftop Package Unit",
          "buildings": 2,
          "areaShare": 0.844
        },
        {
          "value": "Heat Pump",
          "buildings": 1,
          "areaShare": 0.156
        }
      ]
    },
    "coolingType": "Rooftop Package Unit",
    "coolingTypeDetail": {
      "basis": "per_building",
      "buildings": 3,
      "buildingsTotal": 3,
      "areaShare": 1,
      "values": [
        {
          "value": "Rooftop Package Unit",
          "buildings": 2,
          "areaShare": 0.844
        },
        {
          "value": "Heat Pump",
          "buildings": 1,
          "areaShare": 0.156
        }
      ]
    },
    "primaryConstructionType": "Concrete",
    "primaryConstructionTypeDetail": {
      "basis": "per_building",
      "buildings": 3,
      "buildingsTotal": 3,
      "areaShare": 1,
      "values": [
        {
          "value": "Concrete",
          "buildings": 3,
          "areaShare": 1
        }
      ]
    },
    "exteriorWallMaterial": null,
    "exteriorWallMaterialDetail": null,
    "foundationType": "Slab on Grade",
    "foundationTypeDetail": {
      "basis": "per_building",
      "buildings": 3,
      "buildingsTotal": 3,
      "areaShare": 1,
      "values": [
        {
          "value": "Slab on Grade",
          "buildings": 3,
          "areaShare": 1
        }
      ]
    },
    "roofCover": null,
    "roofCoverDetail": null,
    "roofShape": null,
    "roofShapeDetail": null,
    "qualityGrade": "Good",
    "qualityGradeDetail": {
      "basis": "per_building",
      "buildings": 3,
      "buildingsTotal": 3,
      "areaShare": 1,
      "values": [
        {
          "value": "Good",
          "buildings": 2,
          "areaShare": 0.844
        },
        {
          "value": "Average",
          "buildings": 1,
          "areaShare": 0.156
        }
      ]
    },
    "hasPool": false,
    "hasPoolDetail": {
      "basis": "per_building",
      "count": 0,
      "buildings": 3,
      "buildingsTotal": 3
    },
    "hasSprinklers": true,
    "hasSprinklersDetail": {
      "basis": "per_building",
      "count": 2,
      "buildings": 2,
      "buildingsTotal": 3
    },
    "buildingAttributesBasis": "per_building",
    "footprintArea": 21500,
    "footprintAreaSource": "measured",
    "assetCategory": "Office",
    "assetSubcategory": "Office Building",
    "commonName": "Northgate Business Park",
    "nameLocked": false,
    "beneficialOwner": "Northgate Holdings Group",
    "beneficialOwnerType": "private_investor",
    "managementCompany": "Lakeside Property Services",
    "aiRationale": "Four-story multi-tenant office building on a landscaped campus. Managed by Lakeside Property Services on behalf of Northgate Holdings Group...",
    "enrichmentStatus": "completed",
    "lastEnrichedAt": "2026-08-20T14:11:00.000Z",
    "researchedAt": "2026-08-20T14:11:00.000Z",
    "researchTier": {
      "displayName": "Base research model",
      "description": "Our standard AI research pass — fast and accurate for the large majority of properties.",
      "isUpgradeAvailable": true
    },
    "totalParval": 18450000,
    "premiumDataRedacted": false
  },
  "contacts": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000201",
      "fullName": "Dana Whitfield",
      "normalizedName": "dana whitfield",
      "contactType": "individual",
      "email": "dana.whitfield@example.com",
      "normalizedEmail": "dana.whitfield@example.com",
      "emailStatus": "valid",
      "emailValidationStatus": "valid",
      "alternateEmails": [],
      "phone": "(214) 555-0142",
      "normalizedPhone": "+12145550142",
      "phoneLabel": "Direct",
      "phoneSource": "research",
      "phoneExtension": null,
      "aiPhone": null,
      "aiPhoneLabel": null,
      "enrichmentPhoneWork": null,
      "enrichmentPhonePersonal": null,
      "title": "Facilities Manager",
      "companyDomain": "example.com",
      "employerName": "Lakeside Property Services",
      "roleChangedAt": null,
      "employerChangedAt": null,
      "likelyRoleChangeAt": null,
      "likelyRoleChangeVersionWindow": null,
      "likelyEmployerChangeAt": null,
      "likelyEmployerChangeVersionWindow": null,
      "currentRoleStartedAt": "2022-03-01T00:00:00.000Z",
      "currentEmployerStartedAt": "2019-06-01T00:00:00.000Z",
      "linkedinUrl": "https://www.linkedin.com/in/example-dana-whitfield",
      "linkedinStatus": "verified",
      "location": "Dallas, TX",
      "source": "property_research",
      "needsReview": false,
      "reviewReason": null,
      "enrichedAt": "2026-08-20T14:11:00.000Z",
      "createdAt": "2026-08-20T14:11:00.000Z",
      "role": "property_manager",
      "relationshipStatus": "active",
      "revealed": true
    }
  ],
  "contactsSummary": null,
  "researchRevealed": true,
  "researchState": "revealed",
  "revealSource": "paid",
  "coveredByPlan": true
}

Refusal codes

NOT_FOUNDPROPERTY_RETIREDOUT_OF_TERRITORYNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

Fetch one property's detail. Includes the fields useful for building disqualification/qualification rules (D25): asset category/subcategory, lot size, building size, year built, assessed value, and the full description via aiRationale (when entitled). READ `researchState` FIRST — it is the field that tells you what to do next: `none` means this property has never been researched, so there is nothing to reveal and greenfinch_reveal_property will refuse; run greenfinch_start_research instead. `locked` means research exists but is not unlocked for your org: ownership/management fields and aiRationale come back null rather than partial, `contacts` is empty, and `contactsSummary` gives a title plus per-channel availability booleans so you can judge whether revealing is worth it. `revealed` means `contacts` carries the full records (PII masked per-contact unless separately revealed) and `contactsSummary` is null. (The older `researchRevealed` boolean is a redaction switch, not an availability answer — it reads `true` for a never-researched property because there is nothing to withhold.) A property outside the caller's territory/subscription returns a typed OUT_OF_TERRITORY refusal (not a bare not-found) — a property id that does not exist at all still refuses NOT_FOUND. An id you already hold a pipeline deal, list entry, or paid reveal for, but that a county re-ingest has since retired, returns a typed PROPERTY_RETIRED refusal naming the successor property id to use instead (never a bare NOT_FOUND) — see greenfinch_get_pipeline's `property_lifecycle` field for where this comes from. A contact covered ONLY by your org's geography subscription (not a durable per-item reveal/unlock) draws down your org's daily contact-disclosure cap on an ordinary call, same as greenfinch_reveal_contact/greenfinch_get_contact — unmetered otherwise. A read-only-role member's connection never spends this cap here: those contacts come back masked instead.

WritesCosts credits

Unlocks a researched property for your organization, which gives you its full research and every contact attached to it. Use it before reading a property's contacts or exporting its lead bundle.

Cost
10 credits to unlock the property, unless your organization already unlocked it or your plan covers its county. Retrying is safe: a property that is already unlocked costs 0.
ArgumentTypeDescription
propertyIdrequiredstring—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_reveal_property",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000001"
    }
  }
}
Example result
{
  "alreadyRevealed": false,
  "creditsCharged": 10
}

Refusal codes

NOT_FOUNDPROPERTY_RETIREDIDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYOUT_OF_TERRITORYNOT_RESEARCHEDINSUFFICIENT_CREDITSPAYMENT_FAILEDACTION_IN_PROGRESSORG_SUSPENDEDNO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Unlock a property's full research + all its contacts (10 credits, skipped if already unlocked or covered by a geography entitlement).

greenfinch_get_property_constituents

Get Property Constituents

Read-only

For a complex property made up of several parcels (for example an office campus), lists the individual sub-parcels with address, size, category, and assessed value where your plan allows. Use it when a property record represents a multi-parcel site and you need the parts.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
parentPropertyIdrequiredstringParent property UUID or property key.
limitintegerMax rows, default 100, max 200.
offsetintegerRows to skip.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_property_constituents",
    "arguments": {
      "parentPropertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "limit": 100,
      "offset": 0
    }
  }
}
Example result
{
  "parent_property_id": "3f2a9c1e-0000-4000-8000-000000000011",
  "constituents": [
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000021",
      "address": "1200 Commerce Pkwy Bldg A",
      "city": "Plano",
      "state": "TX",
      "zip": "75074",
      "asset_category": "Office",
      "asset_subcategory": "Office Building",
      "lot_sqft": 87120,
      "building_sqft": 42000,
      "assessed_total_val": 6150000
    },
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000022",
      "address": "1200 Commerce Pkwy Lot 2",
      "city": "Plano",
      "state": "TX",
      "zip": "75074",
      "asset_category": "Office",
      "asset_subcategory": "Parking",
      "lot_sqft": 43560,
      "building_sqft": null,
      "assessed_total_val": null
    }
  ],
  "total_matching": 2,
  "constituents_hidden_by_territory": 1
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDOUT_OF_TERRITORYNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

For a complex parent property in your territory, its constituent sub-parcels as derivatives (address, size, use/category, assessed value when your plan includes premium property data) — never separately reachable elsewhere on this connector. The parent must itself be a canonical, in-territory property; a constituent parcel's own id is never accepted here. Each constituent is ALSO territory-, serviceable-, and listing-suppression-fenced on its own, since a sub-parcel can sit in a different county than its parent and can be individually withheld even when its parent is not — `constituents_hidden_by_territory` says how many were hidden by territory or serviceability specifically, so this is never a silent partial. It never counts a withheld constituent: withholding is deliberately invisible on this connector, so a withheld child and a deleted child both leave this number unchanged. Unmetered.

Contacts and organizations

Find, read and reveal contacts and the firms behind properties.

greenfinch_get_contact_relationships

Get Contact Relationships

Read-only

Lists every property a contact is attached to. Properties inside your territory come back with id and address; properties outside it appear only as a state and county, with a pointer to request coverage.

Cost
Free.
ArgumentTypeDescription
contactIdrequiredstringContact UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_contact_relationships",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000201"
    }
  }
}
Example result
{
  "relationships": [
    {
      "in_your_territory": true,
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX"
    },
    {
      "in_your_territory": false,
      "state": "OK",
      "county_fips": "40109",
      "coverage_request_tool": "greenfinch_request_coverage"
    }
  ]
}

Refusal codes

NOT_FOUNDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

List every property a contact is attached to. Properties outside the caller's territory appear only as a coverage teaser (state + county), never as an id or address.

greenfinch_get_organization_properties

Get Organization Properties

Read-only

Lists every property an owner or property-management company is connected to, with its role on each property. Properties outside your territory appear only as a state and county, never as an id or address.

Cost
Free.
ArgumentTypeDescription
organizationIdrequiredstringOrganization UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_organization_properties",
    "arguments": {
      "organizationId": "3f2a9c1e-0000-4000-8000-000000000401"
    }
  }
}
Example result
{
  "organization": {
    "id": "3f2a9c1e-0000-4000-8000-000000000401",
    "name": "Lakeside Property Services"
  },
  "properties": [
    {
      "in_your_territory": true,
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX",
      "role": "property_manager",
      "attributionType": "named_for_property"
    },
    {
      "in_your_territory": false,
      "state": "OK",
      "county_fips": "40109",
      "coverage_request_tool": "greenfinch_request_coverage",
      "role": "owner",
      "attributionType": "county_record"
    }
  ]
}

Refusal codes

NOT_FOUNDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

List every property an owner/property-management firm touches. Properties outside the caller's territory appear only as a coverage teaser (state + county), never as an id or address.

Read-only

Finds contacts by name or employer across everything visible to you (for example 'Dana at Lakeside'), without needing an id first. Returns name, title, employer and location; emails and phones stay behind the reveal tools.

Cost
Free.
ArgumentTypeDescription
queryrequiredstringName or employer fragment, min 2 chars.
limitintegerMax results, default 10, max 50.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_find_contacts",
    "arguments": {
      "query": "Lakeside",
      "limit": 10
    }
  }
}
Example result
{
  "contacts": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000201",
      "name": "Dana Whitfield",
      "title": "Facilities Manager",
      "employer": "Lakeside Property Services",
      "location": "Dallas, TX"
    }
  ],
  "note": null
}

Refusal codes

NO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

Find contacts by name or employer across everything visible to you — 'Jimmy at JLL' without already holding an id. Returns id, name, title, employer, and location; emails/phones stay behind the reveal rules (use greenfinch_get_contact_relationships to see their properties, greenfinch_reveal_contact for channels). Unmetered. Mirrors the app's contact search fences exactly (deliverability, provenance, directory visibility, your territory).

WritesCosts creditsUses a daily limit

Reveals one contact's details (name, email, phone, LinkedIn, title, employer) without unlocking a whole property. Use it when you want one specific person rather than everyone at a property.

Cost
5 credits, unless the contact is already covered: you revealed it before, you unlocked one of its properties, or your plan covers its county. Covered contacts cost 0.
Daily limit
Counts toward the daily contact-reveal limit.
ArgumentTypeDescription
contactIdrequiredstring—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_reveal_contact",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000011"
    }
  }
}
Example result
{
  "contact": {
    "id": "3f2a9c1e-0000-4000-8000-000000000011",
    "fullName": "Dana Whitfield",
    "email": "dana.whitfield@example.com",
    "phone": "(214) 555-0142",
    "phoneLabel": "Direct",
    "phoneFallbackFromEmployer": false,
    "linkedinUrl": "https://www.linkedin.com/in/example-dana-whitfield",
    "title": "Director of Facilities",
    "employerName": "Northgate Business Park LLC"
  },
  "creditsCharged": 5,
  "alreadyRevealed": false
}

Refusal codes

IDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYNOT_FOUNDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDINSUFFICIENT_CREDITSPAYMENT_FAILEDACTION_IN_PROGRESSORG_SUSPENDEDNO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Reveal one contact not already covered by a property unlock (5 credits, skipped if already revealed).

Read-only

Lists the owner and property-management firms that hold at least one property in your visible territory. Use it to find firms by name, role, county, or portfolio size before drilling into one with greenfinch_get_organization.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
rolestring (one of 5)One of: owner, property_manager, operator, tenant, any.
countyFipsstring[]5-digit county FIPS codes.
querystringSubstring match on the firm's name.
minPropertiesintegerOnly firms with at least this many in-territory properties.
sort"propertyCount" | "name"Default name.
limitintegerMax rows, default 25, max 200.
offsetintegerRows to skip.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_browse_organizations",
    "arguments": {
      "role": "owner",
      "countyFips": [
        "48085"
      ],
      "query": "Northgate",
      "minProperties": 2,
      "sort": "propertyCount",
      "limit": 25,
      "offset": 0
    }
  }
}
Example result
{
  "organizations": [
    {
      "organization_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "name": "Northgate Business Park LLC",
      "domain": "example.com",
      "roles": [
        "owner",
        "property_manager"
      ],
      "property_count_in_territory": 7,
      "researched": true
    },
    {
      "organization_id": "3f2a9c1e-0000-4000-8000-000000000002",
      "name": "Northgate Retail Holdings LP",
      "domain": null,
      "roles": [
        "owner"
      ],
      "property_count_in_territory": 3,
      "researched": false
    }
  ],
  "total_matching": 2,
  "scope": {
    "scoped": true,
    "countyCount": 4,
    "states": [
      "TX"
    ]
  }
}

Refusal codes

FEATURE_GATEDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

The app's Organizations page: the firms linked to at least one property in your visible territory — owners, property managers, operators (a business that runs a site it does not own and decides its upkeep) and tenants (recorded, never a property's buyer). Filter by role, county (FIPS), a name substring, and a minimum property count; sort by propertyCount (most first) or name. Unmetered. `total_matching` is the true count behind any cap; `researched` is whether Greenfinch has enriched the firm's own record (domain/socials), independent of any property reveal. `property_count_in_territory` here counts the same way the app's own Organizations page does — every visible property-organization EDGE, including a constituent sub-parcel counted alongside its parent — which can be HIGHER than `greenfinch_get_organization`'s `property_count_in_territory` for the same firm, since that tool counts canonical properties only (a constituent's edge is dropped, not double-counted with its parent).

Read-only

Returns one firm's detail: name, domain, roles, social handles, how many of its properties you can see (and how many are researched or revealed), its first few properties, and a count of its contacts by role type. Where switched on, it can also count the firm's people Greenfinch already knows managing properties in one county's market. Use it after finding a firm with greenfinch_browse_organizations; it never returns contact names.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
organizationIdrequiredstringOrganization UUID.
marketCountyFipsstring5-digit county FIPS: also count the firm's people Greenfinch already knows in this county's market.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_organization",
    "arguments": {
      "organizationId": "3f2a9c1e-0000-4000-8000-000000000001"
    }
  }
}
Example result
{
  "organization": {
    "organization_id": "3f2a9c1e-0000-4000-8000-000000000001",
    "name": "Northgate Business Park LLC",
    "domain": "example.com",
    "roles": [
      "owner",
      "property_manager"
    ],
    "socials": {
      "linkedin": "northgate-business-park-example",
      "twitter": null,
      "facebook": null,
      "crunchbase": null
    }
  },
  "property_count_in_territory": 7,
  "researched_property_count": 5,
  "revealed_property_count": 2,
  "properties": [
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000011",
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX",
      "role": "owner"
    },
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000012",
      "address": "1250 Commerce Pkwy",
      "city": "Plano",
      "state": "TX",
      "role": "property_manager"
    }
  ],
  "properties_truncated": false,
  "contacts_by_role": [
    {
      "role_type": "property_management",
      "count": 4
    },
    {
      "role_type": "other_unclassified",
      "count": 1
    }
  ]
}

Refusal codes

FEATURE_GATEDNOT_FOUNDOUT_OF_TERRITORYNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDNOT_ENABLED
Full description(the text AI assistants read)

One firm's detail: name, domain, roles (owner, property_manager, operator, tenant), how many of its properties are in your visible territory and how many of those are researched/revealed, socials if on record, the first properties in the compact search-row shape, and its contacts as COUNTS by role type only (never names). With `marketCountyFips`, also `contacts_known_in_market`: how many of the firm's people Greenfinch already knows managing a property (property-manager, facilities or operator role) in that county, and elsewhere in its metro area — list and rank them with greenfinch_browse_contacts (organizationId, marketCountyFips, sort marketRank); this market view is available only where Greenfinch has switched it on. Unmetered. Refuses NOT_FOUND (no such organization) or OUT_OF_TERRITORY (the organization exists but nothing it touches is visible to you, or the county is outside your territory).

Read-only

Finds contacts in your territory by role type, job title, employer name, firm, county, or whether you have already revealed them. Rows describe the person (title, role, seniority, employer, property count) without ever including their name, email, phone, or LinkedIn URL; use greenfinch_get_contact or greenfinch_reveal_contact for those. Where switched on, a firm's people can also be ranked by how well Greenfinch already knows them in one county's market.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
roleTypestringContact role-type taxonomy key (see contact-role-taxonomy).
titleTextstringSubstring match on the contact's title.
countyFipsstring[]5-digit county FIPS codes, matched via the contact's attached properties.
revealedState"revealed" | "locked" | "any"Default any.
employerTextstringSubstring match on the contact's employer name.
organizationIdstringOrganization UUID: only that firm's people (a current employment record at the firm, or, with marketCountyFips, anyone the market ranking ties to the firm).
marketCountyFipsstring5-digit county FIPS, with organizationId: mark and rank the firm's people Greenfinch already knows in this county's market.
sort"propertyCount" | "title" | "employerName" | "marketRank"Default employerName. marketRank needs organizationId and marketCountyFips: strongest market evidence first, then everyone else.
limitintegerMax rows, default 25, max 200.
offsetintegerRows to skip.
changedKinds"contact_departure" | "contact_title_change" | "contact_employer_change"[]Only people with a recorded change of one of these kinds: contact_departure (the person left the employer we showed for them), contact_title_change (their title changed, seen on their own public listing or our re-check of their profile), contact_employer_change (our re-check of their profile shows a different employer). Combine with changedWithinDays; call greenfinch_get_changes for the evidence. Available once change filters (signals) are switched on for Greenfinch; until then a call that passes this is refused with SIGNALS_NOT_ENABLED, never run without it.
changedWithinDaysintegerOnly changes the product detected within this many days (1 to 3650). Alone, it matches any of the kinds above. Available once change filters (signals) are switched on for Greenfinch; until then a call that passes this is refused with SIGNALS_NOT_ENABLED, never run without it.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_browse_contacts",
    "arguments": {
      "roleType": "property_management",
      "titleText": "manager",
      "countyFips": [
        "48085"
      ],
      "revealedState": "locked",
      "employerText": "Northgate",
      "sort": "propertyCount",
      "limit": 25,
      "offset": 0
    }
  }
}
Example result
{
  "contacts": [
    {
      "contact_id": "3f2a9c1e-0000-4000-8000-000000000041",
      "title": "Senior Property Manager",
      "role_type": "property_management",
      "seniority": "manager",
      "employer_name": "Northgate Business Park LLC",
      "property_count_in_territory": 5,
      "revealed": false,
      "email_validated": true,
      "has_phone": true,
      "identity_not_confirmed": false
    },
    {
      "contact_id": "3f2a9c1e-0000-4000-8000-000000000042",
      "title": "Regional Property Manager",
      "role_type": "property_management",
      "seniority": "director",
      "employer_name": "Northgate Business Park LLC",
      "property_count_in_territory": 3,
      "revealed": false,
      "email_validated": false,
      "has_phone": false,
      "identity_not_confirmed": false
    }
  ],
  "total_matching": 2
}

Refusal codes

FEATURE_GATEDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDSIGNALS_NOT_ENABLEDOUT_OF_TERRITORYNOT_ENABLEDINVALID_ARGUMENTS
Full description(the text AI assistants read)

The app's Contacts page filters: role type, a title substring, county (FIPS), reveal state, and an employer substring; sort by propertyCount, title, or employerName. Every row is a derivative — id, title, role/seniority, employer NAME (firms are not PII), an in-territory property count, and three booleans (revealed, email_validated, has_phone) — NEVER a contact's full name, email, phone, or LinkedIn URL. `organizationId` limits the rows to one firm's people. With `organizationId` AND `marketCountyFips`, each row also says whether Greenfinch already knows the person in that county's market (`known_in_market`: "county" when they manage, in a property-manager, facilities or operator role, a property in that county; "market" when only elsewhere in its metro area; null otherwise) and their `market_rank` (1 = strongest evidence), and `sort: "marketRank"` lists the firm's people in that order; this market view is available only where Greenfinch has switched it on. Unmetered. `total_matching` is the true count behind any cap.

WritesUses a daily limit

Returns one contact's profile: title, role, seniority, employer, data-quality flags, and the properties they are linked to. Their name, email, phone, and LinkedIn URL are included only if your organization has already revealed this contact; otherwise the response shows the reveal price instead.

Cost
Never charges credits. If the contact is visible only because your plan covers its geography (not a paid per-contact reveal), each successful call counts against your organization's daily agent contact-reveal limit. Unrevealed contacts cost nothing and show reveal_price_credits (currently 5).
Daily limit
Counts toward the daily contact-reveal limit.
ArgumentTypeDescription
contactIdrequiredstringContact UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_contact",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000041"
    }
  }
}
Example result
{
  "contact_id": "3f2a9c1e-0000-4000-8000-000000000041",
  "title": "Senior Property Manager",
  "role_type": "property_management",
  "seniority": "manager",
  "employer_name": "Northgate Business Park LLC",
  "email_validated": true,
  "has_phone": true,
  "identity_not_confirmed": false,
  "revealed": true,
  "relationships": [
    {
      "in_your_territory": true,
      "property_id": "3f2a9c1e-0000-4000-8000-000000000011",
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX"
    },
    {
      "in_your_territory": false,
      "state": "OK",
      "county_fips": "40109",
      "coverage_request_tool": "greenfinch_request_coverage"
    }
  ],
  "fullName": "Dana Whitfield",
  "email": "dana.whitfield@example.com",
  "phone": "(972) 555-0142",
  "phoneLabel": "Direct",
  "phoneFallbackFromEmployer": false,
  "linkedinUrl": "https://www.linkedin.com/in/example-dana-whitfield"
}

Refusal codes

FEATURE_GATEDNOT_FOUNDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDROLE_NOT_PERMITTEDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

One contact as a derivative: title, role/seniority, employer name, data-quality booleans (including `identity_not_confirmed`: the provider identity check refused this person's only match, so the title and employer are research's, unconfirmed), and in-territory property relationships (boundary-teaser shaped, same as greenfinch_get_contact_relationships) — PLUS full name, email, phone, and LinkedIn URL, but ONLY once your org has revealed this contact (the exact check greenfinch_reveal_contact charges against). Unrevealed: those four fields are simply absent, `revealed` is false, and `reveal_price_credits` names the cost. Unmetered — this never charges a reveal itself — but a disclosure covered only by a geography subscription (not a durable per-item reveal/unlock) still draws down the org's daily contact-reveal cap, same as greenfinch_reveal_contact — this tool is therefore classified `spending`, not a pure read: a read-only-role member's agent is refused, and agent hosts are told to confirm before running it. Refuses NOT_FOUND for a nonexistent, suppressed, or otherwise unreachable contact (info-hiding, matching every other contact-keyed tool).

Research

Run and track AI research on properties, contacts and organizations.

WritesCosts creditsUses a daily limit

Returns a contact's researched details. If the contact has never been researched, it first runs a live lookup to find their email, phone and LinkedIn. Use it when you already have access to a contact through a property unlock or reveal and want their current details.

Cost
Free. It works only for contacts your organization already has access to (a property unlock, a contact reveal, or a county subscription). Without access it refuses and tells you what to buy; it never charges.
Daily limit
Counts toward the daily contact-reveal limit.
ArgumentTypeDescription
contactIdrequiredstringContact UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_research_contact",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000011"
    }
  }
}
Example result
{
  "contact": {
    "id": "3f2a9c1e-0000-4000-8000-000000000011",
    "fullName": "Dana Whitfield",
    "email": "dana.whitfield@example.com",
    "phone": "(214) 555-0142",
    "phoneLabel": "Direct",
    "phoneFallbackFromEmployer": false,
    "linkedinUrl": "https://www.linkedin.com/in/example-dana-whitfield",
    "title": "Director of Facilities",
    "employerName": "Northgate Business Park LLC"
  },
  "creditsCharged": 0,
  "alreadyRevealed": true,
  "revealOnly": true
}

Refusal codes

IDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYNOT_FOUNDSUBSCRIPTION_PAYMENT_FAILEDNO_NAMEPROPERTY_UNLOCK_REQUIREDCONTACT_REVEAL_REQUIREDCONTACT_RESEARCH_REQUIREDARGUMENT_REMOVEDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDFEATURE_GATEDENRICHMENT_NO_DATAINSUFFICIENT_CREDITSORG_SUSPENDEDNO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Research/enrich one contact — the same live lookup the app's 'Research Contact' button runs, which queries Greenfinch's contact-data sources in turn until one returns a match. Included free with a property unlock or contact reveal (FLAT-10); if this org has neither, returns a 402-equivalent refusal (PROPERTY_UNLOCK_REQUIRED / CONTACT_REVEAL_REQUIRED) instead of charging. Already-researched data is returned as-is. A contact that has never been researched is filled live; if this org's access to it is a county subscription only, that first fill refuses with CONTACT_RESEARCH_REQUIRED (the paid Deep Research action, greenfinch_deep_research_contact). Re-running research on a contact that already has it is not available here.

WritesCosts credits

Looks up a company by name and/or website domain and returns its profile: industry, headcount, founding year, location, LinkedIn and logo. Use it to learn about an owner or management firm before outreach.

Cost
2 credits when a profile is found. Free if your organization already researched the company matched by that domain, or if no data could be found.
ArgumentTypeDescription
namestringOrganization name.
domainstringOrganization domain (e.g. acme.com).
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_research_organization",
    "arguments": {
      "name": "Northgate Business Park LLC",
      "domain": "example.com"
    }
  }
}
Example result
{
  "organization": {
    "id": "3f2a9c1e-0000-4000-8000-000000000021",
    "name": "Northgate Business Park LLC",
    "domain": "example.com",
    "description": "Owner and operator of suburban office parks in North Texas.",
    "industry": "Real Estate",
    "employees": 45,
    "employeesRange": "11-50",
    "foundedYear": 2004,
    "city": "Plano",
    "state": "TX",
    "country": "United States",
    "linkedinHandle": "example-northgate-business-park",
    "logoUrl": "https://example.com/logo.png",
    "enrichmentSource": "provider"
  },
  "enrichment": {
    "found": true,
    "freshlyFetched": true,
    "source": "provider",
    "isNew": true,
    "matchedBy": "domain"
  },
  "creditsCharged": 2,
  "alreadyRevealed": false
}

Refusal codes

FEATURE_GATEDIDENTITY_UNRESOLVEDINSUFFICIENT_CREDITSORG_SUSPENDEDBILLING_NOT_PROVISIONEDNO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Research/enrich an organization by name and/or domain — the app's 'Research Organization' action: a live company lookup across Greenfinch's company-data sources, queried in turn until one resolves the organization. 2 credits, skipped (creditsCharged: 0) if this org already has the matched organization revealed.

WritesCosts credits

Starts a background Deep Research run on a contact: a fresh live lookup of their details plus web research that produces a condensed outreach summary. Use it before outreach to an important contact, then poll greenfinch_deep_research_status for the result.

Cost
10 credits per run, taken when the run starts processing (seconds after the call) and refunded automatically if the run fails. A call while a run is already in progress costs nothing.
ArgumentTypeDescription
contactIdrequiredstringContact UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_deep_research_contact",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000011"
    }
  }
}
Example result
{
  "runId": "3f2a9c1e-0000-4000-8000-000000000081",
  "status": "running",
  "costCredits": 10,
  "note": "Deep Research runs in the background and typically takes a few minutes. Credits are debited when it starts processing (seconds from now), refunded automatically if it fails outright. Poll greenfinch_deep_research_status with this contactId to check progress and read the result."
}

Refusal codes

IDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYNOT_FOUNDPROPERTY_UNLOCK_REQUIREDCONTACT_REVEAL_REQUIREDFEATURE_GATEDINSUFFICIENT_CREDITSTEMPORARILY_UNAVAILABLENO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Launch Deep Research on a contact — the app's 'Deep Research' action: a forced live re-fetch from Greenfinch's contact-data sources plus a web-grounded AI strategy pass, run in the background (typically a few minutes). Flat 10 credits, debited when the run starts processing (seconds after this call returns) and refunded automatically if the run fails outright — not charged at THIS call, but not deferred to completion either; a zero-balance org is refused here at launch instead. Requires this org to already have the contact revealed (unlock its property or reveal it standalone first). Returns a runId immediately; poll greenfinch_deep_research_status with the SAME contactId for progress and the result. Calling this again while a run is already in flight for this contact returns that run's status instead of starting a second one. The result is a condensed outreach summary, never the full write-up — see greenfinch_deep_research_status.

Read-only

Returns the progress of a contact's Deep Research run and, once it finishes, a condensed outreach summary: a one-line reason to reach out, a few talking points, and the contact's title and employer. Use it to poll a run started with greenfinch_deep_research_contact.

Cost
Free.
ArgumentTypeDescription
contactIdrequiredstringContact UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_deep_research_status",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000011"
    }
  }
}
Example result
{
  "runId": "3f2a9c1e-0000-4000-8000-000000000081",
  "status": "complete",
  "outreachBrief": {
    "whyThisPerson": "Oversees a 2026 renovation of the east office building",
    "talkingPoints": [
      "East building renovation underway",
      "Recently consolidated vendors across three sites"
    ],
    "contactTitle": "Director of Facilities",
    "contactEmployer": "Northgate Business Park LLC"
  },
  "note": "This is a condensed outreach summary, not the full Conversation Strategy. The complete write-up (detailed reasoning, proof points, sources, portfolio sizing) is viewable on this contact's page in the Greenfinch app — it is not returned over MCP by design (derivative-only egress; see docs/architecture/mcp-agent-surface.md).",
  "model": "example-model-id",
  "generatedAt": "2026-09-14T15:00:00.000Z"
}

Refusal codes

IDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYNOT_FOUNDNO_ACTIVE_SEAT
Full description(the text AI assistants read)

Check the status/result of this contact's Deep Research run, launched with greenfinch_deep_research_contact — mirrors GET /api/contacts/[id]/sales-brief's deep half. status is 'not_started' | 'running' | 'complete' | 'error'. On 'complete', returns a CONDENSED outreachBrief (a handful of talking points, a one-line reason, the contact's title/employer) — never the full write-up, which stays viewable on the contact's page in the app.

WritesCosts creditsNeeds a per-user connection

Writes a first-touch outreach email (subject and body) for a contact, based on the contact's conversation strategy and your organization's email templates. Use it once you have access to a contact and want a ready-to-edit intro email.

Cost
5 credits per draft generated; a new draft with different steering is charged again. Retrying with the same requestId returns the earlier draft for free.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
contactIdrequiredstringContact UUID.
steeringstringOptional free-text instruction, max 500 chars.
requestIdstringIdempotency token (UUID) — reuse on retry to avoid a duplicate charge.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_draft_email",
    "arguments": {
      "contactId": "3f2a9c1e-0000-4000-8000-000000000011",
      "steering": "Mention the east building renovation.",
      "requestId": "3f2a9c1e-0000-4000-8000-000000000091"
    }
  }
}
Example result
{
  "draft": {
    "subject": "Supporting the east building renovation at Northgate",
    "body": "Hi Dana,\n\nI saw that Northgate is renovating its east office building this year. We help facilities teams in Plano keep common areas running smoothly during construction.\n\nWould a 15-minute call next week be useful?\n\nBest,\nJordan"
  },
  "mailto": {
    "fit": "ok",
    "requiresFallback": false
  },
  "wordCount": 42,
  "wordBudget": 150,
  "creditsCharged": 5,
  "strategyGrade": "simple"
}

Refusal codes

ACTING_USER_REQUIREDIDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYNOT_FOUNDPROPERTY_UNLOCK_REQUIREDCONTACT_REVEAL_REQUIREDCONTACT_RELATIONSHIP_STALESTRATEGY_REQUIREDFEATURE_GATEDDRAFT_REJECTEDINSUFFICIENT_CREDITSORG_SUSPENDEDNO_ACTIVE_SEATSUBSCRIPTION_PAYMENT_FAILEDCREDIT_ACTION_IN_PROGRESSCREDIT_ACTION_RECOVERY_REQUIREDPAID_REVEAL_PERSISTENCE_FAILEDROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Draft a first-touch outreach email for a contact from its Conversation Strategy (deep preferred; if neither a deep nor a simple strategy exists yet, this call generates the free simple one itself — the same generator the app's contact page runs on first view — then drafts from that, still one charge total) — the app's 'Draft Email' action. 5 credits per generation (re-drafting with different steering is a fresh charge; pass the SAME requestId to replay a prior generation for free instead of re-charging). Requires: the contact revealed, and a per-user OAuth connection — an org-level credential is refused, since every draft is attributed to its human author. Returns ONLY the drafted subject/body plus delivery metadata and which strategy grade ('simple' or 'deep') it drafted from — never the contact's email address or the strategy content itself. A 'simple' grade means greenfinch_deep_research_contact has not run yet; consider running it for a stronger draft.

WritesCosts credits

Starts AI research on a batch of properties: given ids, property keys, or every property on a saved list. Call it with dryRun: true first to see exactly what would launch and what it would cost, then call again without dryRun to launch, and poll greenfinch_research_status with the returned batchId.

Cost
10 credits per property actually launched (the per-property price is returned as perPropertyCost). Skipped properties are not charged. A dryRun call is free.
ArgumentTypeDescription
propertyIdsstring[]Property UUIDs.
propertyKeysstring[]Property keys.
listIdstringResearch every property on this saved list (from greenfinch_list_lists / greenfinch_get_list) — instead of enumerating ids.
mode"unresearched_only" | "refresh_all"—
dryRunbooleantrue = price the batch WITHOUT launching or charging: launched/skipped breakdown and exact credit cost. Always dry-run first for a batch whose cost you have not confirmed with the user.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_start_research",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001",
      "mode": "unresearched_only",
      "dryRun": true
    }
  }
}
Example result
{
  "dryRun": true,
  "mode": "unresearched_only",
  "listName": "Plano office parks - Q4 outreach",
  "hiddenFromYou": 0,
  "wouldLaunch": 18,
  "skippedResearched": 5,
  "skippedIneligible": 2,
  "skippedOwnerSuppressed": 1,
  "skippedInFlight": 0,
  "perPropertyCost": 10,
  "estimatedCredits": 180,
  "note": "Nothing was launched or charged. Repeat the call without dryRun to launch exactly this batch."
}

Refusal codes

FEATURE_GATEDTEMPORARILY_UNAVAILABLEAMBIGUOUS_SELECTIONIDENTITY_UNRESOLVEDLIST_NOT_FOUNDWRONG_LIST_TYPEEMPTY_SELECTIONBATCH_TOO_LARGEBATCH_ALREADY_RUNNINGRESEARCH_LAUNCH_BUSYNO_VISIBLE_TERRITORYORG_SUSPENDEDSUSPENSION_CHECK_UNAVAILABLEINSUFFICIENT_CREDITSSUBSCRIPTION_PAYMENT_FAILEDNO_BATCH_PROPERTIESBATCH_LAUNCH_RECONCILIATION_REQUIREDBILLING_NOT_PROVISIONED
Full description(the text AI assistants read)

Launch AI property research on a set of properties or a whole saved list (10 credits per property launched). 'unresearched_only' (default) skips already-researched properties; 'refresh_all' also re-runs every already-researched property that isn't currently mid-research — there is no time-based cooldown, so check each property's research date and model (from greenfinch_get_property) before deciding whether refreshing it is worth the credits. Pass dryRun:true to get the exact cost and launch/skip breakdown WITHOUT launching or charging — do this first whenever the user has not confirmed the spend. Returns a batchId to poll with greenfinch_research_status.

Read-only

Reports progress on a research batch started with greenfinch_start_research: the overall status, completed/failed/active counts, and a status for each property. Poll it until status is completed, partial or failed.

Cost
Free.
ArgumentTypeDescription
batchIdrequiredstring—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_research_status",
    "arguments": {
      "batchId": "batch_example_0001"
    }
  }
}
Example result
{
  "batchId": "batch_example_0001",
  "status": "processing",
  "totalCount": 18,
  "completedCount": 11,
  "failedCount": 1,
  "activeCount": 6,
  "createdAt": "2026-09-14T15:10:00.000Z",
  "updatedAt": "2026-09-14T15:22:41.000Z",
  "items": [
    {
      "entityId": "3f2a9c1e-0000-4000-8000-000000000011",
      "entityName": "Northgate Business Park",
      "status": "completed",
      "error": null
    },
    {
      "entityId": "3f2a9c1e-0000-4000-8000-000000000013",
      "entityName": "1200 Commerce Pkwy",
      "status": "failed",
      "error": "Research could not be completed for this property."
    }
  ]
}

Refusal codes

NOT_FOUND
Full description(the text AI assistants read)

Check the status of a research batch started with greenfinch_start_research.

Read-only

Lists your organization's past research runs in two separately paged sections: property research batches and contact Deep Research runs, each with status and credits. Use it to review what has already been researched and what it cost.

Cost
Free.
ArgumentTypeDescription
kind"property_batches" | "deep_research"—
limitintegerMax rows per section, default 25, max 100.
propertyBatchesCursorstringFrom a prior call's next_cursor.
deepResearchCursorstringFrom a prior call's next_cursor.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_research_history",
    "arguments": {
      "limit": 2
    }
  }
}
Example result
{
  "property_batches": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000050",
      "label": "Office parks – Somerset County",
      "status": "completed",
      "total_count": 25,
      "completed_count": 24,
      "failed_count": 1,
      "credits_charged": 240,
      "created_at": "2026-09-10T13:00:00.000Z",
      "updated_at": "2026-09-10T13:42:00.000Z"
    }
  ],
  "property_batches_next_cursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA5LTEwVDEzOjAwOjAwLjAwMFoiLCJpZCI6IjNmMmE5YzFlLTAwMDAtNDAwMC04MDAwLTAwMDAwMDAwMDA1MCJ9",
  "deep_research": [
    {
      "run_id": "3f2a9c1e-0000-4000-8000-000000000060",
      "contact_id": "3f2a9c1e-0000-4000-8000-000000000070",
      "status": "complete",
      "credits_charged": 10,
      "created_at": "2026-09-11T16:20:00.000Z"
    }
  ],
  "deep_research_next_cursor": null
}

Refusal codes

INVALID_CURSORIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

This org's past research runs, as two independently-paged sections: property_batches (greenfinch_start_research launches, with status/counts) and deep_research (greenfinch_deep_research_contact launches, with status and contact_id — no contact name, since this history is not territory-fenced; pass contact_id to greenfinch_reveal_contact to fetch the contact if it is still reachable). property_batches is scoped like the app's own research-history page: a per-person connection that is NOT an org admin sees only its OWN batches, with internal adjudication re-run rows hidden; an org-level credential or an org admin sees every batch in the org. Pass kind to fetch only one section (paging its own cursor); omit it to get the first page of both. Every row carries credits_charged — that exact spelling, not creditsCharged. On a deep_research row it is the charge recorded for that run. On a property_batches row it is NOT read back from the billing ledger: it is the batch's completed-item count multiplied by the standard per-property research price (greenfinch_get_price_sheet names that price), so treat it as an upper bound — it reads higher than the amount actually billed whenever a completed item was not charged for, for instance because its charge was refunded. Unmetered.

Read-only

Quotes what a research launch would cost without launching or charging anything, for a batch of properties, an organization lookup, or a contact Deep Research run. Use it to show the user the exact price before they approve the spend.

Cost
Free. It never launches or charges.
ArgumentTypeDescription
kindrequired"property_batch" | "organization" | "deep_research_contact"—
propertyIdsstring[]—
propertyKeysstring[]—
listIdstring—
mode"unresearched_only" | "refresh_all"—
namestring—
domainstring—
contactIdstring—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_price_research",
    "arguments": {
      "kind": "property_batch",
      "propertyIds": [
        "3f2a9c1e-0000-4000-8000-000000000010",
        "3f2a9c1e-0000-4000-8000-000000000011",
        "3f2a9c1e-0000-4000-8000-000000000012"
      ],
      "mode": "unresearched_only"
    }
  }
}
Example result
{
  "kind": "property_batch",
  "mode": "unresearched_only",
  "would_launch": 2,
  "skipped_researched": 1,
  "skipped_ineligible": 0,
  "skipped_owner_suppressed": 0,
  "skipped_in_flight": 0,
  "per_property_cost": 10,
  "estimated_credits": 20,
  "worst_case": false
}

Refusal codes

FEATURE_GATEDAMBIGUOUS_SELECTIONIDENTITY_UNRESOLVEDLIST_NOT_FOUNDWRONG_LIST_TYPEBATCH_TOO_LARGENO_VISIBLE_TERRITORYNOT_FOUNDPROPERTY_UNLOCK_REQUIREDCONTACT_REVEAL_REQUIRED
Full description(the text AI assistants read)

Dry-run price for a research launch, without launching or charging — for a property batch (ids/keys/listId, same args as greenfinch_start_research minus dryRun), an organization research (name/domain), or a Deep Research launch on a contact. Uses the SAME classification/gates each real launch tool checks, never a re-derived estimate. For organization research with no existing domain match, the price reported is a WORST CASE (the real call may resolve free if the organization turns out already revealed) — this is called out in the response. Unmetered.

WritesCosts credits

Re-runs AI research on a property that has already been researched, to pick up newer information, for a flat 10 credits. Call it with dryRun:true first to confirm the price without launching or charging anything.

Cost
10 credits (property_ai_research) per launch, every time, with no cooldown. dryRun:true is free.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
reasonstringOptional context for why you're refreshing this.
dryRunbooleantrue = report the exact price (10 credits) WITHOUT launching or charging.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_refresh_research",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
      "reason": "Tenant roster looks out of date",
      "dryRun": false
    }
  }
}
Example result
{
  "jobId": "3f2a9c1e-0000-4000-8000-000000000030",
  "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
  "creditsCharged": 10,
  "alreadyRevealed": true,
  "status": "enriching"
}

Refusal codes

RATE_LIMITEDTEMPORARILY_UNAVAILABLEFEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORYNOT_YET_RESEARCHEDALREADY_RESEARCHINGRESEARCH_LAUNCH_BUSYOWNER_SUPPRESSED_NO_RESEARCHORG_SUSPENDEDSUSPENSION_CHECK_UNAVAILABLEINSUFFICIENT_CREDITSSUBSCRIPTION_PAYMENT_FAILEDBILLING_NOT_PROVISIONEDNO_ACTIVE_SEAT
Full description(the text AI assistants read)

Re-run AI research on a property that has ALREADY been researched — the same "Update Research" action the property detail page offers, wrapping the identical claim/charge/enqueue launch POST /api/enrich uses for a re-run (10 credits, flat, every time — there is no time-based cooldown, so check the property's existing research date/model with greenfinch_get_property before deciding whether refreshing is worth the credits). Pass dryRun:true to see the exact price WITHOUT launching or charging — do this first whenever the user has not confirmed the spend. Refuses ALREADY_RESEARCHING if this property already has a run in flight (from this tool, greenfinch_start_research, or the app) — poll or wait rather than retrying. A property with no prior research at all refuses NOT_YET_RESEARCHED — use greenfinch_start_research instead, which is unmetered to dry-run and correctly modeled for a first pass.

WritesNeeds a per-user connection

Stops a property-research batch you personally started while it is still running, refunding the properties it had not processed yet. It needs a per-user connection and never cancels a batch someone else started.

Cost
Free. Unprocessed properties in the batch are refunded; a property already mid-run finishes and bills normally.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
batchIdrequiredstring—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_cancel_research",
    "arguments": {
      "batchId": "3f2a9c1e-0000-4000-8000-000000000040"
    }
  }
}
Example result
{
  "batchId": "3f2a9c1e-0000-4000-8000-000000000040",
  "cancelled": true,
  "processedBeforeCancel": 7,
  "totalInBatch": 25,
  "message": "Batch cancelled"
}

Refusal codes

PERMISSIONFEATURE_GATEDBATCH_NOT_ACTIVENOT_YOUR_BATCHCANCEL_FAILED
Full description(the text AI assistants read)

Stop a property-research batch YOU personally started with greenfinch_start_research (or from the app), while it's still running — never a batch another member of your organization or Greenfinch staff started, even though it may be the only batch your org has active right now (founder ruling 2026-09-05: cancel is scoped to your own runs, the same as every other per-person action on this surface). Requires a per-person connection — an org-level credential has no acting user to check ownership against and always refuses PERMISSION. Wraps the same cancel primitive the admin console's own run-monitor kill switch uses: drains this batch's not-yet-processed jobs (an already-executing property finishes on its own — it will still bill or fail normally), marks the batch failed, and refunds every unprocessed property's charge. Refuses BATCH_NOT_ACTIVE if batchId is not this org's currently running batch (already finished, or never existed), and NOT_YOUR_BATCH if it IS currently running but was started by someone else.

Lists

Build and manage saved lists.

Read-only

Lists your saved property or contact lists with their item counts. Use it to find a list's id before reading or editing it.

Cost
Free.
ArgumentTypeDescription
type"properties" | "contacts"—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_list_lists",
    "arguments": {
      "type": "properties"
    }
  }
}
Example result
{
  "lists": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000301",
      "listName": "Plano office targets Q4",
      "listType": "properties",
      "visibility": "private",
      "ownerName": "Jordan Example",
      "itemCount": 42,
      "createdAt": "2026-09-01T17:30:00.000Z"
    }
  ]
}

Refusal codes

IDENTITY_UNRESOLVED
Full description(the text AI assistants read)

List saved lists (properties or contacts) with item counts. An org-level credential sees every list in the org; when connected as a specific user, only the lists that user can see in the app (their own, plus team-shared lists where the org plan allows).

Read-only

Reads a saved list's members. Property lists return search-style rows plus each property's pipeline status; contact lists return contact ids you can pass to the contact tools.

Cost
Free.
ArgumentTypeDescription
listIdrequiredstringList UUID from greenfinch_list_lists.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_list",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000301"
    }
  }
}
Example result
{
  "list": {
    "id": "3f2a9c1e-0000-4000-8000-000000000301",
    "name": "Plano office targets Q4",
    "type": "properties",
    "visibility": "private",
    "created_at": "2026-09-01T17:30:00.000Z"
  },
  "item_count": 3,
  "items": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000001",
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX",
      "zip": "75074",
      "county": "Collin",
      "lat": 33.0198,
      "lon": -96.6989,
      "owner": "Northgate Business Park LLC",
      "primaryOwner": "Northgate Business Park LLC",
      "totalParval": 18450000,
      "yearBuilt": 2004,
      "lotSqft": 217800,
      "buildingSqft": 96000,
      "numFloors": 4,
      "assetCategory": "Office",
      "assetSubcategory": "Office Building",
      "aiRationale": "Four-story multi-tenant office building on a landscaped campus...",
      "commonName": "Northgate Business Park",
      "enrichmentStatus": "completed",
      "assessorBizName": null,
      "assessorOwnerName1": "NORTHGATE BUSINESS PARK LLC",
      "isParentProperty": false,
      "parentPropertyId": null,
      "constituentAccountNums": null,
      "constituentCount": 0,
      "constituentsExplorable": false,
      "pipeline": {
        "status": "qualified",
        "deal_value": 48000,
        "changed_at": "2026-09-13T18:22:04.000Z"
      }
    },
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000002",
      "address": "455 Legacy Dr",
      "city": "Plano",
      "state": "TX",
      "zip": "75024",
      "county": "Collin",
      "lat": 33.0762,
      "lon": -96.8211,
      "owner": "Legacy Row Partners LP",
      "primaryOwner": null,
      "totalParval": 7200000,
      "yearBuilt": 1998,
      "lotSqft": 87120,
      "buildingSqft": 41000,
      "numFloors": 2,
      "assetCategory": "Office",
      "assetSubcategory": "Medical Office",
      "aiRationale": null,
      "commonName": null,
      "enrichmentStatus": "pending",
      "assessorBizName": null,
      "assessorOwnerName1": "LEGACY ROW PARTNERS LP",
      "isParentProperty": false,
      "parentPropertyId": null,
      "constituentAccountNums": null,
      "constituentCount": 0,
      "constituentsExplorable": false,
      "pipeline": {
        "status": "untouched",
        "deal_value": null,
        "changed_at": null
      }
    }
  ],
  "contact_ids": null,
  "hidden_from_you": 1,
  "scope_note": "This list holds 3 items, of which 1 is not currently visible to you (withheld, out of territory, or suppressed) and not shown. The list is intact — your visibility changed. greenfinch_get_entitlement_summary explains what you can see."
}

Refusal codes

LIST_NOT_FOUNDIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

Read a saved list's members. Property lists return full search-shaped rows (same field gating as greenfinch_search_properties) plus each member's pipeline status, so 'which of my list is still untouched' is one call; contact lists return contact ids for use with the contact tools. Items are re-checked against your CURRENT territory: `hidden_from_you` counts members the list still holds that you can no longer see (territory can shrink after items were added) — reported, never silently dropped. A list outside your reach reads as LIST_NOT_FOUND, exactly like the app. A per-person connection that is NOT an org admin sees every member's pipeline `status` (so this list's completeness answer stays correct) but `deal_value` reads null for a property a colleague owns — only your own deals and, for an org admin or an org-level credential, every deal show the dollar figure, matching the app's own list view.

Writes

Creates a new saved list that holds either properties or contacts. Use it before adding items with greenfinch_add_to_list or greenfinch_add_search_results_to_list; set reuseExistingByName to get back an existing list with the same name instead of making a duplicate.

Cost
Free.
ArgumentTypeDescription
listNamerequiredstring—
listTyperequired"properties" | "contacts"—
reuseExistingByNameboolean(default false)
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_create_list",
    "arguments": {
      "listName": "Plano office parks - Q4 outreach",
      "listType": "properties",
      "reuseExistingByName": true
    }
  }
}
Example result
{
  "list": {
    "id": "3f2a9c1e-0000-4000-8000-000000000001",
    "userId": null,
    "clerkOrgId": "org_example0001",
    "listName": "Plano office parks - Q4 outreach",
    "listType": "properties",
    "visibility": "team",
    "listKind": null,
    "createdAt": "2026-09-14T15:04:05.000Z",
    "itemCount": 0
  },
  "created": true
}

Refusal codes

FEATURE_GATEDIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

Create a new saved list of properties or contacts. An org-level credential creates an org-visible team list; when connected as a specific user, the list is created as that user's own private list, exactly as in the app. Set reuseExistingByName to find and return an existing same-named list instead of creating a duplicate.

Writes

Adds up to 500 properties or contacts, by id, to an existing saved list. Before adding, it re-checks that every item is still visible to the caller; items already on the list are counted, not added twice.

Cost
Free.
ArgumentTypeDescription
listIdrequiredstring—
itemIdsrequiredstring[]—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_add_to_list",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001",
      "itemIds": [
        "3f2a9c1e-0000-4000-8000-000000000011",
        "3f2a9c1e-0000-4000-8000-000000000012"
      ]
    }
  }
}
Example result
{
  "added": 1,
  "alreadyExists": 1
}

Refusal codes

IDENTITY_UNRESOLVEDNOT_FOUNDCONTACT_NOT_AVAILABLEPROPERTY_NOT_AVAILABLEFEATURE_GATEDUNKNOWN_ERROR
Full description(the text AI assistants read)

Add one or more properties/contacts to an existing saved list.

Writes

Removes one property or contact from a saved list. Use it to prune a list before running research or exporting it.

Cost
Free.
ArgumentTypeDescription
listIdrequiredstring—
itemIdrequiredstring—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_remove_from_list",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001",
      "itemId": "3f2a9c1e-0000-4000-8000-000000000012"
    }
  }
}
Example result
{
  "success": true
}

Refusal codes

IDENTITY_UNRESOLVEDNOT_FOUND
Full description(the text AI assistants read)

Remove one item from a saved list.

Writes

Gives a saved list a new name. With a per-user connection only the list's owner can rename it; an org-level API key can rename any list in the org.

Cost
Free.
ArgumentTypeDescription
listIdrequiredstringList UUID.
namerequiredstringNew list name.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_rename_list",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001",
      "name": "Plano office parks - priority"
    }
  }
}
Example result
{
  "list": {
    "id": "3f2a9c1e-0000-4000-8000-000000000001",
    "listName": "Plano office parks - priority"
  }
}

Refusal codes

FEATURE_GATEDIDENTITY_UNRESOLVEDNAME_IN_USENOT_FOUND
Full description(the text AI assistants read)

Rename a saved list — app parity for the list detail page's rename action. For a per-person connection, owner-only (the app's own rule: neither other members nor org admins may rename a list they don't own); an org-level credential may rename any list in its org.

Writes

Shares a saved list with the whole team ('team') or makes it private again ('private'). Sharing requires a plan that includes team-shared lists; making a list private does not.

Cost
Free.
ArgumentTypeDescription
listIdrequiredstringList UUID.
visibilityrequired"private" | "team"—
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_set_list_visibility",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001",
      "visibility": "team"
    }
  }
}
Example result
{
  "list": {
    "id": "3f2a9c1e-0000-4000-8000-000000000001",
    "visibility": "team"
  }
}

Refusal codes

FEATURE_GATEDIDENTITY_UNRESOLVEDNOT_FOUND
Full description(the text AI assistants read)

Share ('team') or unshare ('private') a saved list — app parity for the list detail page's share toggle. Sharing (not unsharing) requires this org's Team-shared-lists plan; owner-only for a per-person connection (an org-level credential may share/unshare any list in its org).

greenfinch_add_search_results_to_list

Add Search Results To List

Writes

Runs a property search with the same filters as greenfinch_search_properties and adds the matching properties you can currently see to a saved properties list, up to 500 per call. Use it to build a list from criteria rather than from individual ids.

Cost
Free.
ArgumentTypeDescription
querystringFree-text search across address, city, owner, name.
boundsobject—
filtersobject—
sortBystring (one of 19)Every sort the app's property search offers — works in query mode AND county/bounds mode. Defaults to "relevance". Numeric and date sorts place properties with no value LAST in both directions; the text sorts (commonName, ownerName, address, city, owner) treat a missing value as the highest value, so it sorts last ascending and FIRST descending. "owner" sorts the vendor parcel feed's owner-of-record; "ownerName" sorts the assessor's owner name — different columns. "address" sorts the raw feed address, not the tidied address shown in results. One of: relevance, commonName, lotSqft, buildingSqft, totalUnits, contactCount, landscapableSqft, roofAreaSqft, buildingFootprintSqft, yearBuilt, numFloors, ownerName, propertyValue, updatedAt, lastEnrichedAt, lastSaleDate, address, city, owner.
sortOrder"asc" | "desc"—
verbosity"compact" | "full"compact (default): the decision fields — id, key, address/geo, owner, category, sizes, value, year, teaser. full: adds provenance/plumbing (parcel account numbers, cluster flags, assessor name variants). Rows are ~40% smaller compact; prefer it unless you need the plumbing.
listIdrequiredstringList UUID to add matches to.
maxintegerMax properties to add: 1 to 500, defaulting to 500. A larger value is rejected, not reduced.
41 nested fields(bounds, filters)
ArgumentTypeDescription
bounds.minLatrequirednumber—
bounds.maxLatrequirednumber—
bounds.minLonrequirednumber—
bounds.maxLonrequirednumber—
filters.categoriesstring[]—
filters.subcategoriesstring[]—
filters.countyFipsstring[]5-digit county FIPS codes to search, e.g. ["51760"] for Richmond City, VA. Exact county scoping — use this instead of `bounds` whenever the question is about a county.
filters.zipCodesstring[]—
filters.citiesstring[]—
filters.countiesstring[]State-qualified county slugs (e.g. "middlesex-nj") or legacy bare names. OR-combined with zipCodes/cities, then ANDed with every other filter — matches the app's location panel.
filters.buildingClassesstring[]—
filters.acTypesstring[]—
filters.heatingTypesstring[]—
filters.roofTypesstring[]—
filters.exteriorWallTypesstring[]—
filters.poolTypesstring[]—
filters.fenceTypesstring[]—
filters.garageTypesstring[]—
filters.minLotSqftnumber—
filters.maxLotSqftnumber—
filters.minBuildingSqftnumber—
filters.maxBuildingSqftnumber—
filters.minUnitsintegerDisplayed unit count — researched value when known, else the assessor's.
filters.maxUnitsinteger—
filters.minPropertyValuenumber—
filters.maxPropertyValuenumber—
filters.minYearBuiltnumber—
filters.maxYearBuiltnumber—
filters.minFloorsinteger—
filters.maxFloorsinteger—
filters.minBedroomsinteger—
filters.maxBedroomsinteger—
filters.minBathroomsnumber—
filters.maxBathroomsnumber—
filters.enrichmentStatus"researched" | "not_researched"—
filters.saleRecencyBucketsstring (one of 5)[]e.g. ["3_months", "over_a_year"] — sold or transferred within the last N (the newer of the Last Sold and Last Transfer dates). One of: 1_month, 3_months, 6_months, 12_months, over_a_year.
filters.organizationIdstringProperties linked to this organization. UUID.
filters.contactIdstringProperties linked to this contact. UUID.
filters.changedKinds"ownership_transfer" | "sale" | "manager_change"[]Only properties with a recorded change of one of these kinds: ownership_transfer (the county records a new owner, backed by a newer recorded transfer), sale (a newer sale date was recorded), manager_change (a later research pass found a different managing firm, judged a real change). Combine with changedWithinDays; call greenfinch_get_changes for the evidence. Available once change filters (signals) are switched on for Greenfinch; until then a call that passes this is refused with SIGNALS_NOT_ENABLED, never run without it.
filters.changedWithinDaysintegerOnly changes the product detected within this many days (1 to 3650). Alone, it matches any of the kinds above. Available once change filters (signals) are switched on for Greenfinch; until then a call that passes this is refused with SIGNALS_NOT_ENABLED, never run without it.
filters.leaseTypes"triple_net" | "gross" | "modified_gross" | "ground_lease"[]Only properties whose researched lease arrangement is one of these (triple_net = Triple-net, gross = Gross, modified_gross = Modified gross, ground_lease = Ground lease). Owner-occupied and sale-leaseback are not filterable: they describe who owns the property and are shown on its detail once its research is unlocked. Research records a lease type only when a source it read states it (a leasing flyer, listing or article), so most properties have none and never match; the property's detail carries the source. Available once the lease-type field is switched on for Greenfinch; until then a call that passes this is refused with LEASE_TYPE_NOT_ENABLED, never run without it.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_add_search_results_to_list",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001",
      "filters": {
        "countyFips": [
          "48085"
        ],
        "categories": [
          "Office"
        ],
        "minBuildingSqft": 20000
      },
      "sortBy": "relevance",
      "max": 250
    }
  }
}
Example result
{
  "matched": 250,
  "added": 238,
  "alreadyExists": 12,
  "truncated": false
}

Refusal codes

FEATURE_GATEDIDENTITY_UNRESOLVEDNO_VISIBLE_TERRITORYMISSING_QUERY_BOUNDS_OR_COUNTYAMBIGUOUS_SEARCH_MODENOT_FOUNDPROPERTY_NOT_AVAILABLEWRONG_LIST_TYPEUNKNOWN_ERROR
Full description(the text AI assistants read)

Run a property search (same arguments as greenfinch_search_properties, minus limit/offset/cursor) and add every matching, currently-visible property to a list — bounded by `max` (defaults to 500, which is also the hard ceiling, matching greenfinch_add_to_list's own per-call cap; a `max` above 500 is REJECTED as an invalid argument rather than reduced, so ask for 500 or fewer and call again for the next batch). Reports how many matched, how many were newly added vs. already on the list, and whether the collection was truncated before every match was reached.

Read-only

Shows who added each item on a saved list and when, plus who created the list. Also gives a best-effort flag for whether Greenfinch staff likely set the list up for you. Use listType to know whether the item ids are properties or contacts.

Cost
Free.
ArgumentTypeDescription
listIdrequiredstringList UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_list_provenance",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000001"
    }
  }
}
Example result
{
  "list": {
    "id": "3f2a9c1e-0000-4000-8000-000000000001",
    "listName": "Plano office parks - priority",
    "listType": "properties",
    "createdAt": "2026-09-14T15:04:05.000Z",
    "ownerName": "Dana Whitfield",
    "ownerless": false
  },
  "items": [
    {
      "itemId": "3f2a9c1e-0000-4000-8000-000000000011",
      "addedBy": "Dana Whitfield",
      "addedAt": "2026-09-14T15:06:10.000Z"
    },
    {
      "itemId": "3f2a9c1e-0000-4000-8000-000000000012",
      "addedBy": "agent or Greenfinch staff",
      "addedAt": "2026-09-14T15:07:32.000Z"
    }
  ],
  "hidden_from_you": 2,
  "scope_note": "This list's history holds 4 items, of which 2 are not currently visible to you (withheld, out of territory, or suppressed) and omitted above. The list is intact — your visibility changed.",
  "likelySeededByGreenfinchStaff": false,
  "seededNote": "Best-effort signal derived from this list's own owner and item-attribution columns — not the authoritative staff-side audit record."
}

Refusal codes

FEATURE_GATEDIDENTITY_UNRESOLVEDNOT_FOUND
Full description(the text AI assistants read)

Per-item provenance for a saved list: who added each item (name, or 'agent or Greenfinch staff' when attribution is blank) and when, plus the list's own created-by/at, and a best-effort signal for whether Greenfinch staff likely set this list up on your behalf (derived from the list's own owner/attribution columns — not an authoritative record). `list.listType` ('properties' or 'contacts') says what each `itemId` is: a properties list's item ids are property ids usable with greenfinch_get_property, a contacts list's are contact ids usable with greenfinch_get_contact. Items are re-checked against your CURRENT visibility exactly like greenfinch_get_list: `hidden_from_you` counts members you can no longer see (withheld, out of territory, or — for a contacts list — suppressed) — reported as a count, never named.

Pipeline and CRM

Qualify leads, record outcomes, notes and activity.

Read-only

Shows where properties stand in your organization's sales pipeline: status, deal value, when it changed, and (when you pass property ids) which ones nobody has worked yet. Filter by status to answer questions like 'what did we qualify this week'.

Cost
Free.
ArgumentTypeDescription
propertyIdsstring[]Scope to these properties (max 500) — e.g. a list's members.
statusesstring (one of 7)[]Only these pipeline statuses. One of: new, qualified, attempted_contact, active_opportunity, won, lost, disqualified.
limitintegerMax rows, default 200, max 200.
offsetintegerRows to skip (pages are newest-change first).
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_pipeline",
    "arguments": {
      "propertyIds": [
        "3f2a9c1e-0000-4000-8000-000000000001",
        "3f2a9c1e-0000-4000-8000-000000000002"
      ],
      "limit": 50
    }
  }
}
Example result
{
  "rows": [
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "status": "qualified",
      "deal_value": 48000,
      "changed_at": "2026-09-13T18:22:04.000Z",
      "disqualified_reason": null,
      "lost_reason": null,
      "property_lifecycle": "active",
      "successor_property_id": null
    }
  ],
  "total": 1,
  "untouched_property_ids": [
    "3f2a9c1e-0000-4000-8000-000000000002"
  ],
  "hidden_from_you": 0,
  "unavailable_count": 0
}

Refusal codes

NO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

Where properties stand in this org's pipeline — status, deal value, when it changed, and (when you pass propertyIds) `untouched_property_ids`: the ones with no pipeline record at all, i.e. nobody has worked them. Filter by status to answer 'what did we qualify this week'. Unmetered: this is the org reading its own work product, exactly as every property page in the app shows it. `total` is the true match count; the page is capped at `limit`. A per-person connection that is NOT an org admin is scoped to their OWN pipeline rows only — the same hard-scope the app's pipeline board and dashboard apply to a non-admin rep; an org-level credential or an org admin sees the whole org's pipeline. A row whose property is currently withheld (its owner asked Greenfinch not to list it) is NEVER returned — `total` already excludes it, and `unavailable_count` gives a neutral count of how many matching rows were withheld this way, with no row, address, or reason ever disclosed for them. A withheld property with NO pipeline row at all answers identically to a property id that never existed — it is silently absent from `rows`, `untouched_property_ids`, and every count, never distinguishable from a made-up id. Every row that IS returned carries `property_lifecycle`: 'active' means `property_id` resolves everywhere else on this connector; 'retired' means the underlying property was absorbed into a successor parcel or dropped by a county re-ingest since this deal was recorded; 'not_canonical' means the property record itself is still active but is not a canonical top-level record any other tool will resolve (e.g. a constituent parcel or hidden infrastructure) — the row is NEVER dropped from this answer for either 'retired' or 'not_canonical' (a won deal stays visible), but `property_id` will refuse NOT_FOUND from every other tool on both. For a retired row, use `successor_property_id` (when non-null) with every other tool instead — it is the live id for the same underlying parcel. A retired row with a null successor was a genuine drop with no replacement parcel; a 'not_canonical' row has no successor field at all (there is nothing to switch to — it names the same property, which is simply not one this connector can hand you). Keep the original id only for your own historical reference in either non-'active' case.

WritesNeeds a per-user connection

Writes a note on a property, the working record of a lead (for example 'called, decisions renew in March'). Notes are internal to your organization, shown on the property page in the app, and included in CRM lead bundles.

Cost
Free.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
contentrequiredstringThe note text (1-10000 chars).
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_add_note",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000001",
      "content": "Called front desk; facilities manager Dana is out until Monday. Contract renews in March."
    }
  }
}
Example result
{
  "noteId": "3f2a9c1e-0000-4000-8000-000000000501",
  "createdAt": "2026-09-14T16:05:40.000Z"
}

Refusal codes

ACTING_USER_REQUIREDIDENTITY_UNRESOLVEDFEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORYROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Write a note on a property — the working record of a lead ('called, gatekeeper says PM decisions renew in March'). Notes are internal to the org, visible on the property page in the app, and included in CRM lead bundles. Requires a per-user OAuth connection: a note is authored prose and the app attributes every note to its human author, so an org-level credential (no acting person) is refused — connect as a user, or record machine context via pipeline transitions instead.

Read-only

Reads your organization's notes on a property, newest first, with author names. Use it to see the history a colleague or another agent left before you act on a lead.

Cost
Free.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
limitintegerMax notes, default 50, max 100.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_notes",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000001",
      "limit": 20
    }
  }
}
Example result
{
  "notes": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000501",
      "content": "Called front desk; facilities manager Dana is out until Monday. Contract renews in March.",
      "author": "Jordan Example",
      "created_at": "2026-09-14T16:05:40.000Z"
    }
  ]
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORY
Full description(the text AI assistants read)

Read the org's notes on a property, newest first, with author names — the working history a human or another agent left. Unmetered (the org reading its own record). Same pipeline feature gate and territory fence as the app's property page.

WritesUses a daily limit

Moves a property's deal into the 'qualified' stage with a dollar deal value. That can send a lead-qualified event to the org's connected webhooks, Zapier or CRM. Use it when an agent has confirmed a property is a real sales opportunity. A deal that already closed (won or lost) is refused unless reopen is true, so a closed outcome is never cleared by accident.

Cost
Free, but each call counts against the org's and the connection's daily limit on agent pipeline changes.
Daily limit
Counts toward the daily limit on agent pipeline changes.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
dealValuerequirednumberDeal value in dollars; must be > 1.
testEventbooleanOptional, default false. Set true to mark this qualification (and its outbound lead.qualified delivery) as a test — see the tool description above.
reopenbooleanOptional, default false. A won or lost deal is refused (CLOSED_STAGE) unless this is true; true reopens it as qualified and clears its outcome.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_qualify_lead",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "dealValue": 48000,
      "testEvent": false
    }
  }
}
Example result
{
  "pipeline": {
    "id": "3f2a9c1e-0000-4000-8000-000000000021",
    "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
    "status": "qualified",
    "dealValue": 48000
  },
  "leadQualifiedEventEmitted": true,
  "testEvent": false,
  "reopened": false
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORYMCP_QUALIFICATION_DISABLEDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDDEAL_VALUE_REQUIREDSTAGE_CAPPEDCLOSED_STAGE
Full description(the text AI assistants read)

Mark a property's pipeline as qualified with a deal value greater than $1. A deal that already closed (won or lost) is refused with CLOSED_STAGE unless you pass reopen: true. Gated by this org's MCP-qualification setting and org-wide/per-credential daily transition caps (D17/D22) on top of the normal pipeline entitlement. Pass testEvent: true when you are only verifying that this org's connected webhook/Zapier/CRM systems receive events — it is still a REAL qualification (counts toward the pipeline and the daily cap, never auto-reverts) but its delivery to those systems carries a top-level test: true marker instead of being held back, so the receiving system can choose to ignore it.

WritesUses a daily limit

Marks a property's deal as disqualified, with a written reason and optionally one of the org's reason codes, for a property that never met the customer's criteria. Nothing is sent to outside systems, and a team member can undo it in the app. For a real opportunity that was lost, use greenfinch_update_lead_status with status 'lost' instead.

Cost
Free, but each call counts against the org's and the connection's daily limit on agent pipeline changes.
Daily limit
Counts toward the daily limit on agent pipeline changes.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
reasonrequiredstringRequired rationale for disqualifying this lead (min 10 characters). Logged permanently with this transition.
reasonCodestringOptional: one of this org's reason codes (greenfinch_get_loss_reasons, applies_to includes disqualified), e.g. not_a_fit. Your reason text is kept as the note beside it.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_disqualify_lead",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000012",
      "reason": "Owner-occupied single-tenant warehouse with in-house maintenance staff; outside target profile.",
      "reasonCode": "not_a_fit"
    }
  }
}
Example result
{
  "pipeline": {
    "id": "3f2a9c1e-0000-4000-8000-000000000022",
    "propertyId": "3f2a9c1e-0000-4000-8000-000000000012",
    "status": "disqualified",
    "disqualifiedReason": "not_a_fit",
    "disqualifiedNotes": "Owner-occupied single-tenant warehouse with in-house maintenance staff; outside target profile."
  },
  "reversible": true,
  "reversibleNote": "This disqualification can be undone by a member of the customer's team from the Greenfinch app."
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORYMCP_QUALIFICATION_DISABLEDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDALREADY_DISQUALIFIEDCLOSED_STAGESTAGE_CAPPEDINVALID_LOSS_REASON_CODE
Full description(the text AI assistants read)

Mark a property's pipeline as disqualified — for a property that never met criteria at all; a real opportunity that did not close is greenfinch_update_lead_status lost instead — with a required reason (D25). Disqualification never leaves Greenfinch — no CRM/webhook event fires. Reversible: a customer team member can undo an agent-driven disqualification from the app. Gated by this org's MCP-qualification setting and org-wide/per-credential daily transition caps (D17/D22), shared with greenfinch_qualify_lead.

WritesUses a daily limitNeeds an extra scope

Moves a deal to attempted_contact, active_opportunity, won or lost, with a written note of what happened and how the agent knows. Use it to relay sales progress from your own CRM or outreach tools. It works even for properties outside your viewing territory, but never widens what you can browse.

Cost
Free, but each call counts against the org's and the connection's daily limit on agent pipeline changes.
Daily limit
Counts toward the daily limit on agent pipeline changes.
Requires
The pipeline:transitions_full scope on the connection, granted by an organization admin.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
statusrequired"attempted_contact" | "active_opportunity" | "won" | "lost"—
evidencerequiredstringWhat happened and how you know (20-2000 chars). This is the record a human reads when auditing agent work — write it for them.
dealValuenumberDeal value in dollars — required for won when none was set at qualify.
lossReasonCodestringOne of this org's active loss-reason codes (greenfinch_get_loss_reasons) — only meaningful when status is lost. Your evidence is kept as the note beside it.
reopenbooleanOptional, default false. Moving a won or lost deal to attempted_contact or active_opportunity is refused (CLOSED_STAGE) unless this is true. Moving between won and lost needs no flag.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_update_lead_status",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "status": "lost",
      "evidence": "Property manager emailed on 9/12 that they renewed with their incumbent vendor for two years.",
      "lossReasonCode": "chose_competitor"
    }
  }
}
Example result
{
  "pipeline": {
    "id": "3f2a9c1e-0000-4000-8000-000000000021",
    "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
    "status": "lost",
    "dealValue": 48000,
    "isCurrentCustomer": false
  },
  "previousStatus": "active_opportunity",
  "reopened": false,
  "evidenceRecorded": true,
  "note": "Your evidence is recorded in the activity feed and stage history for human review."
}

Refusal codes

SCOPE_REQUIREDFEATURE_GATEDMCP_QUALIFICATION_DISABLEDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDNOT_FOUNDPROPERTY_RETIREDINVALID_LOSS_REASON_CODEIDENTITY_UNRESOLVEDSTAGE_CAPPEDDEAL_VALUE_REQUIREDSAME_STATUSCLOSED_STAGE
Full description(the text AI assistants read)

Move a lead to attempted_contact, active_opportunity, won, or lost — the working stages beyond qualify/disqualify. Use lost for a real opportunity that did not close; use greenfinch_disqualify_lead for a property that never met criteria at all. A won or lost deal moves back to an open stage only with reopen: true (won ↔ lost needs no flag). Requires: (1) the pipeline:transitions_full scope on this connection, granted by an org admin — without it this tool refuses (SCOPE_REQUIRED); (2) evidence — a sentence saying what happened and how you know (won: signed agreement received 8/30 per J. Smith email), stored durably in the activity feed and stage history that humans review. won requires a deal value (>$1, passed here or already set at qualify); lost stores your evidence as the loss reason and, when lossReasonCode is given (see greenfinch_get_loss_reasons for this org's valid codes), attaches that machine-readable code to the stage-history row so it counts in loss-reason analytics — pass it whenever one of the listed codes fits, rather than relying on your free-text evidence happening to match one. THIS NEVER CHANGES WHETHER THE ORG IS FLAGGED A CUSTOMER (founder ruling 2026-09-06): won/lost is a deal-stage fact only — call greenfinch_sync_customer_status separately to mark the account active or churned. CRM RELAY IS SUPPORTED: these transitions work on properties OUTSIDE your visible territory (founder ruling — relaying your CRM activity records a fact about your business), but recording grants NO browsing access: search, detail, and every read stay territory-fenced exactly as before. Orgs whose external CRM owns these stages refuse with STAGE_CAPPED — those transitions must come from the CRM. Draws down the same daily transition budget as qualify/disqualify.

Read-only

Returns your organization's own activity history on one property (pipeline status changes, deal-value updates, notes, owner assignments), newest first. Use it to see what your team has already done with a property, just like the activity panel on the property page.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
limitintegerMax rows, default 50, max 200.
offsetintegerRows to skip.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_property_activity",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "limit": 50,
      "offset": 0
    }
  }
}
Example result
{
  "events": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000031",
      "type": "status_change",
      "from": "new",
      "to": "contacted",
      "at": "2026-09-10T15:42:07.000Z",
      "by": "Jamie Rivera",
      "by_agent": true
    },
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000032",
      "type": "note_added",
      "from": null,
      "to": "Left a voicemail with the front desk; follow up next week.",
      "at": "2026-09-08T19:03:55.000Z",
      "by": "Jamie Rivera",
      "by_agent": false
    }
  ],
  "total": 2
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDOUT_OF_TERRITORYNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

This organization's own recorded activity on one property — pipeline status changes, deal-value updates, and notes recorded — newest first, paged, with the true total. Unmetered: this is the org reading its own record, exactly like the property page's activity panel. Territory-fenced like every by-id property read. Requires Pipeline management (Pro) on this org's plan, matching the app's own activity panel.

greenfinch_get_pipeline_analytics

Get Pipeline Analytics

Read-only

Returns the pipeline dashboard's summary numbers: how many deals are in each stage and their dollar totals, plus close rate and average time-to-close for deals that closed recently. Org-level API keys and org admins also get a per-rep breakdown.

Cost
Free.
ArgumentTypeDescription
windowDaysintegerTrailing window for close rate / cycle time / by-rep, default 30, max 365.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_pipeline_analytics",
    "arguments": {
      "windowDays": 90
    }
  }
}
Example result
{
  "window_days": 90,
  "since": "2026-06-16T15:30:00.000Z",
  "by_stage": [
    {
      "status": "qualified",
      "count": 14,
      "dealValueTotal": 612000
    },
    {
      "status": "won",
      "count": 3,
      "dealValueTotal": 145000
    }
  ],
  "won_count": 3,
  "lost_count": 2,
  "close_rate_pct": 60,
  "average_cycle_time_ms": 3888000000,
  "deal_value_totals": {
    "open": 780000,
    "won": 145000,
    "lost": 96000
  },
  "by_rep": [
    {
      "name": "Dana Whitfield",
      "qualified": 6,
      "won": 2,
      "lost": 1,
      "dealValueWon": 110000
    },
    {
      "name": "Unassigned",
      "qualified": 8,
      "won": 1,
      "lost": 1,
      "dealValueWon": 35000
    }
  ]
}

Refusal codes

FEATURE_GATEDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

The pipeline dashboard's rollups. Read which figures the window covers before comparing them: by_stage and deal_value_totals are POINT-IN-TIME — the shape of the pipeline right now, all-time, not scoped by windowDays. close_rate_pct, average_cycle_time_ms, won_count, lost_count and closed_in_window (won and lost deal value) cover deals that CLOSED within windowDays (default 30, max 365). In the by_rep breakdown (org credential or org-admin only; names only, no email) won, lost, dealValueWon and dealValueLost are windowed the same way and sum to closed_in_window, while qualified is that rep's current count of deals sitting in the qualified stage, point-in-time like by_stage. Unmetered. Territory-fenced — an acting user with a narrower assigned territory sees rollups over their own visible properties only, exactly like greenfinch_get_pipeline. A per-person connection that is NOT an org admin is additionally scoped to their OWN pipeline rows only, with no by_rep in the response — the same hard-scope the app's pipeline dashboard applies to a non-admin.

Read-only

Lists the reason codes this org can use when marking a deal lost or disqualifying it: its own custom codes plus the standard ones, each saying which of the two it applies to. Pass one as lossReasonCode to greenfinch_update_lead_status, or as reasonCode to greenfinch_disqualify_lead, so the outcome shows up in loss-reason reporting. Two of the standard disqualify codes, bad_property_data and bad_contact_data, mean Greenfinch's own record is wrong rather than the property being a poor fit: they go to Greenfinch's data team, who correct the record and return the lead to the pipeline, so use them only with a reason that says what is wrong.

Cost
Free.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_loss_reasons",
    "arguments": {}
  }
}
Example result
{
  "codes": [
    {
      "code": "chose_competitor",
      "label": "Chose a competitor",
      "description": "The prospect signed with another provider.",
      "eligible_from_stages": [
        "qualified",
        "attempted_contact",
        "active_opportunity"
      ],
      "applies_to": [
        "lost",
        "disqualified"
      ]
    },
    {
      "code": "no_budget",
      "label": "No budget",
      "description": null,
      "eligible_from_stages": [],
      "applies_to": [
        "lost"
      ]
    },
    {
      "code": "not_a_fit",
      "label": "Not a Fit for Our Services",
      "description": null,
      "eligible_from_stages": [
        "new",
        "qualified",
        "attempted_contact",
        "active_opportunity"
      ],
      "applies_to": [
        "disqualified"
      ]
    }
  ]
}

Refusal codes

FEATURE_GATED
Full description(the text AI assistants read)

This org's active loss-reason codes (its own org-specific codes plus every system default) — the same choices the app's lost-deal modal and disqualify dialog offer; applies_to says which of the two each code is for. Pass one of these `code` values as `lossReasonCode` to greenfinch_update_lead_status when marking a lead lost, or as `reasonCode` to greenfinch_disqualify_lead, instead of hoping your free-text evidence happens to match a known code. Unmetered.

Read-only

Shows how many agent pipeline changes (qualify, disqualify and the other stage moves, all counted together) are left today for the org and for this connection, and why the limit is what it is. Check it before a large batch of pipeline updates.

Cost
Free.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_transition_cap",
    "arguments": {}
  }
}
Example result
{
  "org_enabled": true,
  "used_today_org": 12,
  "used_today_credential": 4,
  "org_cap": 40,
  "credential_cap": 20,
  "remaining_org": 28,
  "remaining_credential": 16,
  "basis": "Computed from your organization's monthly credit allotment: the greater of a 25-transition floor or one day's share of that allotment (allotment ÷ 30), giving 40 today. This specific connection has its own narrower daily limit of 20."
}

Refusal codes

FEATURE_GATED
Full description(the text AI assistants read)

How much of today's agent-driven pipeline-transition budget remains (qualify/disqualify/attempted_contact/active_opportunity/won/lost, all counted together, reset at midnight UTC), the cap, and why the cap is that size — an explicit org-set daily limit, or computed from this org's monthly credit allotment, plus a narrower per-connection limit when one is set. Unmetered. Check this before a batch of qualify/disqualify calls to avoid hitting DAILY_CAP_EXCEEDED partway through.

Read-only

Lists every pipeline stage change for one property, newest first: the stage it moved from and to, who made the change, when, how long the deal sat in the previous stage, any note an agent left, and the reason code of a lost or disqualified deal. Use it to audit what happened on a deal.

Cost
Free.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
limitintegerMax rows, default 100, max 500.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_deal_history",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "limit": 50
    }
  }
}
Example result
{
  "property_id": "3f2a9c1e-0000-4000-8000-000000000011",
  "total": 3,
  "has_more": false,
  "entries": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000031",
      "from_stage": "active_opportunity",
      "to_stage": "lost",
      "by": "An agent (org-level credential)",
      "by_agent": true,
      "evidence": "Property manager emailed on 9/12 that they renewed with their incumbent vendor for two years.",
      "reason_code": "existing_vendor",
      "reason_label": "Staying with Existing Vendor",
      "transitioned_at": "2026-09-14T16:02:00.000Z",
      "duration_in_previous_stage_ms": 1209600000
    },
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000030",
      "from_stage": "qualified",
      "to_stage": "active_opportunity",
      "by": "Dana Whitfield",
      "by_agent": false,
      "evidence": null,
      "reason_code": null,
      "reason_label": null,
      "transitioned_at": "2026-08-31T14:20:00.000Z",
      "duration_in_previous_stage_ms": 604800000
    }
  ]
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORY
Full description(the text AI assistants read)

Every pipeline stage change recorded for one property: from/to stage, who made it (name, or 'by an agent' when machine-triggered), when, any evidence text an agent-driven transition carries, and the reason code of a lost or disqualified transition. Unmetered; territory-fenced (a property outside your visible territory refuses OUT_OF_TERRITORY).

Writes

Tells Greenfinch which properties are your organization's active or churned customer accounts, up to 500 per call. Use it to keep Greenfinch in step with your CRM so current customers are marked correctly.

Cost
Free.
ArgumentTypeDescription
accountsrequiredobject[]Up to 500 rows per call.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_sync_customer_status",
    "arguments": {
      "accounts": [
        {
          "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
          "status": "active"
        },
        {
          "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
          "status": "churned"
        }
      ]
    }
  }
}
Example result
{
  "results": [
    {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
      "status": "synced",
      "outOfServiceArea": false
    },
    {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "status": "error",
      "error": "Property not found",
      "outOfServiceArea": false
    }
  ],
  "syncedCount": 1,
  "errorCount": 1,
  "outOfServiceAreaCount": 0
}
Full description(the text AI assistants read)

Tell Greenfinch which properties are this org's currently active or churned customer accounts — the identical write POST /api/v1/customer-accounts/sync and the Zapier "Sync Customer Status" action perform (same underlying function, so all three can never disagree). Up to 500 rows per call; a bad property id inside an otherwise-valid batch is reported as a per-row error, never a whole-batch failure. Syncs regardless of whether the property is inside this org's current viewing area — a customer relationship is a fact about your business, not a data-access grant (founder ruling 2026-08-31) — outOfServiceArea on a row means it synced but won't show on your map/list/search until your service area covers that county. Marking "churned" never deletes the underlying record; it flips the lifecycle status so the account's history survives.

WritesNeeds a per-user connection

Sets a follow-up — a dated task on a property, with an owner, a type (follow_up, call, email, meeting, other) and an optional note. This is the same task the property page's Follow-up button creates, so the assignee sees it in the app; Greenfinch has no separate task list. Give an exact due date as an ISO-8601 instant, or use the app's own presets 'tomorrow_9am' and 'next_week_9am'.

Cost
Free.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
dueAtstringWhen it is due, as an ISO-8601 instant. Use this or duePreset, not both.
duePreset"tomorrow_9am" | "next_week_9am"The app's own two ready-made due dates: tomorrow at 9am, or a week from today at 9am.
timeZonestringIANA time zone the preset's 9am is read on (e.g. America/New_York). Defaults to America/Denver.
descriptionstringWhat to do, in a sentence (up to 5000 characters).
actionTypestring (one of 5)Defaults to follow_up. One of: follow_up, call, email, meeting, other.
assignedToUserIdstringA teammate's Greenfinch user id (greenfinch_get_team). Defaults to you; must be a current member of your organization.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_create_follow_up",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000001",
      "dueAt": "2026-09-25T16:00:00.000Z",
      "description": "Call the facilities manager about the landscaping contract renewal."
    }
  }
}
Example result
{
  "follow_up": {
    "id": "3f2a9c1e-0000-4000-8000-000000000801",
    "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
    "action_type": "follow_up",
    "description": "Call the facilities manager about the landscaping contract renewal.",
    "due_at": "2026-09-25T16:00:00.000Z",
    "status": "pending",
    "completion_status": "pending",
    "overdue": false,
    "assigned_to_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
    "assigned_to": null,
    "created_by_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
    "created_by": null,
    "created_at": "2026-09-22T18:30:00.000Z",
    "completed_at": null
  }
}

Refusal codes

ACTING_USER_REQUIREDIDENTITY_UNRESOLVEDFEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORYAMBIGUOUS_DUE_DATEACTION_TYPE_AND_DUE_DATE_REQUIREDDUE_DATE_INVALIDDUE_DATE_OUT_OF_RANGETIME_ZONE_INVALIDDESCRIPTION_TOO_LONGASSIGNEE_INVALIDASSIGNEE_NOT_A_MEMBER
Full description(the text AI assistants read)

Set a task on a property — this is Greenfinch's task/reminder/to-do object, called a follow-up: a due date, an optional note, an owner, and a type (follow_up, call, email, meeting, other). It is the SAME task the property page's Follow-up button creates, so whatever you set here appears for the assignee in the app and on the property's history; there is no separate task list. Give either an exact dueAt (ISO 8601, e.g. 2026-09-25T17:00:00Z) or duePreset 'tomorrow_9am' / 'next_week_9am' (the app's own two presets; a preset is read on timeZone, defaulting to Greenfinch's US Mountain clock, and the instant it resolved to is always reported back). Defaults to the person connected to this assistant; naming assignedToUserId (from greenfinch_get_team) assigns it to a teammate and notifies them. Unmetered.

Read-only

Reads back the follow-ups (tasks) your organization has set — everything still pending, one property's, or one person's — soonest due first, each flagged when it is past due. The same tasks the app shows on a property and on the pipeline dashboard.

Cost
Free.
ArgumentTypeDescription
propertyIdstringOnly this property's follow-ups.
assignedToUserIdstring'me', or a teammate's Greenfinch user id (greenfinch_get_team).
status"pending" | "completed" | "cancelled"Defaults to pending — the ones still to be done.
overdueOnlybooleanOnly pending follow-ups already past due.
limitintegerMax follow-ups, default 50, max 200.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_list_follow_ups",
    "arguments": {
      "assignedToUserId": "me",
      "status": "pending"
    }
  }
}
Example result
{
  "follow_ups": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000801",
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "action_type": "follow_up",
      "description": "Call the facilities manager about the landscaping contract renewal.",
      "due_at": "2026-09-25T16:00:00.000Z",
      "status": "pending",
      "completion_status": "pending",
      "overdue": false,
      "assigned_to_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
      "assigned_to": "Dana Reyes",
      "created_by_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
      "created_by": "Dana Reyes",
      "created_at": "2026-09-22T18:30:00.000Z",
      "completed_at": null
    }
  ],
  "returned": 1,
  "truncated": false,
  "scope": "every property visible to you in this organization",
  "note": null
}

Refusal codes

FEATURE_GATEDACTING_USER_REQUIREDIDENTITY_UNRESOLVEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORY
Full description(the text AI assistants read)

Read back the tasks (follow-ups) your organization has set: everything still pending, or one property's, or one person's — soonest due first, each flagged overdue when its due date has passed. This is the same task list the app shows on a property and on the pipeline dashboard. Pass assignedToUserId:'me' for your own. Unmetered; a property outside your territory, or one withheld at its owner's request, contributes no follow-ups.

Writes

Closes out a follow-up: completed, or cancelled when it is no longer needed. Completing records the time it was closed, and the answer says whether it landed on time or overdue against its due date. Anyone in your organization may close any of its follow-ups, exactly as in the app.

Cost
Free.
ArgumentTypeDescription
followUpIdrequiredstringThe follow-up's id, from greenfinch_list_follow_ups.
status"completed" | "cancelled"Defaults to completed.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_complete_follow_up",
    "arguments": {
      "followUpId": "3f2a9c1e-0000-4000-8000-000000000801",
      "status": "completed"
    }
  }
}
Example result
{
  "follow_up": {
    "id": "3f2a9c1e-0000-4000-8000-000000000801",
    "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
    "action_type": "follow_up",
    "description": "Call the facilities manager about the landscaping contract renewal.",
    "due_at": "2026-09-25T16:00:00.000Z",
    "status": "completed",
    "completion_status": "completed_on_time",
    "overdue": false,
    "assigned_to_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
    "assigned_to": null,
    "created_by_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
    "created_by": null,
    "created_at": "2026-09-22T18:30:00.000Z",
    "completed_at": "2026-09-24T14:12:00.000Z"
  }
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORY
Full description(the text AI assistants read)

Close out a task (follow-up): mark it completed, or cancelled if it is no longer needed. Completing stamps the time it was closed, and the answer says whether it landed on time or overdue against its due date. Anyone in your organization may close any of its follow-ups — the same rule the app applies, so a colleague can close one out when they were the one who made the call. Unmetered.

Writes

Moves an open follow-up to a new due date, and optionally replaces its note — the same reschedule the property page offers. The new date is an ISO-8601 instant (or one of the two presets) from today up to five years ahead. Only a follow-up still pending can be moved; a completed one keeps the date it was measured against.

Cost
Free.
ArgumentTypeDescription
followUpIdrequiredstringThe follow-up's id, from greenfinch_list_follow_ups.
dueAtstringThe new due date, as an ISO-8601 instant. Use this or duePreset, not both.
duePreset"tomorrow_9am" | "next_week_9am"Tomorrow at 9am, or a week from today at 9am.
timeZonestringIANA time zone the preset's 9am is read on (e.g. America/New_York). Defaults to America/Denver.
descriptionstringOptional new note (up to 5000 characters); omitted, the note is kept.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_reschedule_follow_up",
    "arguments": {
      "followUpId": "3f2a9c1e-0000-4000-8000-000000000801",
      "dueAt": "2026-10-02T16:00:00Z"
    }
  }
}
Example result
{
  "follow_up": {
    "id": "3f2a9c1e-0000-4000-8000-000000000801",
    "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
    "action_type": "follow_up",
    "description": "Call the facilities manager about the landscaping contract renewal.",
    "due_at": "2026-10-02T16:00:00.000Z",
    "status": "pending",
    "completion_status": "pending",
    "overdue": false,
    "assigned_to_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
    "assigned_to": null,
    "created_by_user_id": "3f2a9c1e-0000-4000-8000-000000000301",
    "created_by": null,
    "created_at": "2026-09-22T18:30:00.000Z",
    "completed_at": null
  },
  "previous_due_at": "2026-09-25T16:00:00.000Z"
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORYAMBIGUOUS_DUE_DATEDUE_DATE_REQUIREDDUE_DATE_INVALIDDUE_DATE_OUT_OF_RANGETIME_ZONE_INVALIDDESCRIPTION_TOO_LONGNOT_PENDING
Full description(the text AI assistants read)

Move an open task (follow-up) to a new due date, optionally replacing its note — the same reschedule the property page offers. Give dueAt (ISO 8601) or duePreset 'tomorrow_9am' / 'next_week_9am'.

Writes

Sets a deal's dollar value at whatever stage it is in, without moving the stage. The old and new value are recorded in the property's activity, where people see it in the app. An open deal's value can be changed by any connection that can write; a won or lost deal's value is recorded revenue, so it needs the same pipeline:transitions_full permission as marking a deal won, and is refused when the org's external CRM owns won and lost.

Cost
Free, and does not count against the daily limit on agent pipeline changes.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
dealValuerequiredintegerWhole dollars, greater than 1 and at most 1000000000.
notestringOptional: why the value changed, kept with the activity entry.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_set_deal_value",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "dealValue": 60000,
      "note": "Scope grew to include snow removal after the 9/24 site walk."
    }
  }
}
Example result
{
  "pipeline": {
    "id": "3f2a9c1e-0000-4000-8000-000000000021",
    "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
    "status": "active_opportunity",
    "dealValue": 60000
  },
  "previousDealValue": 48000,
  "changed": true
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORYIDENTITY_UNRESOLVEDDEAL_VALUE_INVALIDSCOPE_REQUIREDSTAGE_CAPPED
Full description(the text AI assistants read)

Set a deal's value in whole dollars at any stage, without moving its stage; the change is recorded in the property's activity. A won or lost deal's value needs the pipeline:transitions_full scope and is refused when the org's external CRM owns outcomes.

Writes

Makes a person the owner of a deal: yourself, or a teammate by their user id. Exactly as in the app, anyone may claim an unowned deal that is still at stage new; assigning a deal to someone else, or taking any other deal, takes an organization admin. The change is recorded in the property's activity.

Cost
Free, and does not count against the daily limit on agent pipeline changes.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
ownerUserIdrequiredstring'me', or a teammate's Greenfinch user id from greenfinch_get_team.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_assign_owner",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
      "ownerUserId": "me"
    }
  }
}
Example result
{
  "pipeline": {
    "id": "3f2a9c1e-0000-4000-8000-000000000021",
    "propertyId": "3f2a9c1e-0000-4000-8000-000000000011",
    "status": "qualified",
    "ownerUserId": "3f2a9c1e-0000-4000-8000-000000000301"
  },
  "previousOwnerUserId": null,
  "changed": true
}

Refusal codes

FEATURE_GATEDNOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYOUT_OF_TERRITORYIDENTITY_UNRESOLVEDACTING_USER_REQUIREDADMIN_REQUIREDASSIGNEE_NOT_A_MEMBERCLAIM_REQUIRES_NEW_STAGEOWNED_BY_SOMEONE_ELSE
Full description(the text AI assistants read)

Make yourself ('me') or a named teammate (greenfinch_get_team) the owner of a deal. Exactly as in the app, a non-admin may claim only an unowned deal still at stage new; anything else takes an organization admin.

Lead bundles

Export CRM-ready lead payloads.

WritesCosts creditsUses a daily limit

Returns the complete CRM-ready record for one property you have unlocked: property details, attached organizations and contacts, pipeline status, notes and actions. Use it to push a single lead into your CRM.

Cost
Free while your organization's monthly export allowance lasts, then 1 credit per delivery. Every call counts as a new delivery, so cache the result instead of fetching it again.
Daily limit
Counts toward the daily lead-export limit.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_lead_bundle",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000001"
    }
  }
}
Example result
{
  "bundle": {
    "bundle_version": 1,
    "greenfinch_property_id": "3f2a9c1e-0000-4000-8000-000000000001",
    "generated_at": "2026-09-14T15:04:05.000Z",
    "delivered_to_org": "org_example000000000001",
    "partial": false,
    "partial_reason": null,
    "property": {
      "address": "1200 Commerce Pkwy",
      "city": "Plano",
      "state": "TX",
      "zip": "75074",
      "county": "Collin",
      "common_name": "Northgate Business Park",
      "asset_category": "Office",
      "building_sqft": 84000,
      "deep_link_url": "https://app.greenfinch.ai/property/3f2a9c1e-0000-4000-8000-000000000001"
    },
    "organizations": [
      {
        "greenfinch_organization_id": "3f2a9c1e-0000-4000-8000-000000000021",
        "role": "owner",
        "name": "Northgate Business Park LLC",
        "domain": "example.com"
      }
    ],
    "contacts": [
      {
        "greenfinch_contact_id": "3f2a9c1e-0000-4000-8000-000000000011",
        "role": "facilities_manager",
        "full_name": "Dana Whitfield",
        "title": "Director of Facilities",
        "email": "dana.whitfield@example.com",
        "phones": [
          {
            "value": "(214) 555-0142",
            "label": "Direct",
            "type": "direct",
            "fallback_from_employer": false
          }
        ]
      }
    ],
    "contacts_summary": null,
    "pipeline": {
      "in_pipeline": true,
      "status": "qualified",
      "deal_value": 24000,
      "status_changed_at": "2026-09-10T18:22:00.000Z",
      "lost_reason": null,
      "disqualified_reason": null,
      "assigned_rep": {
        "greenfinch_user_id": "3f2a9c1e-0000-4000-8000-000000000031",
        "name": "Jordan Example",
        "email": "jordan.rep@example.com"
      }
    },
    "notes": [
      {
        "id": "3f2a9c1e-0000-4000-8000-000000000041",
        "author_name": "Jordan Example",
        "created_at": "2026-09-11T14:00:00.000Z",
        "content": "Spoke with facilities; contract renews in Q1."
      }
    ],
    "notes_digest": "2026-09-11 Jordan Example: Spoke with facilities; contract renews in Q1.",
    "actions": [
      {
        "id": "3f2a9c1e-0000-4000-8000-000000000051",
        "action_type": "follow_up",
        "description": "Send proposal",
        "due_at": "2026-09-18T15:00:00.000Z",
        "status": "pending",
        "completed_at": null,
        "assignee_name": "Jordan Example",
        "created_by_name": "Jordan Example",
        "created_at": "2026-09-11T14:05:00.000Z"
      }
    ],
    "actions_digest": "Pending: follow up (Send proposal), due 2026-09-18."
  },
  "billed_via": "quota",
  "credits_charged": 0,
  "delivery_id": "3f2a9c1e-0000-4000-8000-000000000061"
}

Refusal codes

IDENTITY_UNRESOLVEDDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDNOT_FOUNDPROPERTY_RETIREDOUT_OF_TERRITORYNOT_ENTITLEDCOMPLIANCE_CHECK_UNAVAILABLEINSUFFICIENT_CREDITSNO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Fetch the full CRM lead bundle for a property (property + contacts + organizations, field-masked per this org's export settings). Counts against the org's free monthly egress quota, then 1 credit per delivery beyond it.

WritesCosts creditsUses a daily limit

Exports CRM lead bundles for every property in a saved property list, one page at a time. Use it to sync a whole list into your CRM; run it with dryRun first to see what it will cost.

Cost
Free for each delivery while your organization's monthly export allowance lasts, then 1 credit per property delivered. Credits are only spent up to the maxCredits you pass; leaving maxCredits out means nothing beyond the free allowance is ever charged.
Daily limit
Counts toward the daily lead-export limit.
ArgumentTypeDescription
listIdrequiredstringSaved properties-list UUID.
maxCreditsintegerSpend ceiling in credits. Omitted = 0: only free-quota deliveries happen and nothing is ever charged unconfirmed. The COST_CONFIRMATION_REQUIRED refusal tells you the exact number to pass.
limitintegerBundles per page, default 25, max 50.
offsetintegerList members to skip (pages are list order).
dryRunbooleanProject cost and outcomes; deliver nothing.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_lead_bundles",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000071",
      "maxCredits": 5,
      "limit": 25,
      "offset": 0
    }
  }
}
Example result
{
  "listName": "Plano office prospects",
  "list_members": 2,
  "hidden_from_you": 0,
  "delivered": 1,
  "credits_charged": 1,
  "outcomes": [
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "outcome": "delivered",
      "billed_via": "credit",
      "credits_charged": 1
    },
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000002",
      "outcome": "refused",
      "refusal_code": "NOT_ENTITLED"
    }
  ],
  "bundles": [
    {
      "bundle_version": 1,
      "greenfinch_property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "generated_at": "2026-09-14T15:04:05.000Z",
      "delivered_to_org": "org_example000000000001",
      "partial": false,
      "partial_reason": null,
      "property": {
        "address": "1200 Commerce Pkwy",
        "city": "Plano",
        "state": "TX"
      },
      "organizations": [],
      "contacts": [],
      "contacts_summary": null,
      "pipeline": {
        "in_pipeline": false,
        "status": "new"
      },
      "notes": [],
      "notes_digest": "",
      "actions": [],
      "actions_digest": ""
    }
  ],
  "offset": 0,
  "next_offset": null
}

Refusal codes

IDENTITY_UNRESOLVEDLIST_NOT_FOUNDWRONG_LIST_TYPEEMPTY_SELECTIONDAILY_CAP_EXCEEDEDCREDENTIAL_DAILY_CAP_EXCEEDEDCOST_CONFIRMATION_REQUIREDNO_ACTIVE_SEATROLE_NOT_PERMITTED
Full description(the text AI assistants read)

Export CRM lead bundles for a whole saved property list — the CRM-sync unit. Billing is identical to greenfinch_get_lead_bundle, per property delivered (free monthly quota first, then 1 credit each). ALWAYS dryRun:true first: it projects how many deliveries ride quota vs credits. A live run REFUSES (COST_CONFIRMATION_REQUIRED) if credits would be charged beyond your maxCredits ceiling — passing maxCredits is how you confirm the spend. Pages of up to 50 (bundles are large); per-property outcomes are itemized, and a mid-run credit exhaustion reports exactly what was and was not delivered.

Workspace and account

Credits, quotas, coverage, team and company profile.

Read-only

Describes your workspace in one call: the counties you can see, the property categories in your visible data (with counts), every pipeline status, the credit price sheet, your export quota, limits, and step-by-step recipes for common workflows. Call it once at the start of a session.

Cost
Free.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_describe_workspace",
    "arguments": {}
  }
}
Example result
{
  "scope": {
    "scoped": true,
    "countyCount": 2,
    "states": [
      "TX"
    ]
  },
  "visible_counties": [
    {
      "fips": "48085",
      "name": "Collin County",
      "state": "TX"
    },
    {
      "fips": "48121",
      "name": "Denton County",
      "state": "TX"
    }
  ],
  "categories_in_your_data": [
    {
      "category": "Office",
      "properties": 1840
    },
    {
      "category": "Unknown / Unassigned",
      "properties": 37
    }
  ],
  "total_visible_properties": 1877,
  "pipeline_statuses": [
    "new",
    "qualified",
    "attempted_contact",
    "active_opportunity",
    "won",
    "lost",
    "disqualified"
  ],
  "pricing_credits": {
    "property_ai_research": 10,
    "property_unlock": 10,
    "contact_included_access": 0,
    "contact_reveal": 5,
    "contact_manual_enrich": 5,
    "organization_enrich": 2,
    "email_search": 5,
    "contact_deep_research": 10,
    "contact_email_draft": 5,
    "crm_lead_export": 1
  },
  "export_quota": {
    "billed_via": "quota",
    "used_this_period": 4,
    "free_exports_per_month": 50
  },
  "limits": {
    "search_page_max": 200,
    "research_batch_max": 100,
    "daily_egress_caps": {
      "contact_reveal": {
        "cap": 200,
        "used_today": 12,
        "remaining_today": 188
      },
      "lead_export": {
        "cap": null,
        "used_today": 0,
        "remaining_today": null
      }
    }
  },
  "recipes": [
    {
      "goal": "Build a ranked prospect list for a county",
      "steps": [
        "greenfinch_describe_workspace → find the county's FIPS code under visible_counties (or greenfinch_get_entitlement_summary).",
        "..."
      ]
    }
  ],
  "honesty_contract": "Empty never means nonexistent on this surface: ...",
  "existing_accounts_note": "There is no separate 'customers' roster on this surface. ..."
}

Refusal codes

NO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

START HERE. One unmetered call describing this workspace to an agent: the counties you can actually see (name + FIPS), the asset-category vocabulary present in YOUR visible data (with counts, so a filter that can never match is visible before you search), every pipeline status, the full credit price sheet (derived from the same map the billing path charges from — it cannot disagree with what you are charged), your export quota, your records allowance for this billing period (how many distinct property, firm and person records may still be handed to a program across every door together, when it resets, and whether going past it stops or is priced), the daily limits in force, batch limits, and step-by-step recipes for the common workflows — including how tasks work here (they are called follow-ups). Call it once at the start of a session instead of discovering the rules by trial and refusal.

Read-only

Shows what agents (and optionally people) did in your organization recently and what it cost: property activity entries plus credit debits and refunds, newest first. Use it to answer 'what did my agent do yesterday and what did it spend?'.

Cost
Free.
ArgumentTypeDescription
daysintegerHow many days back (default 7, max 90).
agentActionsOnlybooleantrue (default): only credential-attributed (agent) actions. false: include human in-app activity.
limitintegerMax rows per section, default 50, max 200.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_activity",
    "arguments": {
      "days": 7,
      "agentActionsOnly": true,
      "limit": 50
    }
  }
}
Example result
{
  "since": "2026-09-07T15:00:00.000Z",
  "pipeline_activity": [
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "type": "qualified",
      "from": "new",
      "to": "qualified",
      "by_agent": true,
      "at": "2026-09-13T18:22:04.000Z"
    },
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000002",
      "type": "note_added",
      "from": null,
      "to": "Called front desk; facilities manager is out until Monday.",
      "by_agent": true,
      "at": "2026-09-12T16:05:40.000Z"
    }
  ],
  "credit_entries": [
    {
      "type": "debit_consumption",
      "credits": -10,
      "at": "2026-09-13T18:20:11.000Z"
    },
    {
      "type": "grant_refund",
      "credits": 10,
      "at": "2026-09-12T09:00:00.000Z"
    }
  ],
  "totals": {
    "credits_spent": 10,
    "credits_refunded": 10,
    "note": "Credit totals are org-wide for the window — ledger debits are not attributable to a single credential."
  },
  "note": null
}

Refusal codes

NO_VISIBLE_TERRITORYIDENTITY_UNRESOLVED
Full description(the text AI assistants read)

What agents (and optionally people) have done in this org recently, with what it cost: pipeline transitions from the activity log, and every credit debit from the ledger, newest first. Unmetered — this is the org reading its own audit trail. Built for the accountability question a human asks after connecting an agent: 'what did it do yesterday, and what did that cost?' A property whose owner asked Greenfinch not to list it never appears in `pipeline_activity` — not the row, not a count, not a reason — exactly as if that property's history never happened; a withheld property's own activity is not something this feed reports on at all.

Read-only

Lists the outbound events your organization has sent to a connected CRM or automation, newest first, with delivery status: lead events (for example after a lead is qualified) and, once signals are switched on, change events (signal.ownership_transfer, signal.sale, signal.manager_change, signal.contact_departure, signal.contact_title_change, signal.contact_employer_change, and signal.withdrawn when a change already sent is retracted), each naming its subject. Use it to confirm what actually left Greenfinch.

Cost
Free.
ArgumentTypeDescription
daysintegerHow many days back (default 30, max 90).
limitintegerMax rows, default 50, max 200.
eventTypestring (one of 9)Only events of this type. Omit to see every type. The signal.* types work once signals are switched on. One of: lead.qualified, lead.changed, signal.ownership_transfer, signal.sale, signal.manager_change, signal.contact_departure, signal.contact_title_change, signal.contact_employer_change, signal.withdrawn.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_emitted_events",
    "arguments": {
      "days": 30,
      "limit": 25,
      "eventType": "lead.qualified"
    }
  }
}
Example result
{
  "events": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000101",
      "type": "lead.qualified",
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "subject_type": null,
      "subject_id": null,
      "withdraws_event_id": null,
      "status": "fanned_out",
      "skip_reason": null,
      "by_agent": true,
      "occurred_at": "2026-09-13T18:22:04.000Z",
      "fanned_out_at": "2026-09-13T18:22:06.000Z",
      "test": false
    }
  ],
  "total": 1,
  "note": "status 'pending' = queued for delivery; 'fanned_out' = handed to the org's configured endpoints (per-endpoint attempts live in webhook delivery logs); a skip_reason means the event was recorded but deliberately not delivered. test: true marks a deliberate test qualification (testEvent: true) — it still delivered for real with the same marker in its webhook/Zapier body."
}

Refusal codes

NO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDSIGNALS_NOT_ENABLED
Full description(the text AI assistants read)

The outbound CRM events this org has emitted (lead-qualified events, and — once signals are switched on — change events: signal.<kind> when Greenfinch recorded a change on a property or person your webhook subscribed to, signal.withdrawn when one was retracted; what a connected CRM or Zapier sees), newest first, with who/what triggered each and its delivery status. A change event names its subject (subject_type, subject_id); read its evidence with greenfinch_get_changes. Unmetered. This is how you verify what actually left Greenfinch after a qualify — the outbound counterpart to greenfinch_get_activity. A property whose owner asked Greenfinch not to list it never appears here — not the event, not a count, not a reason — and `total` already excludes it: this feed simply never reports on a withheld property's history.

Read-only

Shows how your organization's next lead-bundle export would be billed: from the free monthly export allowance, or with credits once that allowance is used up. Call it before an export when you want to tell the user whether it will cost anything.

Cost
Free to call. It only reads; it never charges or reserves anything.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_quota_state",
    "arguments": {}
  }
}
Example result
{
  "billed_via": "quota",
  "used_this_period": 12,
  "max_exports_per_month": 50,
  "max_rows_per_month": 50000,
  "period_start": "2026-09-01T00:00:00.000Z"
}
Full description(the text AI assistants read)

Peek this org's current egress quota state — what the NEXT greenfinch_get_lead_bundle call would bill through (free quota vs. credit), advisory only.

Read-only

Returns your organization's current spendable credit balance: the total plus how much sits in each pool (plan-included, purchased, trial, enterprise). Use it before a paid action to check the organization can afford it.

Cost
Free to call.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_credit_balance",
    "arguments": {}
  }
}
Example result
{
  "total": 740,
  "included": 500,
  "purchased": 200,
  "trial": 40,
  "enterprisePool": 0
}
Full description(the text AI assistants read)

This org's current spendable credit balance, by pool.

greenfinch_get_entitlement_summary

Get Entitlement Summary

Read-only

Explains which geography this connection can actually see and why: what the organization is licensed for, which area an admin has switched on, and the counties that are really visible after any personal territory is applied. Call it first whenever searches come back empty, because it lists visible counties by name and by 5-digit county code.

Cost
Free to call.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_entitlement_summary",
    "arguments": {}
  }
}
Example result
{
  "entitlement": {
    "nationwide": false,
    "stateAbbrs": [
      "NJ"
    ],
    "countyFips": []
  },
  "serviceableArea": {
    "wholeStateAbbrs": [
      "NJ"
    ],
    "countyFips": [
      "42101"
    ]
  },
  "effectiveTerritory": {
    "scoped": true,
    "countyCount": 2,
    "states": [
      "NJ"
    ],
    "counties": [
      {
        "fips": "34019",
        "name": "Hunterdon County",
        "state": "NJ"
      },
      {
        "fips": "34035",
        "name": "Somerset County",
        "state": "NJ"
      }
    ],
    "narrowedByYourAssignedTerritory": true,
    "countiesHiddenFromYou": 1,
    "statesHiddenFromYou": [
      "PA"
    ]
  },
  "notices": [
    "Your assigned territory is narrower than your organization's serviceable area: 1 county your organization serves are not visible to you. Adding geography at the organization level will NOT widen your view — ask your organization admin to add those counties to your assigned territory, or to clear your assigned territory entirely (a member with no assigned territory sees the whole serviceable area)."
  ],
  "tier": {
    "canRunEnrichments": true,
    "canUsePipeline": true,
    "canUseLists": true,
    "canExportFullCRM": false
  }
}
Full description(the text AI assistants read)

What geography this caller can actually see, and why. Reports the org's licensed entitlements and its configured serviceable area, plus — and this is the field to trust when results look empty — `effectiveTerritory`: the counties actually visible to THIS credential after the acting user's assigned territory narrows the org's serviceable area, listed by name AND 5-digit FIPS code (pass those codes to greenfinch_search_properties as filters.countyFips to search a county exactly). The two can differ: a state turned on for the org is invisible to a user whose assigned territory omits its counties, and any `notices` entry explains such a gap in plain words.

Read-only

Lists the properties and contacts your organization has revealed over a recent window, newest first, with the credits charged for each. Use it to explain or audit where credits went.

Cost
Free. Does not spend credits or any daily limit.
ArgumentTypeDescription
daysintegerHow many days back, default 30, max 365.
limitintegerMax rows, default 50, max 200.
offsetintegerRows to skip.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_reveal_history",
    "arguments": {
      "days": 30,
      "limit": 50,
      "offset": 0
    }
  }
}
Example result
{
  "reveals": [
    {
      "entity_type": "contact",
      "entity_id": "3f2a9c1e-0000-4000-8000-000000000041",
      "revealed_at": "2026-09-12T16:20:11.000Z",
      "credits_charged": 5
    },
    {
      "entity_type": "property",
      "entity_id": "3f2a9c1e-0000-4000-8000-000000000011",
      "revealed_at": "2026-09-09T14:05:43.000Z",
      "credits_charged": 0
    }
  ],
  "total_matching": 2,
  "window_days": 30,
  "note": "Org-wide, not narrowed by your personal territory — this explains money the organization already spent. credits_charged sums this entity's own debit_consumption ledger rows posted within this same window; a 0 can mean the reveal rode a geography entitlement or an already-unlocked property, not that nothing was ever charged for it."
}
Full description(the text AI assistants read)

What this organization has revealed (properties and contacts) over a window, newest first, paged, with the true total and each row's own credit cost. Unmetered — this is the org reading its own spend record, from revealed_items + credit_ledger, org-wide (not narrowed by any one member's personal territory, since it explains money the whole org already spent).

Read-only

Shows how many credits your organization has used in the current billing period, broken down by type of action. Org admins and org-level API keys also get a per-member breakdown by name.

Cost
Free.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_usage_breakdown",
    "arguments": {}
  }
}
Example result
{
  "period_start": "2026-09-01T00:00:00.000Z",
  "period_end": "2026-09-30T23:59:59.999Z",
  "credits_used": 185,
  "by_category": [
    {
      "category": "property",
      "credits_used": 120,
      "calls": 12
    },
    {
      "category": "contact",
      "credits_used": 50,
      "calls": 10
    },
    {
      "category": "organization",
      "credits_used": 15,
      "calls": 8
    }
  ],
  "by_member": [
    {
      "name": "Dana Whitfield",
      "creditsUsed": 140,
      "calls": 22
    },
    {
      "name": "Unknown user",
      "creditsUsed": 45,
      "calls": 8
    }
  ],
  "by_member_note": null
}
Full description(the text AI assistants read)

This org's credit usage for the current billing period: total credits used, a breakdown by action category (contact/property/organization/ai/export/other), and — org-admin acting context only, matching the app's own Usage page gate — a per-member breakdown by name (never email). Unmetered.

Read-only

Returns Greenfinch's full credit price list: how many credits each paid action costs. It is the same price list billing charges from, so what it shows always matches what is charged.

Cost
Free.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_price_sheet",
    "arguments": {}
  }
}
Example result
{
  "pricing_credits": {
    "property_ai_research": 10,
    "property_unlock": 10,
    "contact_included_access": 0,
    "contact_reveal": 5,
    "contact_manual_enrich": 5,
    "organization_enrich": 2,
    "email_search": 5,
    "contact_deep_research": 10,
    "contact_email_draft": 5,
    "crm_lead_export": 1
  }
}
Full description(the text AI assistants read)

The full credit price sheet, standalone — the same map greenfinch_describe_workspace's pricing_credits field already carries (it cannot disagree, since both read @core/credit-costs, the same map the billing path charges from). Unmetered.

Read-only

Lists your organization's team members with their role, join date, and how many counties their personal territory covers. It returns names only, never email addresses. It is available to org admins and org-level API keys.

Cost
Free.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_team",
    "arguments": {}
  }
}
Example result
{
  "members": [
    {
      "name": "Dana Whitfield",
      "role": "org:admin",
      "joined_at": "2026-03-02T17:20:00.000Z",
      "effective_territory_county_count": null
    },
    {
      "name": "Marcus Lee",
      "role": "org:member",
      "joined_at": "2026-05-11T14:05:00.000Z",
      "effective_territory_county_count": 4
    }
  ],
  "service_area_configured": true
}

Refusal codes

PERMISSION
Full description(the text AI assistants read)

This org's team: name, role, join date, and assigned-territory county count (null = unrestricted, sees the whole serviceable area) per member, plus whether the org has a service area configured at all — derivatives only, never an email address, and no seat or billing status. Org-admin acting context only (or an org-level credential, which already sees whole-org data elsewhere on this surface); a per-person connection that is not an org admin refuses PERMISSION. Unmetered.

Read-only

Reads the company profile Greenfinch keeps for your organization: description, brand values, differentiators, services, industry, size, headquarters and property focus. Greenfinch uses this profile to steer AI-written drafts and briefs.

Cost
Free. A pure read with no side effects.

This tool takes no arguments.

Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_company_profile",
    "arguments": {}
  }
}
Example result
{
  "profile": {
    "org_name": "Northgate Grounds Services",
    "org_description": "Commercial landscaping and snow removal for office parks and retail centers.",
    "org_brand_values": [
      "Reliability",
      "Safety first"
    ],
    "org_differentiators": [
      "24/7 snow response",
      "Dedicated account managers"
    ],
    "org_key_services": [
      "landscaping",
      "snow_ice_removal"
    ],
    "services_offered": [
      "landscaping",
      "snow_ice_removal"
    ],
    "property_focus": "commercial",
    "org_industry": "Landscaping services",
    "org_employee_count": 85,
    "org_founded_year": 2004,
    "org_headquarters": "Springfield, IL",
    "org_enrichment_status": "complete"
  }
}
Full description(the text AI assistants read)

The AI-editable company profile Greenfinch keeps for this org: name, description, brand values, differentiators, key services, services offered, industry, employee count, founded year, headquarters, and property focus — the same fields the app's Company Profile settings page shows. A read only — this never triggers auto-enrichment. Unmetered.

greenfinch_update_company_profile

Update Company Profile

WritesNeeds a per-user connection

Updates your organization's company profile. Only the fields you pass change. It needs a per-user connection belonging to someone who is an org admin at the time of the call, and it returns the updated profile.

Cost
Free.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
orgNamestringOnly used to backfill a missing org name — never overwrites an existing one.
orgDescriptionstringUp to 2000 characters.
orgIndustrystringUp to 200 characters.
orgBrandValuesstring[]Up to 20 short values.
orgKeyServicesstring[]Service-category keys this org offers. Every key must be one Greenfinch recognizes: a key it does not recognize is rejected as an invalid argument and the whole call fails, so nothing is written.
primaryServicestringThe headline/default revenue service — must be one of orgKeyServices, else the first selected service wins.
orgDifferentiatorsstring[]Up to 20 entries, 120 characters each.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_update_company_profile",
    "arguments": {
      "orgDescription": "Commercial landscaping, snow removal and parking-lot maintenance for office parks and retail centers across central Illinois.",
      "orgBrandValues": [
        "Reliability",
        "Safety first"
      ],
      "orgKeyServices": [
        "landscaping",
        "snow_ice_removal",
        "parking_pavement"
      ],
      "primaryService": "landscaping",
      "orgDifferentiators": [
        "24/7 snow response",
        "Dedicated account managers"
      ]
    }
  }
}
Example result
{
  "profile": {
    "org_name": "Northgate Grounds Services",
    "org_description": "Commercial landscaping, snow removal and parking-lot maintenance for office parks and retail centers across central Illinois.",
    "org_brand_values": [
      "Reliability",
      "Safety first"
    ],
    "org_differentiators": [
      "24/7 snow response",
      "Dedicated account managers"
    ],
    "org_key_services": [
      "landscaping",
      "snow_ice_removal",
      "parking_pavement"
    ],
    "services_offered": [
      "landscaping",
      "snow_ice_removal",
      "parking_pavement"
    ],
    "property_focus": "commercial",
    "org_industry": "Landscaping services",
    "org_employee_count": 85,
    "org_founded_year": 2004,
    "org_headquarters": "Springfield, IL",
    "org_enrichment_status": "complete"
  }
}

Refusal codes

PERMISSION
Full description(the text AI assistants read)

Update the AI-editable company profile Greenfinch keeps for this org — the same write POST /api/onboarding/update-company-profile performs from the onboarding wizard and the org-admin Company Profile settings page. A partial update: only fields you pass are changed. Steers future drafts and briefs, so keep it accurate. Scoped to the SAME authorization level as an app user (founder ruling 2026-09-05): only a per-person connection whose CURRENT org role is org-admin, verified live against Clerk, may call this — an org-level credential has no acting user to check and always refuses PERMISSION, and a per-person connection that is not currently an org admin also refuses PERMISSION. Returns the updated profile, same shape as greenfinch_get_company_profile.

Support and requests

Ask for coverage, refunds and help; flag bad data.

Writes

Asks the Greenfinch team to add data coverage for a county, identified by its 5-digit county code. It is an interest signal a person reviews, not a purchase or a billing change.

Cost
Free. It does not change your plan or bill anything.
ArgumentTypeDescription
fipsrequiredstring5-digit county FIPS code.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_request_coverage",
    "arguments": {
      "fips": "48121"
    }
  }
}
Example result
{
  "fips": "48121",
  "requested": true
}

Refusal codes

RATE_LIMITEDTEMPORARILY_UNAVAILABLEINVALID_FIPS
Full description(the text AI assistants read)

Ask Greenfinch to add a county to this org's coverage. A lightweight interest signal (not a billing action) — reviewed by the Greenfinch team out of band.

Writes

Requests an automatic credit refund for one of your organization's own earlier paid actions that failed or gave bad results. Point it at the research job, export delivery or credit charge by its id and explain why.

Cost
Free to call. A granted claim adds credits back; it never charges.
ArgumentTypeDescription
claimTyperequired"technical_failure" | "quality_claim"—
referencedActionTyperequired"enrichment_job" | "egress_delivery" | "credit_ledger_entry"—
referencedActionIdrequiredstringUUID of your own prior action.
reasonrequiredstringWhy this action should be refunded.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_request_refund",
    "arguments": {
      "claimType": "technical_failure",
      "referencedActionType": "enrichment_job",
      "referencedActionId": "3f2a9c1e-0000-4000-8000-000000000001",
      "reason": "The research job for 100 Commerce Way finished as failed and no results were delivered."
    }
  }
}
Example result
{
  "requestId": "3f2a9c1e-0000-4000-8000-000000000002",
  "creditsRefunded": 10,
  "reviewFlagged": false,
  "status": "refunded",
  "settlementPending": false,
  "summary": "10 credits were refunded to your organization's balance and can be used now."
}

Refusal codes

INVALID_REFERENCEALREADY_REFUNDEDNOTHING_TO_REFUNDREFUND_FAILEDREMEDIATION_CAP_EXCEEDEDREMEDIATION_DURING_TRIAL
Full description(the text AI assistants read)

Request an automatic credit refund for one of this org's own prior MCP-driven paid actions that failed or produced bad results (D18 self-serve remediation). Bounded by a small monthly abuse cap; every grant is auditable and every quality-claim grant is flagged for after-the-fact review. A granted refund has two outcomes, named by `status` and explained in `summary` (relay the summary as written): 'refunded' — the credits are on the org's balance now; 'refund_processing' (`settlementPending: true`) — the refund is recorded and owed, already counted against the monthly cap, and the credits will appear on the balance shortly with nothing further needed from the customer. Do not request the same refund again while it is processing.

Writes

Files a support request with the Greenfinch team for something the tools cannot do: a missing capability, data that looks wrong, or a billing or access question. A person triages it. Include the tool name and refusal code if a specific refusal sent you here.

Cost
Free.
ArgumentTypeDescription
categoryrequiredstring (one of 5)missing_capability = you wanted an action no tool offers; data_problem = Greenfinch data looks wrong; billing_question / access_question / other. One of: missing_capability, data_problem, billing_question, access_question, other.
descriptionrequiredstringPlain words, 10-4000 characters: what you were trying to do, and what happened instead.
relatedToolstringTool name that refused or fell short, if any.
relatedRefusalCodestringRefusal code you hit, if any.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_request_support",
    "arguments": {
      "category": "missing_capability",
      "description": "I wanted to plan a driving route for visiting the properties on my saved list tomorrow, and no tool will put them in a sensible order.",
      "relatedTool": "greenfinch_get_list",
      "relatedRefusalCode": "NOT_FOUND"
    }
  }
}
Example result
{
  "requestId": "3f2a9c1e-0000-4000-8000-000000000003",
  "category": "missing_capability",
  "filedAt": "2026-09-14T15:04:05.000Z",
  "note": "Filed with the Greenfinch team, attributed to this org and credential. A human triages these — there is no automated fix or response yet, so tell your user it has been reported rather than promising a timeline."
}

Refusal codes

RATE_LIMITEDTEMPORARILY_UNAVAILABLE
Full description(the text AI assistants read)

Ask the Greenfinch team for something this surface cannot do: a missing capability ('I wanted to plan a driving route through the properties on a list and there is no tool for it'), a data problem ('this property's owner looks wrong'), a billing question, or an access question. Filed durably with your org and credential attached and triaged by a human — include relatedTool and relatedRefusalCode when a specific refusal sent you here, so the request arrives as a feature ask with its evidence. Not for refunds of failed paid actions (greenfinch_request_refund) or county coverage (greenfinch_request_coverage).

Read-only

Lists the support requests your organization has already filed, newest first. Check it before filing a new one so you don't send a duplicate.

Cost
Free.
ArgumentTypeDescription
limitintegerMax rows, default 25, max 100.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_support_requests",
    "arguments": {
      "limit": 10
    }
  }
}
Example result
{
  "total": 3,
  "has_more": true,
  "requests": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000003",
      "category": "missing_capability",
      "description": "I wanted to plan a driving route for visiting the properties on my saved list tomorrow, and no tool will put them in a sensible order.",
      "related_tool": "greenfinch_get_list",
      "related_refusal_code": null,
      "by_this_credential": true,
      "filed_at": "2026-09-14T15:04:05.000Z"
    }
  ]
}
Full description(the text AI assistants read)

The support requests this org has filed through greenfinch_request_support, newest first. Check here before filing — a duplicate ask is noise for the team and for your user. Requests are triaged by a human; there is no status field yet (responses arrive out of band), so treat presence here as 'reported', not 'in progress'.

Writes

Reports that a property or contact record looks wrong, sending it to the queue Greenfinch staff work through to correct data, and automatically refunding every credit this organization spent on that record — research it commissioned, an unlock or reveal it paid for, an email lookup, a draft. It returns the id of the report and what the refund did — credits returned, nothing owed, already refunded, or the organization's monthly automatic-refund ceiling reached. Check on the report later with greenfinch_get_flag_status.

Cost
Free.
ArgumentTypeDescription
entityTyperequired"property" | "contact"—
propertyIdstringProperty UUID — required when entityType is property.
contactIdstringContact UUID — required when entityType is contact.
categoryrequiredstring (one of 5)One of: incorrect_info, outdated, wrong_relationship, duplicate, other.
issueDescriptionrequiredstringWhat's wrong (5-2000 characters) — shown to the staff member who triages this.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_flag_entity",
    "arguments": {
      "entityType": "property",
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
      "category": "incorrect_info",
      "issueDescription": "The listed owner is Northgate Business Park LLC, but the site was sold to Riverside Holdings LLC in 2025."
    }
  }
}
Example result
{
  "flagId": "3f2a9c1e-0000-4000-8000-000000000020",
  "attributedToYou": true,
  "refund": {
    "status": "refunded",
    "creditsRefunded": 10,
    "remediationRequestId": "3f2a9c1e-0000-4000-8000-000000000021",
    "reviewFlagged": true
  },
  "refundSummary": "10 credits you had spent on this record were refunded automatically. Greenfinch reviews every automatic refund afterwards."
}

Refusal codes

RATE_LIMITEDTEMPORARILY_UNAVAILABLENOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORY
Full description(the text AI assistants read)

Report "this is wrong" on a property or contact into the same data-quality triage queue staff work (entity_flags — the unified store POST /api/data-issues writes, which POST /api/properties/[id]/flag also mirrors into for owner/manager reports). Reporting a record ALSO refunds, automatically, every credit your organization spent on that record — the research it commissioned, the unlock or reveal it paid for to see it, an email lookup, a draft: the answer carries the report id and what the refund did (credits returned, nothing was owed, it was already refunded, or your organization is at its monthly automatic-refund ceiling). Being right about the data is not the condition for the refund. Check later with greenfinch_get_flag_status for whether a Greenfinch staff member has acted on the report; there is no promised turnaround time. Property targets are territory-fenced exactly like every other property-keyed tool on this surface (canonical parent properties only, refuses OUT_OF_TERRITORY for a real property outside your visible geography). Contact targets go through the same reachable-contact gate every other contact-keyed tool here uses — a contact private to another organization, or outside your paid geography, refuses NOT_FOUND exactly like a nonexistent id. Works for both an org-level credential (the report is filed with no specific person attributed) and a per-person connection (attributed to you).

Read-only

Checks what became of the data-quality reports this organization filed: whether Greenfinch staff have acted on each one yet, plus what the automatic refund of what the organization spent did. There is no promised turnaround time and none is reported — an open report means nobody has acted on it yet.

Cost
Free.
ArgumentTypeDescription
flagIdstringOne report's id. Omit to list recent reports.
limitnumberHow many recent reports to return (1-50).
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_flag_status",
    "arguments": {
      "flagId": "3f2a9c1e-0000-4000-8000-000000000020"
    }
  }
}
Example result
{
  "reports": [
    {
      "flagId": "3f2a9c1e-0000-4000-8000-000000000020",
      "category": "incorrect_info",
      "issueDescription": "The listed owner is Northgate Business Park LLC, but the site was sold to Riverside Holdings LLC in 2025.",
      "triageStatus": "resolved",
      "filedAt": "2026-09-22T15:04:00.000Z",
      "actedOnAt": "2026-09-23T11:20:00.000Z",
      "staffNote": "Owner corrected from the 2025 deed.",
      "refund": {
        "status": "refunded",
        "creditsRefunded": 10,
        "remediationRequestId": "3f2a9c1e-0000-4000-8000-000000000021",
        "reviewFlagged": true
      },
      "refundSummary": "10 credits you had spent on this record were refunded automatically. Greenfinch reviews every automatic refund afterwards.",
      "statusSummary": "Greenfinch staff resolved this report."
    }
  ]
}

Refusal codes

NOT_FOUND
Full description(the text AI assistants read)

Check what became of the data-quality reports your organization filed with greenfinch_flag_entity (or from the Greenfinch app). Returns each report's triage state — "open" until a Greenfinch staff member resolves or dismisses it — and what the automatic refund of what the organization spent on that record did: how many credits came back, or why none did (no credits were ever spent on that record, it was already refunded, or the organization is at its monthly automatic-refund ceiling). Pass flagId for one report, or omit it for your most recent 50 at most. There is no promised turnaround time and none is reported: an open report means nobody has acted on it yet, not that it is overdue. Only your own organization's reports are visible.

WritesNeeds a per-user connection

Tells Greenfinch about a person connected to a property — their name, an email address or LinkedIn URL, and their relationship to the building. Greenfinch researches and judges the claim at its own cost, and pays a 20-credit reward when it holds up. A LinkedIn URL is checked after the answer (linkedinCheck is "checking"); greenfinch_get_submission_status reads what the check found — if no profile can be found there it says so, so you can check the URL or add an email address. Requires a per-person connection, because the submission is attributed to you and the reward is paid to you.

Cost
Free to submit; earns 20 credits when the submitted relationship is verified, subject to a daily per-person ceiling on rewards.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
propertyIdrequiredstringProperty UUID.
namerequiredstringThe person's full name.
rolerequiredstring (one of 14)This person's relationship to the property. One of: owner, beneficial_owner, property_manager, facilities_manager, operator, leasing, leasing_agent, regional_property_manager, developer, investor, broker, tenant, facilities, other.
emailstringTheir email address (or give linkedinUrl).
linkedinUrlstringTheir LinkedIn profile URL (or give email).
titlestringTheir job title, if you know it.
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_submit_contact",
    "arguments": {
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
      "name": "Dana Whitfield",
      "role": "property_manager",
      "email": "dana.whitfield@riversideholdings.example",
      "title": "Regional Facilities Manager"
    }
  }
}
Example result
{
  "submissionId": "3f2a9c1e-0000-4000-8000-000000000030",
  "outcome": "promoted",
  "rewardGranted": true,
  "rewardCredits": 20,
  "message": "Contact verified and added. You earned 20 credits.",
  "linkedinCheck": null
}

Refusal codes

PERMISSIONRATE_LIMITEDTEMPORARILY_UNAVAILABLENOT_FOUNDPROPERTY_RETIREDNO_VISIBLE_TERRITORYIDENTITY_UNRESOLVEDOUT_OF_TERRITORY
Full description(the text AI assistants read)

Tell Greenfinch about a person you know is connected to a property — the same "Add Contact / submit what you know" action the property page offers (same underlying function, so the two can never disagree). Give their name, an email address or a LinkedIn URL, and their relationship to the property. Greenfinch matches or researches the person at its own cost (you are never charged for this), then judges whether they plausibly work for that property's owner or management firm. If it holds up, the relationship is added and you earn 20 credits; there is a daily ceiling on how many of these rewards one person can earn. If it does not hold up — or cannot be confirmed — the outcome is "under_review" and a person at Greenfinch looks at it; a submission already known to Greenfinch returns "already_verified" and earns nothing, which is not a rejection. A LinkedIn URL you give is checked after this answer (linkedinCheck "checking"): read the result with greenfinch_get_submission_status and the submissionId returned here — if no profile can be found there, it says so, so you can check the URL or add an email address. Requires a per-person connection: the submission is attributed to you and the reward is paid to you, so an organization-level API key has nobody to attribute it to and always refuses PERMISSION. The property must be one you can see.

Read-onlyNeeds a per-user connection

Checks what became of the contacts you submitted: each submission's outcome, its reward, and what the check of the LinkedIn URL it carried found. That check runs after the submission is answered — "checking" until it ends, then "found", "not_found" with a sentence asking you to check the URL or add an email address or another identifier, or "not_checked" when our check could not be done (not a sign the URL is wrong). Only your own submissions, and never the contact a submission matched.

Cost
Free.
Requires
A per-user connection (an AI assistant signed in as a member); organization API keys are refused with ACTING_USER_REQUIRED.
ArgumentTypeDescription
submissionIdstringOne submission's id (from greenfinch_submit_contact). Omit to list recent ones.
limitnumberHow many recent submissions to return (1-50).
Example call
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_submission_status",
    "arguments": {
      "submissionId": "3f2a9c1e-0000-4000-8000-000000000030"
    }
  }
}
Example result
{
  "submissions": [
    {
      "submissionId": "3f2a9c1e-0000-4000-8000-000000000030",
      "propertyId": "3f2a9c1e-0000-4000-8000-000000000010",
      "submittedAt": "2026-09-30T17:02:00.000Z",
      "outcome": "under_review",
      "rewardGranted": false,
      "rewardCredits": 0,
      "linkedinCheck": {
        "status": "not_found",
        "message": "We could not find that LinkedIn profile; the URL may be incorrect. Check it, or add an email address or another identifier so we can match the person.",
        "checkedAt": "2026-09-30T17:02:21.000Z"
      }
    }
  ]
}

Refusal codes

PERMISSIONNOT_FOUND
Full description(the text AI assistants read)

Check what became of the contacts you submitted with greenfinch_submit_contact (or from the Greenfinch app): each submission's outcome ("promoted", "already_verified", or "under_review" for everything else), its reward, and — when you gave a LinkedIn URL — what the check of that URL found. That check runs after the submission is answered: "checking" until it ends, then "found"; "not_found" (LinkedIn has no profile there and neither does a data provider) with a sentence asking you to check the URL or add an email address or another identifier; or "not_checked" (our check could not be done — not a sign the URL is wrong) with a sentence saying so. Pass submissionId for one submission, or omit it for your most recent 50 at most. Requires a per-person connection: only your own submissions are visible, and never the matched contact.