Developers · Lead bundles

Reference · Payloads

Lead bundles

A lead bundle is everything a CRM needs about one prospect property — the building, its owner and manager firms, the decision-makers, and your pipeline history — in one versioned JSON document.

Where bundles come from

ChannelUse it toHow
WebhookReceive each lead as it is qualifiedlead.qualified deliveries
RESTFetch one property's bundleGET /leads/{id}
MCPFetch one bundlegreenfinch_get_lead_bundle
MCPExport a saved list page by pagegreenfinch_get_lead_bundles

Every channel builds the same bundle, applies the same field settings, and is billed the same way. Bundles leave one property at a time; there is no bulk dump.

Example

LeadBundleV1 (illustrative)
{
  "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",
    "lat": 33.0198,
    "lon": -96.6989,
    "common_name": "Northgate Business Park",
    "common_name_confidence": 0.92,
    "lot_sqft": 217800,
    "building_sqft": 96000,
    "building_sqft_is_planned": false,
    "year_built": 2004,
    "year_built_detail": {
      "basis": "per_building",
      "oldest": 1998,
      "newest": 2004,
      "primary_building_basis": "area",
      "buildings": 3,
      "buildings_total": 3
    },
    "num_floors": 4,
    "num_floors_detail": {
      "basis": "per_building",
      "max": 4,
      "area_weighted_mean": 3.51,
      "primary_building": 4,
      "primary_building_basis": "area",
      "buildings": 3,
      "buildings_total": 3
    },
    "effective_year_built": 2015,
    "effective_year_built_detail": {
      "basis": "per_building",
      "oldest": 2009,
      "newest": 2015,
      "primary_building_basis": "area",
      "buildings": 2,
      "buildings_total": 3
    },
    "heating_type": "Rooftop Package Unit",
    "heating_type_detail": {
      "basis": "per_building",
      "buildings": 3,
      "buildings_total": 3,
      "area_share": 1,
      "values": [
        {
          "value": "Rooftop Package Unit",
          "buildings": 2,
          "area_share": 0.844
        },
        {
          "value": "Heat Pump",
          "buildings": 1,
          "area_share": 0.156
        }
      ]
    },
    "cooling_type": "Rooftop Package Unit",
    "cooling_type_detail": {
      "basis": "per_building",
      "buildings": 3,
      "buildings_total": 3,
      "area_share": 1,
      "values": [
        {
          "value": "Rooftop Package Unit",
          "buildings": 2,
          "area_share": 0.844
        },
        {
          "value": "Heat Pump",
          "buildings": 1,
          "area_share": 0.156
        }
      ]
    },
    "primary_construction_type": "Concrete",
    "primary_construction_type_detail": {
      "basis": "per_building",
      "buildings": 3,
      "buildings_total": 3,
      "area_share": 1,
      "values": [
        {
          "value": "Concrete",
          "buildings": 3,
          "area_share": 1
        }
      ]
    },
    "exterior_wall_material": null,
    "exterior_wall_material_detail": null,
    "foundation_type": "Slab on Grade",
    "foundation_type_detail": {
      "basis": "per_building",
      "buildings": 3,
      "buildings_total": 3,
      "area_share": 1,
      "values": [
        {
          "value": "Slab on Grade",
          "buildings": 3,
          "area_share": 1
        }
      ]
    },
    "roof_cover": null,
    "roof_cover_detail": null,
    "roof_shape": null,
    "roof_shape_detail": null,
    "quality_grade": "Good",
    "quality_grade_detail": {
      "basis": "per_building",
      "buildings": 3,
      "buildings_total": 3,
      "area_share": 1,
      "values": [
        {
          "value": "Good",
          "buildings": 2,
          "area_share": 0.844
        },
        {
          "value": "Average",
          "buildings": 1,
          "area_share": 0.156
        }
      ]
    },
    "has_pool": false,
    "has_pool_detail": {
      "basis": "per_building",
      "count": 0,
      "buildings": 3,
      "buildings_total": 3
    },
    "has_sprinklers": true,
    "has_sprinklers_detail": {
      "basis": "per_building",
      "count": 2,
      "buildings": 2,
      "buildings_total": 3
    },
    "building_attributes_basis": "per_building",
    "footprint_area": 21500,
    "footprint_area_source": "measured",
    "asset_category": "Office",
    "asset_subcategory": "Office Building",
    "category_confidence": 0.95,
    "beneficial_owner": "Northgate Holdings Group",
    "beneficial_owner_type": "private_investor",
    "beneficial_owner_confidence": 0.8,
    "ownership_type": "private",
    "management_company": "Lakeside Property Services",
    "registered_owner": "Northgate Business Park LLC",
    "assessed_total_val": 18450000,
    "last_sale_date": "2017-05-22",
    "last_sale_price": 16900000,
    "last_transfer_date": null,
    "revenue_estimates": {
      "landscaping": {
        "mid": 42000,
        "low": 31000,
        "high": 55000,
        "tier": 2
      }
    },
    "property_website": "https://northgate.example.com",
    "ai_rationale": "Four-story multi-tenant office building on a landscaped campus…",
    "property_phone": "(972) 555-0118",
    "property_phone_confidence": 0.7,
    "last_enriched_at": "2026-08-20T14:11:00.000Z",
    "deep_link_url": "https://app.greenfinch.ai/property/3f2a9c1e-0000-4000-8000-000000000001"
  },
  "organizations": [
    {
      "greenfinch_organization_id": "3f2a9c1e-0000-4000-8000-000000000021",
      "role": "property_manager",
      "attribution_type": "named_for_property",
      "is_current": true,
      "name": "Lakeside Property Services",
      "domain": "lakeside.example.com",
      "location": {
        "city": "Dallas",
        "state": "TX",
        "postal_code": "75201"
      },
      "industry": "Real Estate",
      "employees": 140,
      "employees_range": "51-200",
      "linkedin_handle": "lakeside-property-services-example",
      "phone_numbers": [
        "(214) 555-0100"
      ]
    }
  ],
  "contacts": [
    {
      "greenfinch_contact_id": "3f2a9c1e-0000-4000-8000-000000000011",
      "role": "property_manager",
      "attribution_type": "named_for_property",
      "relationship_status": "active",
      "relationship_confidence": "high",
      "stale_pending_review": false,
      "identity_not_confirmed": false,
      "full_name": "Dana Whitfield",
      "title": "Director of Facilities",
      "email": "dana.whitfield@example.com",
      "email_validation_status": "valid",
      "linkedin_url": "https://www.linkedin.com/in/example-dana-whitfield",
      "employer_name": "Lakeside Property Services",
      "phones": [
        {
          "value": "(214) 555-0142",
          "label": "direct_work",
          "type": "Direct",
          "fallback_from_employer": false
        }
      ],
      "phone_e164": "+12145550142",
      "confidences": {
        "name": 0.95,
        "email": 0.9,
        "linkedin": 0.85
      }
    }
  ],
  "contacts_summary": null,
  "pipeline": {
    "in_pipeline": true,
    "status": "qualified",
    "deal_value": 48000,
    "status_changed_at": "2026-09-12T16:40:11.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; landscaping contract renews in Q1."
    }
  ],
  "notes_digest": "2026-09-11 — Jordan Example: Spoke with facilities; landscaping contract renews in Q1.",
  "actions": [
    {
      "id": "3f2a9c1e-0000-4000-8000-000000000051",
      "action_type": "call",
      "description": "Follow up before renewal",
      "due_at": "2026-10-01T15:00:00.000Z",
      "status": "pending",
      "completed_at": null,
      "assignee_name": "Jordan Example",
      "created_by_name": "Jordan Example",
      "created_at": "2026-09-11T14:02:00.000Z"
    }
  ],
  "actions_digest": "2026-10-01 — Call (pending): Follow up before renewal"
}

Fields

Every field is always present; a value Greenfinch does not have is null (or an empty array). Your organization admin can switch off groups of contact and organization fields for all exports on the Integrations page; switched-off fields arrive as null (phone lists as empty arrays). IDs, roles and relationship flags are never switched off.

Removed on 2026-09-16: property.calculated_building_class, property.building_class_rationale, property.management_type and organizations[].estimated_annual_revenue. Nothing ever populated these keys, so no data was lost.

Changed 2026-09-16: where a county lists every building on a site, year_built carries the year of the building with the most floor area — or, when that building's record gives no year, of the largest building that does — and num_floors carries the tallest building's floor count, rounded up to a whole floor.

Envelope

NameTypeDescription
bundle_versionrequired1Schema version. Fields can be added, and a field that never carried a value can be removed, without changing it. A populated field is never removed within a version.
greenfinch_property_idrequireduuidThe property's stable ID — the key to de-duplicate on.
generated_atrequiredISO-8601When the bundle was assembled.
delivered_to_orgrequiredstringYour organization's ID.
partialrequiredbooleantrue only for a webhook delivery of a property that was not unlocked; see contacts_summary.
partial_reasonrequired"not_revealed" | nullWhy the bundle is partial.

property

NameTypeDescription
address, city, state, zip, countyrequiredstringValidated location. address is always set.
lat, lonrequirednumberParcel centre.
common_namerequiredstringThe property's name. A common_name_confidence of 0.4 or less means an address-style fallback, not a known name.
lot_sqft, building_sqftrequirednumberLot and building floor area. building_sqft_is_planned marks planned rather than built floor area.
year_built, effective_year_built, num_floorsrequirednumberWhen the building was built, when it dates from once renovations are counted, and its floor count. On a site with several buildings: the year of the building with the most floor area (or, when that building's record gives no year, of the largest building that does), and the tallest building's floor count.
heating_type, cooling_type, primary_construction_type, exterior_wall_material, foundation_type, roof_cover, roof_shaperequiredstringBuilding details from a fixed list of values. On a site with several buildings, the value covering the most floor area. Wall material, roof cover and roof shape are empty on most properties today.
quality_graderequiredstringThe construction-quality grade the county assessor recorded to value the building for tax, on that county's own scale. A rough tier, not an inspection and not a statement about the building's condition today.
has_pool, has_sprinklersrequiredbooleantrue when at least one building has one; false only when the county says there is none; null when it does not say. Sprinklers are empty on most properties today.
<field>_detailrequiredobjectBeside each building detail above (not the footprint below): how many buildings it covers (buildings, buildings_total), its share of floor area, every value on the site for a list-valued detail (values, whose first entry is always the value itself), the oldest and newest year, or the tallest floor count as the county records it (num_floors is that figure rounded up) and the average. Present whenever the value is, unless a stored per-building breakdown could not be read, in which case the value still ships and the detail is null. basis is per_building when every building was combined and main_building_only when only one main-building record is known, in which case the counts are null.
building_attributes_basisrequired"per_building" | "main_building_only" | nullHow the building details were put together; null only when the property has none of them.
footprint_area, footprint_area_sourcerequirednumber / stringThe building's footprint in square feet as the Greenfinch property page shows it, and whether it is measured or an estimate (county_record is reserved for a county's recorded foundation area and does not occur yet). Empty on plans without premium property data. No detail object.
asset_category, asset_subcategoryrequiredstringWhat the property is, with category_confidence.
beneficial_owner, beneficial_owner_typerequiredstringWho really owns it, with beneficial_owner_confidence and ownership_type.
management_companyrequiredstringWho manages it.
registered_ownerrequiredstringThe owner of record on the county's assessor roll.
assessed_total_val, last_sale_date, last_sale_price, last_transfer_daterequirednumber / dateAssessed value; the county's last recorded sale and its price; a later recorded transfer.
revenue_estimatesrequiredobjectEstimated annual service revenue by service category: mid, low, high and a size tier.
property_website, property_phonerequiredstringDiscovered contact points, with property_phone_confidence.
ai_rationalerequiredstringThe research write-up.
last_enriched_atrequiredISO-8601When the property was last researched.
deep_link_urlrequiredstringThe property's page in the Greenfinch app.

organizations[]

NameTypeDescription
greenfinch_organization_idrequireduuidThe firm's stable ID.
rolerequiredstringThe firm's relationship to the property: owner, property_manager, operator (runs a site it does not own and decides its upkeep) or tenant (occupies space without deciding upkeep; recorded, never the buyer).
attribution_typerequiredstringThe strength of the evidence, strongest first: named_for_property, portfolio_evidence, roster_deterministic, roster_llm, coverage_inferred, county_record.
is_currentrequiredbooleanWhether the relationship is current.
name, domain, locationrequiredstring / objectFirm identity and city, state and postal code.
industry, employees, employees_rangerequiredstring / numberFirmographics.
linkedin_handle, phone_numbersrequiredstring / string[]The firm's LinkedIn handle and main office numbers.

contacts[]

NameTypeDescription
greenfinch_contact_idrequireduuidThe contact's stable ID.
role, attribution_typerequiredstringDecision-maker role at this property and the evidence behind it.
relationship_statusrequiredstringactive, job_change_detected, former, needs_review, demotion_withheld or retraction_withheld.
relationship_confidencerequiredstringhigh, medium or low.
stale_pending_reviewrequiredbooleantrue when the relationship is under review; do not treat the contact as confirmed-current.
identity_not_confirmedrequiredbooleantrue when the person's current job could not be confirmed; the title and employer are unconfirmed.
full_name, title, employer_namerequiredstringWho the person is.
email, email_validation_statusrequiredstringEmail and "valid" or "unknown". Unknown means found but not yet confirmed deliverable — not invalid.
linkedin_urlrequiredstringProfile URL.
phones[]requiredobject[]Deliverable numbers: value, label (the stored label), type ("Mobile", "Direct", "Office" or null) and fallback_from_employer (true when the number is the employer's main line, not the person's).
phone_e164requiredstringThe primary number in E.164 form for matching; null when the only number is an employer fallback.
confidencesrequiredobjectConfidence in name, email and linkedin, 0–1.

contacts_summary

null on a full bundle. On a partial bundle it replaces contacts: total_count and, per contact, title and availability (email, phone, linkedin booleans) — what unlocking would give you, without names or values.

pipeline, notes and actions

NameTypeDescription
pipeline.in_pipelinerequiredbooleanfalse when the property has no pipeline record (the status is then a default of new).
pipeline.status, deal_value, status_changed_atrequiredstring / numberThe current stage, deal value and when it changed.
pipeline.lost_reason, disqualified_reasonrequiredstringWhy a deal was lost or disqualified.
pipeline.assigned_reprequiredobjectgreenfinch_user_id, name and email of the owner, or null.
notes[]requiredobject[]id, author_name, created_at and content. notes_digest is the same history as plain text.
actions[]requiredobject[]Every task — pending, completed and cancelled — with action_type, description, due_at, status, completed_at, assignee_name, created_by_name and created_at. actions_digest is the same history as text.

How deliveries are metered

On Team plans, bundle deliveries are metered per delivery:

  • A free monthly allowance. Each billing period your organization can export a set number of bundles free. The allowance and how much is used are in GET /account (egress_quota).
  • Then 1 credit each. Once the allowance is used, every delivered bundle costs 1 credit, on every channel.
  • Every delivery counts. Fetching the same property twice is two deliveries.

On Enterprise plans, bundle deliveries draw the records allowance your order states, at no credit cost, on every channel — a bundle counts its property plus each distinct firm and person inside it, once per record per billing period. A bundle with two firms and two people in it is five records; fetching that same property again in the same period adds nothing.

  • Unlocking is separate. A bundle includes contacts only for properties your organization has unlocked (10 credits, once) or that your subscription covers.
  • Daily limits. An admin can cap deliveries per day for the organization and per key; see daily limits.

Each REST response tells you how it was billed in meta.billed_via (quota or credit) and meta.credits_charged.

Availability — 15 September 2026

The move of Enterprise deliveries from the per-delivery meter to the records allowance is rolling out from mid-September 2026, with each Enterprise order. Until it reaches your organization, Enterprise deliveries are metered exactly like Team's — the free monthly allowance, then one credit each — and the dry-run and ceiling controls below apply unchanged. Team plans do not change.

Dry runs and spend ceilings

greenfinch_get_lead_bundles exports a saved property list one page at a time and is built so a job never spends more than you approved.

1. Price the page with a dry run

curl -X POST "https://app.greenfinch.ai/api/v1/mcp" \
  -H "Authorization: Bearer $GREENFINCH_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_lead_bundles",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000071",
      "limit": 25,
      "offset": 0,
      "dryRun": true
    }
  }
}'
structuredContent
{
  "dryRun": true,
  "listName": "Plano office prospects",
  "list_members": 42,
  "hidden_from_you": 0,
  "page_size": 25,
  "offset": 0,
  "projected_deliveries": 22,
  "projected_refusals": 3,
  "projected_outcomes": [
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000001",
      "outcome": "would_deliver"
    },
    {
      "property_id": "3f2a9c1e-0000-4000-8000-000000000013",
      "outcome": "would_refuse",
      "refusal_code": "NOT_ENTITLED"
    }
  ],
  "projected_via_quota": 18,
  "projected_credits": 4,
  "note": "Nothing was delivered or charged. 3 of 25 properties on this page would be refused and cost nothing — see projected_outcomes."
}

A dry run delivers and charges nothing. projected_credits counts only the properties this page can actually deliver — a property that will be refused (not unlocked, outside your territory) is never charged for, and is listed in projected_outcomes with its refusal_code. The figure is bounded by today's remaining daily export allowance as well, since deliveries past it do not happen, and then by your free monthly allowance, which is spent before any credit is. If a page is long enough that the allowance runs out part-way, the properties beyond that point are not examined at all and are reported as not_projected rather than counted either way.

2. Run it with a ceiling

curl -X POST "https://app.greenfinch.ai/api/v1/mcp" \
  -H "Authorization: Bearer $GREENFINCH_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "greenfinch_get_lead_bundles",
    "arguments": {
      "listId": "3f2a9c1e-0000-4000-8000-000000000071",
      "limit": 25,
      "offset": 0,
      "maxCredits": 7
    }
  }
}'
  • maxCredits is the most the call may spend beyond the free allowance. Leaving it out means 0: only free exports happen.
  • If the page would cost more than maxCredits, the call refuses with COST_CONFIRMATION_REQUIRED and the projected numbers, before delivering anything. Call again with a higher ceiling to confirm.
  • The ceiling is re-checked before every delivery. If credits, the allowance or a daily limit run out mid-page, the call stops early, keeps what it delivered, and says so in stopped_early and note.
  • Each result lists an outcomes entry per property (delivered, refused with a refusal_code, or failed), the bundles, and credits_charged.
  • Continue with next_offset until it comes back null. It always points at the first property the call did not finish with, so nothing is skipped.
  • A run that stopped early returns next_offset: null — continuing unchanged would stop in the same place — plus stopped_early saying what ran out and resume_offset, the property to start from once it has been dealt with (the daily cap resets, or you raise maxCredits).

Single-bundle calls (GET /leads/{id}, greenfinch_get_lead_bundle) have no ceiling argument: each costs at most 1 credit. Check egress_quota first if you need to stay within the allowance.