RealtyAds
Manage your properties
- Category
- Pending
- Primary Subcategory
- Pending
Integration details
Description
The RealtyAds MCP connection allows you fully manage all your RealtyAds properties. All functionality available in the RealtyAds portal is now available directly in ChatGPT. You can create and edit ads, save ads for later use, view performance and pull reports, and ask product and support questions.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Category
- Pending
- Primary Subcategory
- Pending
- Secondary Subcategories
- None listed
- Brand
- Unknown
- Access
- Account required
- First tracked
- 2026-09-01
- Tool count
- 63
- Geography
- US
The broad Category that contains the Primary Subcategory.
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is listed.
ChatGPT Plugin Discovery Score
ChatGPT Plugin discovery is coming soon
ChatGPT can surface a Plugin when it matches a user's request.Your Plugin Discovery Score measures how often yours appears.
No spam. Unsubscribe any time.
What discovery looks like

Competitive lineup
63 tools agents can invoke
Bulk version of add_company_to_targeting: add many companies to one RealtyAds account's targeted-firms list in a single call. Each entry needs a company_name; linkedin_company_url and/or linkedin_company_id are strongly recommended for an immediate match. Use this tool when the user wants to add several companies to a RealtyAds account's targeted-firms list in one go (e.g. "target these 10 companies", or running through a list pasted from a spreadsheet). Per-entry behavior is identical to add_company_to_targeting. Required: - account_id: the RealtyAds property account that should target the companies. Must be an account the caller has access to. - companies: a JSON array of objects, each containing: - company_name (required): used verbatim as firm_name (max 150 chars). - linkedin_company_url (optional, recommended): "https://www.linkedin.com/company/jll/" or just "/company/{slug}". - linkedin_company_id (optional, recommended): numeric LinkedIn company id. Up to 100 entries per call. Behavior per entry (same as add_company_to_targeting): - When a LinkedIn id is supplied or resolved from the URL, writes a fully-matched row immediately and clears any matching exclusion / partner-pursuit / partner-integration suppression flags. - When only a name is supplied, writes a lightweight row and lets the matching cron resolve the LinkedIn record on its next pass. - Idempotent on (account_id, linkedin_company_id): duplicates return action_taken="already_targeted" without creating extra rows. Errors are per-entry, not per-batch. A bad row (e.g. empty company_name) returns action_taken="failed" with an "error" string for that entry; the rest of the batch still runs. The top-level response carries counts (added / already_targeted / failed) so the caller can see at a glance what happened. Each entry's response carries the input position (`index`) plus the same fields the singular tool returns (action_taken, targeted_firm_id, linkedin_company_id, matched_via, canonical_company_name, queued_for_matching). This is a WRITE action. Every successful add is logged in the portal activity feed under the calling user.
Add one company to a RealtyAds account's targeted-firms list so the ad system starts targeting decision-makers at that company. company_name is required; linkedin_company_url and/or linkedin_company_id are strongly recommended for an immediate match. Use this tool when the user wants to start targeting a specific company through their RealtyAds account. The company is added to the same targeted-firms list the portal's "Company Targeting" UI writes to. Required: - account_id: the RealtyAds property account that should target this company. Must be an account the caller has access to. - company_name: the company name to add. Used verbatim as the firm_name on the row. Strongly recommended (provide whatever you have — both is fine): - linkedin_company_url: a full LinkedIn URL like "https://www.linkedin.com/company/jll/" or a "/company/{slug}" tail. The slug can be a vanity name ("jll") or a numeric id. - linkedin_company_id: numeric LinkedIn company id, when you already know it from search_companies, lookup_company_information, get_companies_reached, etc. When a LinkedIn id is supplied (or resolved from the URL via our local cache), the row is written fully matched so ad delivery picks it up immediately, the company is removed from any active exclusion list, and partner-pursuit / partner-integration "do not target" flags for the same company are cleared. When only a name is supplied, the row is queued for the matching cron — typically resolved within an hour, but the company isn't actively targeted until then. Returns: - action_taken: "added", "already_targeted", or (rare) an error message - targeted_firm_id: the id of the new row in realty_client_targeted_firms (or the existing active row, when already_targeted) - account_id, company_name, canonical_company_name - linkedin_company_id: the id used on the row, when resolved - matched_via: "linkedin_company_id" | "linkedin_company_url_numeric" | "linkedin_company_url" | "name_only" - queued_for_matching: true when we wrote a name-only row that the cron still needs to match Idempotent on the (account_id, linkedin_company_id) pair: re-adding a company that's already actively targeted returns action_taken="already_targeted" and does not create a duplicate row. Re-adding by name alone (no LinkedIn id) does not de-duplicate — every name-only call creates a fresh row, matching the portal's "manual entry" precedent. This is a WRITE action. It is logged in the portal activity feed under the calling user.
Add one contact to a RealtyAds account's targeted-users list so the ad system starts targeting that person. Clears an existing per-contact exclusion when present. Provide at least one of: contact_id, linkedin_profile_url, work_email, personal_email, cell_phone, or the trio first_name + last_name + company_name. Use this tool when the user wants to start targeting a specific individual through their RealtyAds account. The contact is added to the same targeted-users list the portal's "Decision-Maker Targeting" UI writes to, and ads from this account will start including them. Required: - account_id: the RealtyAds property account that should target this contact. Must be an account the caller has access to. - exactly one of the identifier groups below. Identifier groups (provide whichever you have — more specific is better): - contact_id: internal RealtyAds contact id (e.g. from lookup_contact_information, get_company_decision_makers, get_website_visitors) - linkedin_profile_url: full LinkedIn URL like "https://www.linkedin.com/in/jane-smith/" or the "linkedin.com/in/jane-smith" tail. We synchronously look the profile up so the contact is fully populated before being added. - work_email: e.g. "[email protected]" - personal_email: e.g. "[email protected]" - cell_phone: digits-only is fine; we normalize for matching. - first_name + last_name + company_name: all three required if you go this route. Optional context (job_title, city, state) improves the stub record we create when no existing match is found. If the contact is already on file we attach the targeting row to that record. If they're not on file, we create a new contact record from the fields you provided and attach to that — background enrichment will then fill in additional details over the next few minutes. If the contact was previously on the account's exclusion list, that exclusion is cleared. Returns: - action_taken: "added" or "already_targeted" - targeting_user_id: id of the new row on the targeting list (or the existing row, when already_targeted) - audience_data_contact_id: internal contact id used on the targeting row - account_id, first_name, last_name, job_title, company_name, linkedin_profile_url - resolved_via: which input identifier matched — "contact_id", "linkedin_profile_url", "work_email", "personal_email", "cell_phone", "name_and_company", or "created_new_contact" - created_stub_contact: true when no existing contact matched and we created a new record - message: short human-readable summary Idempotent on the (account_id, audience_data_contact_id) pair: re-adding a contact that's already actively targeted returns action_taken="already_targeted" and does not create a duplicate row. This is a WRITE action. It is logged in the portal activity feed under the calling user.
Bulk version of add_contact_to_targeting: add many contacts to one RealtyAds account's targeted-users list in a single call. Per-entry behavior matches the singular tool — supply at least one identifier (contact_id, linkedin_profile_url, work_email, personal_email, cell_phone, or name+company). Use this tool when the user wants to add multiple contacts to a RealtyAds account's targeted-users list in one go — for example after pasting a CSV of contacts they want targeted, or applying a list of decision-makers exported from another system. Per-entry behavior is identical to add_contact_to_targeting. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - contacts: a JSON array of objects (up to 100 entries). Each entry needs at least one of: - contact_id (internal RealtyAds contact id) - linkedin_profile_url (full URL or "linkedin.com/in/..." tail) - work_email - personal_email - cell_phone - first_name + last_name + company_name (all three required when going this route) Optional context fields per entry: job_title, city, state — used to populate the contact stub when no existing match is found. Per-entry behavior (same as add_contact_to_targeting): - Resolves the contact via the priority order above (contact_id → linkedin_profile_url → work_email → personal_email → cell_phone → name+company). - When no existing contact matches, creates a stub audience_data.contacts row from the supplied fields and attaches the targeting row to it. - Idempotent on (account_id, audience_data_contact_id): re-adding an already-targeted contact returns action_taken="already_targeted" without creating duplicates. - Clears the contact from the account's exclusion list when present. - Logs "Updated Decision-Maker Targeting" / "Added a decision-maker to targeting" with action_source="mcp". Errors are per-entry, not per-batch. A bad row (no identifier supplied, etc.) returns action_taken="failed" with an "error" string. The top-level response carries counts (added / already_targeted / failed) so the caller can see at a glance what happened. This is a WRITE action. Every successful add is logged under the calling user and shows up in the portal activity feed.
Add one custom job title to the targeted-job-title list for a RealtyAds account so decision-makers with that title at the account's target companies become eligible to see ads. Looks up the LinkedIn title id from a job-title name when one is not supplied. Use this tool when the user wants RealtyAds AI to specifically target a job title across the account's target companies — "add VP of Real Estate to our job-title targeting", "we want to reach Heads of Workplace", "target Chief People Officers". What it does (mirrors the portal): - Looks up the LinkedIn-canonical title id from the supplied name (cached typeahead; falls back to live LinkedIn API when cache is cold). - Skips silently if the title is already on the account's targeting list (idempotent). - INSERTs into r1.realty_client_targeted_job_titles. - Logs to r1.user_change_log under "Updated Job Title Targeting" with action_source="mcp". The portal itself does not log this action — MCP writes are logged for AI auditability. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - title_name: the job title to add (e.g. "VP of Real Estate"). Should be a common LinkedIn-style title — uncommon phrasings may not resolve to a LinkedIn id. Optional: - title_id: the LinkedIn title id (numeric tail of `urn:li:title:<n>`, as a string). Use when you already know it (e.g. from a prior `add` response's `title_id`). When omitted, the tool will look it up by name. Returns: - action_taken: "added", "already_targeted", or "no_match" (if the typeahead couldn't resolve a title id) - row_id, account_id, title_id, title_name - matched_via: "explicit_title_id" / "linkedin_cache" / "linkedin_api" - candidates: up to 5 alternative typeahead matches (returned only when there's ambiguity, so the caller can confirm the right one was picked) - message: short human-readable summary Pair with `get_ad_targeting` (which lists current job titles in `filters.job_titles`, each with a `row_id`) and `remove_custom_job_title_from_targeting` (which takes the row_id). This is a WRITE action.
Add one geography (city / metro / region) to the targeted-geographies list for a RealtyAds account so people and companies in that geography become eligible to see ads. Looks up the LinkedIn geo id from a name when one is not supplied. Use this tool when the user wants to expand targeting to a new geography — "also target tenants in Jersey City", "add Greenwich, Connecticut to our targeting", "we want to reach brokers in Atlanta". What it does (mirrors the portal): - Looks up the LinkedIn-canonical geo id from the supplied name (cached typeahead; falls back to live LinkedIn API when cache is cold). - Skips silently if the geography is already on the account's targeting list (idempotent on (account, geo_id)). - INSERTs into r1.realty_client_targeted_geos with `target_cre=1, target_companies=1` by default (matching the portal default — geo applies to both broker reach and company reach). - Logs to r1.user_change_log under "Updated Geography Targeting" with action_source="mcp". The portal itself does not log this action — MCP writes are logged for AI auditability. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - geo_name: the geography to add. Be as specific as possible — "Atlanta, Georgia, United States" resolves more reliably than just "Atlanta". Optional: - geo_id: the LinkedIn geo id (numeric tail of `urn:li:geo:<n>`, as a string). Use when you already know it. - target_cre: (default true) include this geography when targeting commercial real-estate brokers. - target_companies: (default true) include this geography when targeting companies / decision-makers. Both can be set to false, but at least one should be true or the row has no effect. Returns: - action_taken: "added", "already_targeted", or "no_match" (if the typeahead couldn't resolve a geo id) - row_id, account_id, geo_id, geo_name, target_cre, target_companies - matched_via: "explicit_geo_id" / "linkedin_cache" / "linkedin_api" - candidates: up to 5 alternative typeahead matches (returned only when there's ambiguity) - message: short human-readable summary Pair with `get_ad_targeting` (which lists current geos in `geography.submarkets`, each with a `row_id`) and `remove_geography_from_targeting` (which takes the row_id). This is a WRITE action.
Add a file to the account's media library from a public http(s) URL. Additive — it never deletes or overwrites existing media. Returns the new asset's id and CDN URL. Fetches the file at source_url (a public http(s) URL) and stores it in the account's media library. Optionally attach a short description and tags to help the user find it later. This is additive — it never deletes or overwrites existing media. Use list_media_library to see what is already there. Returns the new media_id, cdn_url, and media_type. This is a WRITE action.
Definitive check whether a specific contact or company is on an account's active target list, exclusion list, or neither. Returns a boolean membership result — no list scanning needed. Always prefer this over searching get_ad_targeting results when you need to verify a single entity's targeting status (get_ad_targeting lists are capped, so absence from that sample does not prove an entity is untargeted). Provide account_id plus at least one of contact_id (checks the individual target/exclusion lists) or linkedin_company_id (checks the company target/exclusion lists). You may pass both. The response includes on_target_list / on_exclusion_list booleans and, for companies, previously_targeted (soft-removed) plus target/exclusion detail blocks when present.
Build a new, non-live saved ad with custom copy and optional media-library images. Use media ids returned by list_media_library or add_media_to_library. When media_ids is omitted, the campaign's current images are inherited. The name is only the saved-ad label, not the ad copy. The result is not live; call launch_saved_ad separately after explicit user confirmation.
Duplicate an existing saved ad into a new, non-live saved ad on the same campaign. Copies the source saved ad exactly, including copy, media, and landing page. Use update_saved_ad afterward only when the duplicate should differ.
Add one company to a RealtyAds account's exclusion list so ads on this account will never target the company, even when other targeting signals would otherwise match. Stronger than remove_company_from_targeting — works even when the company isn't on the targeting list yet. Use this tool when the user wants to permanently keep a company off ads on a RealtyAds account — "exclude Microsoft from targeting", "we never want our ads to reach Apple employees", or to block a known-irrelevant tenant or competitor. Difference vs remove_company_from_targeting: - remove takes a company OFF the active targeting list. The matching cron could later re-add them based on other signals. - exclude is sticky — the company is registered as "do not target" so the matching cron, partner-pursuit signals, and other paths can't bring them back. Use exclude when the user really doesn't want this company ever targeted on this account. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - linkedin_company_id: numeric LinkedIn company id (use search_companies or lookup_company_information to resolve a name first). - company_name (optional but recommended): used as the firm_name on the exclusion row when supplied; otherwise we use the canonical name from RealtyAds' LinkedIn cache. Side effects (matches portal exactly): - INSERTs a row on the exclusion list. - Deactivates any matching active row on the targeted-firms list (so the company drops off active targeting immediately). - Scrubs the company from r1.linkedin_company_targeting. - Sets partner-pursuit and partner-integration "block" flags on for the (account, company) pair — unconditional, no guard. Returns: - action_taken: "excluded" or "already_excluded" - excluded_firm_id, account_id, linkedin_company_id, company_name - message: short human-readable summary Idempotent: re-excluding a company that's already on the exclusion list returns action_taken="already_excluded" with no writes. This is a WRITE action. Logged in r1.user_change_log under the calling user with action_source="mcp".
An account's setup and optimization assessment: a one-stop summary, per topic, of whether the account is fully optimized or has a specific opportunity to get more value out of RealtyAds. Reports, per topic, whether the account is fully optimized or has a specific opportunity — targeting setup (competition set / individual / company), the Insights Tag, integrations (CRM / deal-flow via Partner Hub), report engagement, content freshness, and the Chrome/Edge extension. Also returns last_content_change: the account-level datetime of the most recent ad content edit (Updated Ad Text / Images / Video / Loaded Saved Ad) from the same user_change_log the portal dashboard uses. Present even when the Content tip is "Fully Optimized" and does not name the date in prose; null when no edit has been logged. Use this for "what can I do to optimize my account?", "is my account set up right?", "when was content last changed?", or before nudging on infrastructure so you only recommend what's genuinely missing (never tell a client to connect a CRM they already have). Requires account_id.
Monthly reporting card for one account, with totals and insights across each active RealtyAds service. Use when the user asks 'how did account X do in <month>?', 'what were last month's ad results?', 'who visited the website in May?', 'is the broker reach hitting target?', or any other broad performance question. Requires `account_id`. `year_month` defaults to the most recently completed calendar month (previous month); pass `YYYY-MM` (e.g. `2025-08`) to drill into a specific historical month. Response sections (each omitted when there's no data for the period): - `digital_ads_stats`: totals (hyper_targeted_views, unique_companies_reached, frequency, clicks), broker_reach (target % vs actual %, YTD avg, months beating target), tenant_reach (target / actual companies, multi-month engagers), per-ad-network breakdown. - `website_stats`: page_views, unique_visitors, new_visitors, returning_visitors, total_companies, new_companies, high_engagement_companies, desktop_visitors, mobile_visitors (all sourced from the same monthly cache the portal renders), plus identified_contacts and decision_makers_identified (deduped by contact_id) and a companies-that-also-saw-ads cross-signal. `services_reported` advertises the section names emitted in this response (e.g. `["digital_ads_stats", "website_stats"]`) so the LLM can look up the matching block directly. Always returns the period metadata (`is_current_month`, `is_partial`), the account's `services_active_now`, and a `headline` prose summary the LLM can quote directly. Sections about services that weren't active or had no data are omitted entirely — absence means 'no activity', not 'zero'. Response also carries two curated, per-topic prose blocks: - `insights_summary` (keys: `overview`, `current_month`, `broker_reach`, `tenant_reach`, `website_services`, `digital_ads_upsell`, `website_services_upsell`) — mirrors the portal AI Assistant's response to 'How is this account performing?'. - `optimization_insights` (keys: `intro`, `functionality`, `website_analytics`, `report_engagement`, `content`, `integrations`, `chrome_edge_extension`; special: `not_active` / `no_digital_ads`) — mirrors the portal AI Assistant's response to 'How can I further optimize this account?'. Quote these back to the user verbatim. Do NOT paraphrase or re-derive these sentences from the raw structured fields — the prose is deliberately curated to lock in tone, accuracy, and the specific RealtyAds value-prop framing (broker reach vs industry standard, projection-vs-actual sentiment, multi-month engagement, content rotation cadence, etc.). The prose paragraphs contain markdown links (`[label](url)`) to RealtyAds reporting pages, pursuit-profile drill-downs, browser-extension stores, and Account Manager mailto: addresses — the same set of links the portal AI Assistant renders. Pass them through verbatim. Each paragraph also has a parallel `<key>_references` array (e.g. `tenant_reach_references`, `functionality_references`) listing every link as `{label, url, type}` for clients that render plain text or want to format links differently. Link `type` is one of: `report` (portal page), `pursuit_profile` (company drill-down on the tenant reach report), `download` (XLSX/file), `mailto` (AM email), `extension` (browser extension store). Note on vocabulary: `hyper_targeted_views` is the RealtyAds-branded name for ad impressions delivered through the account's targeting filters. Use it instead of generic 'impressions' when describing the data to a user.
Generate the same Activity Report (PDF and/or XLSX) the portal produces. Chronological platform activity (AI optimizations, client actions, account-manager events) for one or more accounts in a given month. Use this tool when the user wants the monthly Activity Report — "what happened on the account last month", "send the activity report PDF", "give me the activity feed as Excel". What it does: - Pre-fetches `/ajax/account_activity_feed/?method=read` (POST) for the month with context=main. - For PDF: posts the standard stats payload to /reporting/downloads/generate_pdf/. The PDF template re-fetches activities server-side using account_id_list + year_month. - For XLSX: hits /ajax/budget_optimizations/?method=read_xlsx with activity_feed_only=true (shared endpoint with AI Report, distinguished by the flag). Inputs: - account_ids (optional): subset to include. Defaults to all the caller's accounts. - year_month (optional): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Lite-account gating: the portal blocks Activity Report when ALL selected accounts are Lite. This tool surfaces the portal's rejection as a tool error. Activity data is only available from 2024-08 onward (per portal logic).
List the account's ad campaigns with each campaign's property, active state, current ad copy, saved ads (saved_ad_id + name), and rotation-schedule state. For each campaign returns its internal campaign_id (plumbing — never print it to the user), the property it advertises, whether it is active, the current ad copy, its saved ads (each with a saved_ad_id and name), and its rotation-schedule state. This is the entry point for ad management — call it first to get the campaign_id and saved_ad_id values used by the saved-ad authoring, launch, and scheduling tools. Requires account_id.
Compare an account's ad creatives by hyper-targeted views and site visits for a date range. Use this tool for creative-level ad performance: which creative performed best, how individual ads compare, or whether image or video creatives performed better in a date range. Requires account_id, start_date, and end_date (YYYY-MM-DD). Creatives are ordered by hyper-targeted views. Returns one row per creative plus by_creative_type totals and per-creative averages. `hyper_targeted_views` is the RealtyAds name for ad impressions. `site_visits` matches the Ad Report's client-facing label for ad clicks. Use the metric the user asked about when naming a winner; do not claim one creative or media type performed better overall when the returned metrics disagree. Use get_ads instead when the user wants ad copy, media, landing pages, or previews. Use get_account_performance for broad account-level reporting.
Read every targeting setting currently applied to a RealtyAds account — who is being targeted (industries, job titles, company sizes), where (submarkets, geo-fencing), the account's target audiences, and the account's target / excluded company and individual lists. Use this tool when the user asks any question about who the account is currently targeting — "who are we targeting?", "are we targeting tech companies?", "what's on the target list?", "is power prospecting on?", "how big is the exclusion list?", "are we hitting submarket X?", or as a sanity-check before suggesting changes via the targeting write tools. Returns a single bundle that mirrors the portal's Targeting Settings page, restructured into plain-English fields. Empty sections are omitted entirely (absence means "not configured" / "not applicable" — never "zero"). Top-level fields always present: - account_id, account_name, account_category (Office / Multi-Family / Industrial / Retail / Medical / Life Science / Land), optimization_goal ("reach" or "clicks") - headline: one-sentence summary the LLM can quote verbatim ("Currently targeting commercial real estate brokers and tenants in the market across 7 industries; 142 companies and 5 individuals on the targeted lists; 2 companies excluded.") - target_audiences: the proprietary RealtyAds audiences the account is reaching (Commercial Real Estate Brokers, Tenants In The Market, Asset Managers & Property Owners, Residential Real Estate Brokers, and the bookkeeping entries for the account's own uploaded lists). Each carries `group_id`, `name`, and `included: true/false`. Use the group_id with update_target_audience_groups_targeting to flip a group on or off. - filters: industries (each `{industry_id, name}`), detailed_categories (vertical-specific sub-segments, when applicable; each `{industry_id, name}`), job_titles (each `{row_id, title_id, name}` — use row_id with remove_custom_job_title_from_targeting), company_size_buckets. industry_id values are reusable with update_industry_targeting. - geography: submarkets (each `{row_id, geo_id, name}` — use row_id with remove_geography_from_targeting), geo_fencing (bool), competition_buildings (address list), colleges (multi-family only). - growth_signals: power_prospecting, coworking_targeting, funding_targeting, site_selectors_targeting — each a bool. Use update_growth_signal_targeting to flip any of these. - vertical_specific (only when applicable): live_work_play_targeting, ideal_tenant_targeting (multi-family), life_science_investor_targeting, life_science_funding_stages, life_science_clinical_stages. Use update_vertical_targeting to flip the bool toggles (geo_fencing, live_work_play_targeting, ideal_tenant_targeting, life_science_investor_targeting). - target_companies: { total, shown_in_response, has_more, next_offset?, companies[] }. Each company carries `targeted_firm_id` (use with set_company_targeting_priority / remove_company_from_targeting), company_name, linkedin_company_id (when LinkedIn has been matched), date_added, and priority (always present: "low" / "normal" / "high" / "boosted"; "normal" is the default). Sorted newest-first; capped at 200 per response with `has_more=true` when the full list is larger — page the rest via the `list` arg (see Pagination below). Match-quality internals are not exposed; do not speculate about how well a row is matched. - target_individuals: { total, shown_in_response, has_more, next_offset?, individuals[] }. Each individual carries `targeting_user_id` (use with set_contact_targeting_priority / remove_contact_from_targeting), first_name, last_name, job_title, company, location, priority (always present: "low" / "normal" / "high"; "normal" is the default), date_added. **Email and phone are intentionally NOT included** — pulling those is out of scope for this read tool. - excluded_companies: { total, shown_in_response, has_more, next_offset?, companies[] }. Each carries company_name, linkedin_company_id, date_added. Use unexclude_company_from_targeting (with linkedin_company_id) to remove a company from this list. - always_on: a list of audiences that RealtyAds runs on every account regardless of settings — e.g. "remarketing", "proprietary_realtyads_audiences", "online_behavioral_patterns". Surfaced so the LLM doesn't tell the user "we're not targeting anyone" when the toggleable sections are empty. Pagination — fetching a full long list: Each long list (target_companies, target_individuals, excluded_companies) is capped at 200 entries per response. `total` always reflects the true count; `has_more` indicates truncation and `next_offset` tells you where the next page starts. To page through one full list, call this tool again with the optional `list` arg set to "target_companies", "target_individuals", or "excluded_companies", plus `offset` (from the previous response's `next_offset`) and optionally `limit` (default and max 200). In list mode the response contains ONLY that list page — { list, total, offset, shown_in_response, has_more, next_offset?, companies[]|individuals[] } — not the rest of the bundle. Keep calling with the returned `next_offset` until `has_more` is false to retrieve every entry (e.g. a 759-company target list takes 4 calls). Entries are sorted newest-first consistently across pages. Companion targeting WRITE tools (all in the "targeting" family): - add_company_to_targeting / add_companies_to_targeting — append to target_companies - remove_company_from_targeting / remove_companies_from_targeting — remove from target_companies (auto-excludes) - exclude_company_from_targeting — append to excluded_companies (sticky block) - unexclude_company_from_targeting — remove from excluded_companies - add_contact_to_targeting / add_contacts_to_targeting — append to target_individuals - remove_contact_from_targeting — remove from target_individuals (auto-excludes the contact) - add_custom_job_title_to_targeting / remove_custom_job_title_from_targeting — change filters.job_titles - add_geography_to_targeting / remove_geography_from_targeting — change geography.submarkets - set_company_targeting_priority — Low / Normal / High on one target_companies entry - set_contact_targeting_priority — Low / Normal / High on one target_individuals entry - update_target_audience_groups_targeting — flip target_audiences groups on/off - update_industry_targeting — replace the full industries / detailed_categories set - update_company_size_targeting — replace the full company_size_buckets set - update_growth_signal_targeting — flip the four growth_signals toggles - update_vertical_targeting — flip vertical / specialty toggles (geo_fencing, live_work_play, ideal_tenant, life_science_investor) Always call this tool FIRST to read current state before modifying anything, so the write tools target the right ids and the user sees a meaningful diff. Do not use this tool to list the companies that have already SEEN the ads — that's get_companies_reached.
List the ad creatives for an account (currently-running and saved), including ad text, media, landing page URL, and a portal preview URL. Use this tool when the user asks about their ads — what they currently look like, what saved versions exist, what ad copy or images are being used, what the landing page is, or to get a preview URL for a specific creative. Returns one entry per ad creative tied to the account. Each entry includes: - id: stable saved-template id (use as a reference in follow-up questions) - name: display name for the creative - status: "live" (currently running), "saved" (a saved option), or "archived" - creative_type: "image" or "video" - ad_text: the ad copy shown to viewers - call_to_action: button text (e.g. "Learn More", "Schedule a Tour") - media: ordered list of image URLs for image ads, or [video_url] for video ads - landing_page_url: where clicks send the viewer - preview_url: public RealtyAds page that renders the ad inside a phone-bezel mockup with buttons to switch between Facebook, Instagram, LinkedIn, Google, and X previews. Safe to share with the end user — no login required. - date_created: when that saved version was first stored (not the account-level last content edit) - last_updated: when that creative's content was last saved, including Edit Ad Media / campaign-block saves when the saved-template row itself has no usable timestamp The live ad is always returned first, followed by saved options newest-first. Archived ads are excluded unless include_archived is true. Defaults to all live + non-archived saved creatives for the account. Pass account_id (required) and optional include_archived (bool) and limit (int, default 50, max 200). Do not use this tool for creative-level performance metrics — use get_ad_creative_performance. Use get_account_performance for broad account-level reporting. Do not use it to list companies who saw the ads — use get_companies_reached.
Generate the same AI Report (PDF and/or XLSX) the portal produces for one account and one month. Includes per-platform spend, views, clicks, AI optimization counts, and the exposure chart. Use this tool when the user wants the monthly AI Report — "send the AI report for [account]", "what did RealtyAds AI do last month", "I want the AI optimizations PDF". What it does: - Pre-fetches three AJAX endpoints the portal JS gathers: 1. /ajax/budget_optimizations/?method=read — per-platform stats 2. /ajax/account_activity_feed/?method=read — AI activity (counted by platform) 3. /ajax/budget_optimizations/?method=react_chart_exposure — exposure chart series - For PDF: posts the assembled payload to /reporting/downloads/generate_pdf/. - For XLSX: hits /ajax/budget_optimizations/?method=read_xlsx with the same scope. Inputs: - account_id (required). - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Lite-account gating: portal blocks AI Report for Lite accounts (server-side in generate_pdf). When the account is Lite, the bridge call fails with the portal's "this report is unavailable on the current subscription" message — surfaced as a tool error.
Generate the same Broker Reach Report (PDF and/or XLSX) the portal produces for one account and one month. Includes monthly + YTD reach stats and the broker roster with targeting tactics. Use this tool when the user wants the monthly Broker Reach Report — "send the broker reach for [account]", "I want the broker roster as Excel", "give me the broker reach PDF". What it does: - Pre-fetches `/ajax/broker_reach_report/?method=performance_stats` for the account + month. - For PDF: posts to `/reporting/downloads/generate_pdf/` with the full reach-stats payload. (The portal's per-page handleShare path is broken — it omits broker_stats and the template exits. This tool uses the working Reporting Center payload shape.) - For XLSX: posts `read_xlsx` to `/ajax/broker_reach_report/` with the same stats. Inputs: - account_id (required). - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Returns a text summary containing the direct download URL(s) (always show them to the user) + one or two `resource_link` items, 24-hour expiry. Gating: blocked when broker reach is disabled for the account (no broker or audience targeting configured). The tool surfaces a clear error rather than producing an empty report.
List companies reached by an account's ads for a month range, including why each company was targeted. Use this tool when the user asks which companies saw or engaged with their ads, who was reached in a month or range of months, or why specific companies were included in their targeting. Requires account_id. start_year_month and end_year_month are optional YYYY-MM values; when omitted, both default to the most recently completed calendar month. These inputs select whole calendar months, not an exact rolling-day window. response_mode controls the shape: - "monthly" (default) returns one independent canonical Tenant Reach result per calendar month. Filters, sorting, and limit are applied separately to each month. - "combined" groups a multi-month range by company before sorting and limiting. It returns unique_companies_reached, repeat_engager_count, the account-level period total, and each company's months_reached plus server-computed aggregate Hyper-Targeted Views. A one-month combined request is normalized to the standard monthly response. Monthly mode may span up to 12 calendar months. Combined mode may span up to 3 consecutive calendar months. Never add monthly company counts or capped monthly views yourself. Use combined mode when the user wants one unique company list or aggregate view across multiple calendar months. In monthly mode, the default sort_by="relevance" preserves the Tenant Reach Report and PDF's default highest-relevance order (targeting method, explicit priority, and decision-maker availability). In combined mode, "relevance" ranks sustained reach first (months_reached, then aggregate views). Use sort_by="views_desc" only when the user asks for "most views", "most engaged", or "top engagers by views"; use "views_asc" for least views. tenant_filter mirrors the report's Advanced Search segments: - "all" (default) — every successfully engaged tenant - "ai_prospecting" — only tenants identified through AI Prospecting - "client_targeting" — only tenants engaged from client targeting Apply tenant_filter="ai_prospecting" whenever the user explicitly asks for AI-prospected engagers. Do not infer that a high-engagement or client-targeted company is an AI prospect. Monthly output mirrors the Tenant Reach Report company list and caps per-company hyper_targeted_views at "500+". Combined output never exposes an uncapped per-company aggregate: totals through 500 are exact, totals from 501–999 are "500+", and totals of 1,000 or more are "1,000+". The account-level period total remains exact, matching the quarterly report overview aggregate. Company rows also include the LinkedIn company page, estimated company size from LinkedIn profile counts, 6/12/24 month employee growth rates when cached, industry, website URL, compact reasons_targeted keys, targeting_reason_definitions, and targeting_priority. Each company includes reasons_targeted (array of keys). targeting_reason_definitions maps those keys to reporting titles and descriptions for this response — use it for labels; do not invent reason names. A company can have multiple reasons. These keys explain why a company was targeted; tenant_filter uses the same primary classification as the report's Advanced Search. Common reason keys (not exhaustive; prefer definitions in the response when present): - ai_prospecting — AI Prospecting: companies surfaced by RealtyAds AI from decision-maker / opportunity signals - list_upload — Broker Prospecting: companies from a client-uploaded target list - detailed — Detailed Industry Prospecting: companies prioritized for selected industries - activity_report — Activity Report Prospecting - partner_hub — Partner Hub / CRM-linked prospecting - competition — Competition Prospecting - funding — Funding Prospecting - proprietary — Proprietary Audience Prospecting Do not use this tool for website visitors; use get_website_visitors for website-specific traffic. Do not use it for broad account performance summaries; use get_account_performance.
Return the top decision-makers at a company, ranked by the same pursuit-profile algorithm the portal uses. Requires a LinkedIn company id or LinkedIn company URL. Default 3 contacts, max 15. Use this tool when the user wants the most relevant senior contacts at a specific company — "who should we reach out to at JLL?", "give me the top decision makers at Acme", or any prelude to a follow-up like add_contact_to_targeting (coming soon). Required (pass exactly one): - linkedin_company_id: numeric (the id you already have from search_companies, lookup_company_information, get_companies_reached, etc.) - linkedin_company_url: a full LinkedIn URL like "https://www.linkedin.com/company/jll/" (or just the "/company/{slug}" tail; numeric slugs work too) Resolution order: linkedin_company_id wins, then linkedin_company_url. Optional: - max_decision_makers: default 3, max 15. Caller can ask for a deeper list when the user wants more candidates. Anything above 15 is clamped. Returns: - linkedin_company_id, company_name, linkedin_profile_url, resolved_via - decision_makers_shown, max_decision_makers (the cap that was applied) - decision_makers: array of contacts, each with contact_id, first_name, last_name, job_title, linkedin_profile_url, profile_image_url, work_email, phone, follower_count. Empty contact-info fields are omitted from each entry. Ranking is the same pursuit-profile algorithm the portal renders: targeted-user boost, country / state proximity, account-specific exclusions, executive-assistant / inflated-follower penalties, and ChatGPT-DM augmentation. Because the algorithm is account-scoped, the tool automatically picks one of the caller's accounts as the ranking context — preferring an account that's actively targeting the company, then one that has reached the company via ads, then any active account, then any account. If none of the caller's accounts has a signal for the company (relevant when the caller is an internal RealtyAds user with no account-specific context), the decision_makers array is empty and a `warnings` entry explains why. Do not use this tool to find a company by name — that's search_companies. Do not use it for the full company profile bundle — that's lookup_company_information (which also embeds up to 10 decision-makers if you only need a quick top-of-list view alongside other company info).
How a single company is engaging an account's properties: a month-by-month trend of that company's hyper-targeted ad engagement (impressions), with first-engagement date, averages, peak month, and largest swings. Use this for "how is this company engaging my properties?". Does NOT require a connected CRM or activity-report upload — prefer this over get_deal_attribution for plain engagement questions. Returns engaged:false (not an error) when the company has no recorded ad engagement on the account yet. Requires account_id and the company's linkedin_company_id (the same id returned by get_companies_reached, search_companies, get_top_prospects, etc.). The response includes total_months, total/average monthly engagements, peak_engagement, largest_increase / largest_decrease, and a monthly_timeline array. For a specific period total, pass both start_year_month and end_year_month in YYYY-MM format. The response then includes requested_period.total_hyper_targeted_views, computed from the returned monthly data. The current incomplete month is excluded.
Get a contact's work email and phone numbers by contact_id (preferred), LinkedIn URL, email, or contact_id_partner_network (credit-gated; consumes 1 lookup credit per successful enrichment). Use this tool when the user explicitly asks for someone's email address, phone number, or contact details. This is a credit-gated operation that consumes one credit per successful lookup from the user's included monthly allowance. Pass whichever identifier you have (exactly one), preferring contact_id when you have one: - contact_id: use when you already have one from a prior tool call (e.g. get_company_decision_makers, get_website_visitors, get_companies_reached). Preferred — fastest and unambiguous. A contact_id_partner_network is a different id; never pass one in this field. - linkedin_profile_url: a full LinkedIn URL like "https://www.linkedin.com/in/jane-smith/" or the "linkedin.com/in/jane-smith" tail. The contact is resolved automatically before enrichment. - email: a work or personal email address. Looked up against existing contacts. - contact_id_partner_network: the id returned by search_contacts. The contact is resolved automatically before enrichment. Returns the person's work email, mobile phone, and work phone. The data is enriched synchronously via multiple contact-data providers, with smart merge logic (provider agreement beats domain match beats fallback). Enriched values apply to this response only and are not written back to the shared contact record. Each returned field carries a confidence label in the `confidence` map (high / medium / low) — relay low confidence to the user as "possibly outdated" rather than presenting the value as certain. Credit reporting: `credit_charged` states whether THIS lookup consumed a credit — lookups that find no contact information are free. `credits_used_this_month` and `credits_remaining_this_month` are the user's month-to-date running totals, NOT the cost of this call; a single lookup never costs more than 1 credit. If credits are exhausted, the tool returns an error explaining the limit.
How a single person is engaging an account's properties — their employer's company-level ad-engagement trend (a proxy) plus person-level website-visit, deal-pipeline, and targeting signals. IMPORTANT: LinkedIn ad impressions are tracked at the company level, not per individual — so the ad-engagement trend returned (employer_ad_engagement) is this person's CURRENT EMPLOYER's month-by-month engagement (the best available proxy), not the individual's own impression count. Present it that way to the user. On top of that company proxy, this adds genuinely person-level signals: whether THIS person specifically has been identified visiting the account's website (count + last visit), whether they appear in the account's connected-CRM deal pipeline, and their targeting status + priority. Use this for "how is this person engaging my properties?", "how active is this broker with us?", or "what's this contact's engagement?". Returns employer_ad_engagement.engaged=false (not an error) when the employer has no recorded engagement, and flags when the person has no linked employer company. Requires account_id and contact_id (the audience_data id from lookup_contact_information / current_target — NOT a contact_id_partner_network). If individual_visitor_data_restricted is set, person-level website visit verification was suppressed for this account. Cannot verify that a specific individual visited the website due to local privacy laws; company visitor lists and decision-makers at those companies remain available.
Returns RealtyAds' influence and engagement timeline across all active tenant deals on a RealtyAds account, grouped by tenant company. Includes monthly engagement, current deal stage, decision-makers reached, and (when known) employee growth signals. Requires a connected CRM or an activity-report upload within the last 6 months. Use this tool when the user wants the deal-attribution picture for a RealtyAds account — "what deals are we influencing?", "which pursuits has Kalshi turned into?", "which tenants are we reaching and what stage are they in?", or any question that pairs deals with RealtyAds engagement. Required: - account_id: the RealtyAds property account to report on. Must be an account the caller has access to. Optional: - linkedin_company_id: drill down to one tenant company. - deal_stages: comma-separated list of stages to include, e.g. "Tour" or "Proposal,LOI". Default excludes Dead and Lease Executed; recommend leaving as default unless the user is hunting for a specific stage. - limit: max companies returned. Default 25, max 100. The response is sorted with the most-engaged companies first. - include_monthly_timeline: default true. Set false to skip the per-month engagement bars when only the headline metrics are needed (smaller response). Eligibility: this report needs CRM data to compute deal stages. If the account has neither a connected CRM nor a recent activity-report upload, the response carries: - eligible: false - partner_hub_url and support_email - a message explaining how to enable the report Report scope: fixed 24-month lookback ending in the current calendar month. There is no timeframe input — RealtyAds influence accumulates over a long pursuit cycle, so the report always covers the full window. Response shape: - account_id, report_period (start_month / end_month / lookback_months) - eligibility_source: "crm_integration" or "activity_report_upload" - deal_stage_filter: human-readable summary of what was filtered - total_companies, shown_in_response, has_more - companies[] — each entry contains: - linkedin_company_id, company_name, logo_url, industry, headquarters, locations_count - employee_count, employee_growth_rate_6_month / _12_month / _24_month - current_deal_stage ("Tour", "Proposal", etc.) - deal_data_source[]: the partners that contributed deal data for this tenant — e.g. ["vts"], ["hubspot"], ["salesforce"], ["activity report upload"], or a combination like ["vts", "activity report upload"] when both sources have data. Alphabetically sorted. - crm_deal_ids[] — when at least one source is a CRM (anything other than "activity report upload"), the underlying CRM deal ids associated with this tenant (one company can have more than one) - identified_by_realtyads_ai (bool) - targeted_for_engagement (month label), first_engagement (month label) - months_with_engagement, total_hyper_targeted_ad_views, total_website_page_visits - website_services_active (bool) - decision_makers[]: name, job_title, linkedin_profile_url, profile_image_url - deal_stage_history[]: ordered stages with started_at / last_seen dates - monthly_timeline[]: per-month bars with hyper_targeted_ad_views, website_visits, prospect_boosting_active, deal_stage (when known) The "Identified by RealtyAds' AI" flag is account-level (one stable signal per company), not per-month — same as the portal's pursuit-profile chart legend. Do not use this tool to list every company reached by ads (that's `get_companies_reached`) or to inspect targeting settings (`get_ad_targeting`). Use this when the user wants to understand the deal pipeline + RealtyAds' contribution.
Read the current portal Insights Tag status for one account. Returns the same finalized Insights Tag status shown in the client portal. Use when the user asks whether the Insights Tag is active for a property. Statuses: `active` (tracking visitors), `no_traffic` (tag active on a RealtyAds landing page but no visitors yet), `waiting` (not activated yet), `issue` (recently stopped reporting), or `stale` (stopped reporting a long time ago). `last_activity_date` is the latest relevant pixel or visitor activity date when available.
List active leads for an account — individual contacts plus the reasons they qualify as a lead (website visit, CRM, form fill, ad view) and their current lifecycle stage. Use this tool when the user asks about their leads, prospects, or pipeline — who's been engaging with the property, who's in the CRM, who filled out an inquiry, what stage each deal is in, or what the overall lead funnel looks like. Returns one entry per identified person across every lead-generating surface: - identified website visitors (`contact_visited_website`) - contacts whose employer's company visited the site (`company_visited_website`) - contacts in the client's CRM (Yardi, VTS, etc.) (`in_crm`) - contacts who filled out a lead / inquiry form (`lead_form_completion`) - contacts whose employer was reached by the account's ads (`ad_view`, inferred at the company level) Each lead carries: - contact_id, first_name, last_name, job_title, company_name, linkedin_company_id - linkedin_profile_url, profile_image_url, company_logo_url (when available) - work_email, phone, city, state - lead_qualifiers: deduplicated array of the keys above; a single person can carry several - lifecycle_stage: one of "lead" (default), "inquiry" (form filled but no CRM stage), "in_market", "tour", "proposal", "legal", "lease_out" (lease document sent for signature), "lease_executed" (signed), "idle" (dormant CRM prospect), or "dead". Derived from the CRM's `prospect_status` / `prospect_raw_status` when present, falling back to "inquiry" for form-only leads and "lead" otherwise. - last_activity: most recent timestamp across all sources (visit / form / CRM update) Leads are deduplicated by audience_data contact id when we have it, otherwise by normalized email. The same person across multiple sources becomes ONE row with multiple qualifiers, not multiple rows. Qualifier groups can overlap. A `lead_qualifier_definitions` lookup is included at the top level so the LLM can show the user a human-readable description for each key without bloating every row. Defaults to year-to-date (January 1 of the current year through today). Pass start_date and/or end_date (YYYY-MM-DD) for any window. Filters: lifecycle_stages (array — return only leads matching one of these stages), qualifiers (array — return only leads that have at least one of these qualifiers, e.g. ["in_crm","lead_form_completion"]), min_certainty (1–5 floor for website-visit identification confidence), limit (default 50, max 200). The default sort_by="lifecycle_stage" surfaces the most advanced lifecycle stages first, then orders by last_activity within each stage. sort_by="last_activity_desc" puts the newest activity first, then lifecycle stage. Sorting is applied before limit. Sorting does not change the date window; use start_date/end_date for a specific timeframe. The date window bounds website visits, company visits, form submissions, and ad-view signals. Active CRM prospects are included regardless of the window, because CRM presence is not a dated acquisition event. Do not use this tool for company-level reach metrics — that's get_companies_reached. Do not use it for raw website visit traffic — that's get_website_visitors. If individual_visitor_data_restricted is set, named visitor-identified leads (contact_visited_website) were suppressed for this account. Cannot verify that a specific individual visited the website due to local privacy laws; company visitor lists and decision-makers at those companies remain available.
Generate the same portfolio-level Overview Report (PDF and/or XLSX) the portal produces. Covers all the caller's accounts (or a subset they specify) for one month — reach %, views, consistency, subscription. Use this tool when the user wants a portfolio-level monthly recap across multiple properties — "give me the overview for all my properties for April", "send the portfolio report as Excel", "what's the multi-property snapshot for last month". What it does: - Pre-fetches `/ajax/get_account_budgets.php` for the month (the only data the portal JS gathers before posting to generate_pdf for Overview). - For PDF: posts the standard portal payload to `/reporting/downloads/generate_pdf/`. The PDF template re-fetches all per-account stats server-side using `realty_report_stats` + the budget map. - For XLSX: hits `/ajax/overview_reporting_stats.php?method=read_xlsx`. Inputs: - account_ids (optional): subset of accounts to include. When omitted, includes every account the caller has access to. Lite accounts are automatically excluded from both PDF + XLSX (matches portal behavior). - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Returns a text summary containing the direct download URL(s) (always show them to the user) plus one or two `resource_link` items. Links expire 24 hours after generation. Lite-account gating: Lite accounts in the caller's portfolio are filtered out before generation. If ALL the caller's accounts are Lite, the report is empty and the tool returns an error.
Generate the same Pursuit Case Study PDF the portal produces from the Pursuit Profile modal for one company. Includes the engagement timeline, targeting graph, ad preview, and impressions for that company against the account. Used heavily for sales enablement. Use this tool when the user wants a per-company case study — "make a case study for Microsoft", "I need the pursuit PDF for Apple on this account", "send the case study for company X". What it does: - Pre-fetches four AJAX endpoints the Pursuit Profile modal calls: 1. /ajax/tenant_reach_report/?method=pursuit_profile — company stats, employee profiles 2. /ajax/tenant_reach_report/?method=company_insights — headcount + growth metrics 3. /ajax/website_analytics/?method=get_interest_profile — engagement timeline graph 4. /ajax/partner_hub/?method=is_crm_pursuit — chooses template (CRM vs standard) - Picks the right PDF template: `case_study_pdf.php` (standard) or `case_study_crm_pdf.php` (CRM-integrated pursuit) - Posts the assembled bundle through the bridge to /reporting/downloads/generate_pdf/. Inputs: - account_id (required): the RealtyAds property account context for the case study. - linkedin_company_id (required): the LinkedIn company id of the target. Use search_companies or lookup_company_information to resolve from a company name first. - year_month (optional): context month for the timeline graph; defaults to last complete month. Returns a text summary containing the direct download URL (always show it to the user) + a `resource_link` to the case-study PDF (24-hour expiry). No XLSX for this report — case studies are inherently visual / prose-heavy.
Generate the same Service Snapshot PDF the portal produces for one RealtyAds account and one month. The Service Snapshot is the headline broker + tenant reach summary with notable companies. Returns a downloadable PDF link the user can open or save. Use this tool when the user asks for the Service Snapshot — the most-clicked monthly client export. "Give me the Service Snapshot for [property] for [month]", "send the snapshot PDF for last month", "I need the one-pager". What it does: - Pre-fetches the two property_snapshot AJAX endpoints (read + notable_companies) the portal JS calls. - Calls the same `/reporting/downloads/generate_pdf/` endpoint the portal does, with the same payload. - The portal renders the PDF via its existing pdfmyurl pipeline and streams it back. - The PDF is saved on the MCP server; the direct HTTPS download URL is included in the text response (share it with the user), and a `resource_link` content item is also attached for clients that render attachments. Inputs: - account_id (required): the RealtyAds property account. - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (the only supported format — Service Snapshot has no XLSX in the portal). Output: text summary containing the direct download URL (always show this URL to the user — some MCP clients don't render resource_link attachments), plus a resource_link content item pointing at the PDF. The link expires 24 hours after generation. Lite-account gating: the portal blocks Service Snapshot for Lite-tier accounts. If the caller's account is Lite, the generation request will fail at the portal side with a "this report is unavailable on the current subscription" message — that's preserved verbatim and surfaced as a tool error. Doesn't return data fields — for the structured snapshot metrics, use get_account_performance instead.
Generate the same Tenant Reach Report (PDF and/or XLSX) the portal produces for one account and one month. Shows targeted tenants, impressions, engagement stats, and per-company highlights. Use this tool when the user wants the monthly Tenant Reach Report — "send the tenant reach for [account] for [month]", "I need the tenant report as Excel". What it does: - Pre-fetches `/ajax/tenant_reach_report/?method=performance_subscription` for the supplied account + month. - For PDF: posts the standard payload (subscription stats + identifiers) to `/reporting/downloads/generate_pdf/`. The PDF template re-fetches the per-tenant list server-side. - For XLSX: posts the same `tenants_targeted_xlsx` payload to `/ajax/tenant_reach_report/`. Inputs: - account_id (required). - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Returns a text summary containing the direct download URL(s) (always show them to the user) + one or two `resource_link` items, 24-hour expiry. No Lite-account gating on this report — every account with tenant targeting can produce one.
Automatically pick an account's highest-relevance Tenant Reach companies and generate a Pursuit Case Study PDF for each — no company id needed. Great for sales enablement when the user just wants "some case studies." Use this tool when the user wants case studies for an account but does NOT name a specific company — "make me some case studies", "generate case studies for this account", "what are my best case studies". What it does: - Auto-selects the account's highest-relevance companies using the Tenant Reach Report/PDF default ranking (get_companies), so the picks match the portal's default order. - The default ranking considers targeting method, explicit priority, and decision-maker availability. It is not a raw Hyper-Targeted Views ranking. - Generates one Pursuit Case Study PDF per company via the same pipeline as get_pursuit_case_study (per-company prefetch, CRM-vs-standard template, bridged PDF generation). Inputs: - account_id (required): the RealtyAds property account context. - limit (optional): how many case studies to generate (default 3, max 5). - year_month (optional): context month for the engagement timelines and company selection window (YYYY-MM). Defaults to last complete calendar month. - linkedin_company_ids (optional): explicit array of LinkedIn company ids to use instead of auto-selecting. Duplicates are removed, then the list is capped at 5. When provided, limit is ignored. When the user asks for case studies from a filtered Tenant Reach segment (such as AI Prospecting) or asks for the companies with the most views, call get_companies_reached first with the requested tenant_filter/sort_by, then pass at most 5 selected company ids here via linkedin_company_ids. Returns a text summary containing the direct download URL of every generated PDF (always show these URLs to the user) + one resource_link per case-study PDF (24-hour expiry). When the user wants a case study for ONE named company, use get_pursuit_case_study instead.
The account's most engaged non-CRE tenant prospects, ranked by depth of sustained ad engagement, with targeting status, priority, growth signals, website-visit flag, and a Prospect Boost recommendation. Each prospect includes its targeting status, targeting priority, employee growth signals, and whether the company has also visited the property website. Also surfaces a prospect_boost_recommendation (the best candidate not already being boosted) and untargeted_engager_count (multi-month engagers not yet on the target list). Use this for sustained multi-month prioritization: "who should I prioritize?", "show me my top prospects", "who should I Prospect Boost?", "which multi-month engagers am I not targeting?", or "suggest firms to add to my targeting". It analyzes all completed months available for the account, requires at least two engaged months, and excludes the current partial month. Do NOT use this to reproduce a selected month's Tenant Reach Report, rank companies by views for a report period, or select generic Tenant Reach case studies. Use get_companies_reached for those requests. Requires account_id. Optional limit (default 10, max 25).
Generate the same Visitor Identification Report (PDF and/or XLSX) the portal produces. Identified website visitors (companies + individuals) for one account, one month. Requires Website Services with Visitor Intelligence. Use this tool when the user wants the monthly Visitor Identification Report — "who visited our site last month", "send the visitor ID PDF", "give me the identified visitors list". What it does: - Pre-fetches `/ajax/website_analytics/?method=get_visitors_overview` for the date range (eligibility check; also confirms visitors > 0). - For PDF: posts minimal payload to /reporting/downloads/generate_pdf/; the template re-fetches the visitor rows server-side. - For XLSX: hits /reporting/downloads/visitor_identification_xlsx.php. Inputs: - account_id (required). - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Gating: - Requires Website Services subscription. - Requires at least one identified visitor in the period (zero-visitor months produce no report).
Generate the same Website Analytics Report (PDF and/or XLSX) the portal produces for one account and one month. Includes traffic overview, top locations, page-level data, mobile breakdown, and ad-placement chart. Requires the account to be on Website Services. Use this tool when the user wants the monthly Website Analytics Report — "send the website analytics for [account]", "what was our traffic last month", "give me the analytics PDF". What it does: - Pre-fetches `/ajax/website_analytics/?method=get_visitors_overview` for the date range (converted from year_month: "2026-04" → "2026-04-01_2026-04-30"). - For PDF: posts the full analytics payload (location_data, page_data, etc.) to /reporting/downloads/generate_pdf/. - For XLSX: hits /reporting/downloads/website_analytics_xlsx.php for the same range. Inputs: - account_id (required). - year_month (optional, YYYY-MM): defaults to last complete month. - format: "pdf" (default), "xlsx", or "both". Gating: - Requires Website Services subscription. If the account doesn't have Website Services, returns "Website Services not enabled". - Returns "no website traffic for this period" when the account had zero page views in the month.
List the individual contacts and companies identified visiting the account's marketing website in a given date window. Use this tool when the user asks who's visited their website, which companies are showing up, who the named visitors are, which decision makers are engaging, or what the website intelligence is telling them. Returns two parallel lists for a single account: - companies: each visitor company with linkedin_company_id, company_name, company_domain, logo_url (LinkedIn company logo when we have it), linkedin_profile_url, interest_level ("high" | "medium" | "low" — same buckets the portal shows: high = top prospects, medium = interested, low = researching), also_saw_ads (true when the company was also reached by paid ads in the same window), total_visits, total_page_views, first_visit, last_visit, city, state, and a pursuit_profile_url that opens the portal's pursuit-profile modal for that company. - contacts: each named individual with contact_id, first_name, last_name, job_title, company_name, linkedin_company_id, linkedin_profile_url, profile_image_url (LinkedIn profile photo when we have it), work_email, phone, certainty_level (string like "4/5" — confidence this person was actually the visitor on a 1–5 scale; 5/5 is highest), last_visit, city, state. Empty PII / image fields are omitted from the response. Contacts are deduplicated by contact_id; if the same person was matched to multiple companies, the highest-confidence / most-recent row wins. Defaults to the last 30 days. Pass start_date and/or end_date (YYYY-MM-DD) for any window. Other filters: include_companies / include_contacts (booleans, both default true) let the caller drop either list to save tokens; company_id scopes contacts to a single LinkedIn company; decision_makers_only narrows contacts to senior decision-makers at the company (RealtyAds' internal decision-maker rank >= 70, not surfaced in the response); min_certainty filters contacts by minimum confidence in the match (1–5); also_saw_ads_only keeps only visitor companies that were also reached by ads in the window; targeted_companies_only keeps only visitor companies on the account's active explicit target-company list; limit (default 50, max 200) caps each list independently. The two company-overlap filters run before the underlying 500-company cap. total_companies_identified and total_contacts_identified report the count returned by the underlying data source for the window — both are capped at 500 by the source layer for performance. If you see 500 for either, narrow the window or apply more filters to see further; otherwise the count is the true total. Do not use this tool for companies who saw the ads (no website visit required) — that's get_companies_reached. Do not use it for ad performance metrics — that's get_account_performance. If individual_visitor_data_restricted is set, named visitor contacts were suppressed for this account. Cannot verify that a specific individual visited the website due to local privacy laws; company visitor lists and decision-makers at those companies remain available.
Make an existing saved ad the campaign's live running ad. This visibly changes the client's running ad and queues rebuilt platform creatives. Confirm with the user first, naming the account and property. Pass confirm=true only after that explicit confirmation. Get ids from get_ad_campaigns.
List the property accounts the caller can access, with full identity, property, subscription, contract, and account-manager context for each. Use when the user asks 'what accounts do I have?', 'which building is account X?', 'who manages this account?', 'when does the contract renew?', or any other broad question about their RealtyAds account set. Returns one rich record per account: name, company, brokerage, ownership, the building (property name + full address), the active services with human-readable package names (e.g. 'Market Entry', 'Visitor Intelligence Agent'), the current contract term with months_remaining, monthly_cost, and auto_renew, and the assigned Account Manager (name, email, phone). The per-account `status` field is the account's lifecycle stage, not just a binary on/off. Possible values: `active` (fully running), `pending_activation` (signed but services haven't launched yet), `deactivated` (services paused), `pending_deactivation` (scheduled to end soon), `terminated` (ended early), `cancelled` (did not renew), `archived` (closed), `prospect` (pre-sale), `not_subscribed` (account exists in the system but has no services subscribed). Look at each service's `active` flag in `active_services` for which specific services are running. A `summary` block aggregates totals and breakdowns by status, category, and ad package — useful for quick portfolio overviews. The summary is omitted when filtered to a single account. Defaults to active accounts only; pass `include_archived: true` to include archived ones. Use `account_id` to narrow to a single account, or `limit` (default 50, max 200) to truncate large portfolios. The full caller-visible count is always reported in `you_have_access_to` so the LLM knows whether truncation happened.
List the account's media library assets (uploaded images, videos, and files) with their CDN URLs, descriptions, and tags. Use for "what's in my media library?", "show me my uploaded photos/videos", or to find an existing asset before referencing it. Requires account_id. Optional media_type filters the set: "media" = images + videos (default), "images", "videos", "files" (non-image/video), or "all". Returns up to 100 assets, each with media_id, file_name, cdn_url, thumbnail_url, media_type, description, tags, and date_created.
Look up detailed information on one company by LinkedIn id, LinkedIn URL, or domain; refreshes employee count and 6/12/24-month headcount growth rates from the LinkedIn data API if our cached data is older than 30 days. Use this tool when you need detailed information on one specific company — beyond what search_companies returns — or when you want to make sure the headcount / growth numbers are fresh. Provide exactly one of: - linkedin_company_id: numeric (the id you already have from search_companies, get_companies_reached, etc.) - linkedin_company_url: a full LinkedIn URL like "https://www.linkedin.com/company/jll/" (or just the "/company/{slug}" tail) - company_domain: the company's website domain ("jll.com", "https://www.jll.com/") Resolution order: linkedin_company_id wins, then linkedin_company_url, then company_domain. Returns one company record: - linkedin_company_id, company_name, linkedin_profile_url, logo_url - website_url, website_domain, primary_email_domain, industry - employee_count, estimated_csuite_employees - hq_city, hq_state, hq_country_code - employee_growth_rates { 6_month, 12_month, 24_month } when populated - cre_tags (["brokerage"], ["owner"], or both) when our CRE classifiers have flagged the company - total_office_locations: integer total count we have for this company (could be in the thousands for global brokerages) - office_locations: array of up to `max_locations` (default 25, max 200) locations, with HQ first. Each carries formatted_address, street_address, suite, city, state, postal_code, country_code, location_type ("headquarters" or "office"), latitude / longitude when available. - top_decision_makers: array of up to `max_decision_makers` senior contacts (default 3, max 10) at this company, ranked using the exact pursuit-profile algorithm from the portal — `audience_tools::get_decision_makers`. The algorithm is account-scoped (targeted-user boost +200, country / state proximity, account-specific exclusions, etc.), so behind the scenes the tool automatically selects one of the caller's accounts as the ranking context — preferring an account that's actively targeting the company, then one that has reached the company via ads, then any active account, then any account. Each entry carries contact_id, first_name, last_name, job_title, linkedin_profile_url, profile_image_url, work_email, phone, follower_count. Empty PII fields are omitted. If none of the caller's accounts has a signal for the company (relevant when the caller is an internal RealtyAds user with no account-specific context), the block is omitted entirely and a warning explains why. - data_freshness: { last_identity_refresh, last_employee_metrics_refresh, last_growth_refresh } as YYYY-MM-DD dates - resolved_via: which input we used to find the row ("linkedin_company_id", "linkedin_company_url", "company_domain", "company_domain_linkedin_api") Pass force_refresh: true to bypass the staleness check and re-fetch from LinkedIn regardless of when we last looked. Useful when the user explicitly asks for the latest figures. Pass max_locations to widen or narrow the office_locations array (1–200), and max_decision_makers to widen the top_decision_makers list (1–10). Returns warnings (and a null company) when the input doesn't resolve to a row in our cache. For long-tail companies that aren't enriched yet, search_companies' linkedin_api fallback can surface a linkedin_company_id you can then feed back into this tool. Do not use this tool to find a company by name — that's search_companies. Do not use it for engagement signals (visits, ad views) — those are per-account and live in get_companies_reached / get_website_visitors.
Get the full profile for ONE specific commercial-real-estate professional from the partner-network contact directory (LinkedIn + ZoomInfo + Apollo) — title, company, LinkedIn profile, and location. NOT limited to RealtyAds customers — works for any person in the directory. Identify them by contact_id, contact_id_partner_network from `search_contacts`, or LinkedIn profile URL. Cached results within 30 days are served without re-querying the source. Use `get_contact_email_and_phone` to retrieve email and phone numbers. Use this tool when the user wants the full profile for one specific person — "look up that contact", "tell me about Jane Smith", "get her LinkedIn profile" — typically after `search_contacts` has narrowed down to a single person. To get someone's email address or phone number, use `get_contact_email_and_phone` instead (credit-gated; consumes 1 lookup credit per successful enrichment). Provide exactly one identifier: - contact_id_partner_network: the id you got back from `search_contacts`. - contact_id: internal RealtyAds contact id (e.g. from get_company_decision_makers or get_website_visitors). - linkedin_profile_url: a full LinkedIn URL like "https://www.linkedin.com/in/jane-smith/" or the "linkedin.com/in/jane-smith" tail. Caching: if we have the contact on file and their LinkedIn profile was refreshed in the last 30 days, we return the cached values without re-querying anything. Otherwise we run the full enrichment pipeline (LinkedIn profile ingest + partner-network lookup) before returning. Pass force_refresh: true to skip the cache check and re-run the pipeline regardless of how recently the contact was looked up. Returns one contact: - contact_id, contact_id_partner_network - first_name, last_name, job_title, company_name, linkedin_company_id - linkedin_profile_url, profile_image_url - location, country_code - linkedin_followers, linkedin_connections - data_freshness: { linkedin_profile, contact_info_primary, contact_info_fallback, record_last_updated } as YYYY-MM-DD dates Empty fields are dropped from the response. Do not use this tool to search or filter — that's `search_contacts`. Do not use it to list the senior decision-makers at a whole company — that's `get_company_decision_makers`. Do not use it to get email or phone — that's `get_contact_email_and_phone`.
Answer a non-client-specific factual question about RealtyAds, its products, services, platform, or knowledge base. Searches the RealtyAds client knowledge base and returns a synthesized answer to the question. Use this tool for any non-client-specific question about RealtyAds, including the company, products, services, packages, platform features, workflows, or client-safe knowledge-base topics. Do not use this tool for account-specific reporting, account performance, website visitors, companies reached, targeting settings, leads, or deal attribution. For those, use account-specific MCP tools. Returns a plain-text answer. The tool handles retrieval and synthesis internally — pass the question as-is, do not pre-format it as a search query.
Bulk version of remove_company_from_targeting: drop many companies off one RealtyAds account's targeted-firms list in a single call. Each entry identifies one company by targeted_firm_id or linkedin_company_id. Use this tool when the user wants to remove several companies from a RealtyAds account's targeted-firms list in one go — for example after pasting a list of companies they no longer want targeted, or sweeping out tenant pursuits that just executed leases. Per-entry behavior matches remove_company_from_targeting. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - companies: a JSON array (up to 100 entries) where each entry is an object with one of: - targeted_firm_id (preferred), OR - linkedin_company_id Per-entry behavior (same as remove_company_from_targeting): - Soft-deactivates the targeted-firms row. - When a LinkedIn id is known, scrubs the company from r1.linkedin_company_targeting, sets partner-pursuit / partner-integration "block" flags, and INSERTs an exclusion row when none exists. - Logs "Updated Company Targeting" / "Removed a company target" with action_source="mcp". Errors are per-entry, not per-batch. A bad row returns action_taken="failed" with an "error" string for that entry; the rest of the batch still runs. The top-level response carries counts (removed / already_removed / not_targeted / failed) so the caller can see at a glance what happened. This is a WRITE action. Every successful remove is logged under the calling user.
Remove one company from a RealtyAds account's targeted-firms list. Pass targeted_firm_id (preferred) or linkedin_company_id. The portal's Company Targeting modal trash-icon behavior, exposed via MCP. Use this tool when the user wants to stop targeting a specific company on a RealtyAds account — "remove CBRE from targeting", "we should stop targeting Apple", or right after listing companies via get_companies_reached / get_ad_targeting and deciding one shouldn't be on the list. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - one of: - targeted_firm_id: the row id on r1.realty_client_targeted_firms (the id the portal's targeting list uses). Highest priority. - linkedin_company_id: numeric LinkedIn company id. We resolve to the matching active row on the targeted-firms list. What the call does (matches the portal's "remove" flow exactly): - Soft-deactivates the targeted-firms row (sets active=0, not a hard DELETE) so the audit trail of prior targeting stays intact. - When a LinkedIn id is known, scrubs the company from r1.linkedin_company_targeting, flips partner-pursuit / partner-integration "block" flags on for that (account, company) pair, and INSERTs an active exclusion row when one isn't already on file. This last step is what makes "remove" sticky — without it, the next matching cron pass would re-add the company. Returns: - action_taken: "removed", "already_removed" (the row was already inactive), or "not_targeted" (no row found for the supplied identifier) - targeted_firm_id: id of the row that was deactivated - account_id, linkedin_company_id, company_name - added_to_exclusion_list: true when a fresh exclusion was inserted - excluded_firm_id: id of that exclusion row when present - message: short human-readable summary Idempotent: re-removing a company that's already inactive returns action_taken="already_removed" and writes nothing. This is a WRITE action, logged in the portal activity feed under the calling user.
Remove one contact from a RealtyAds account's targeted-users list and register them as excluded so future matching can't re-add them. The portal's Pursuit Profile 'Remove from targeting' button, exposed via MCP. Use this tool when the user wants to stop targeting a specific contact on a RealtyAds account — "remove Jane Smith from targeting", "stop targeting that contact", or right after listing decision-makers via get_company_decision_makers / get_website_visitors and deciding one shouldn't be on the list. Required: - account_id: the RealtyAds property account. Must be an account the caller has access to. - contact_id: internal RealtyAds contact id (audience_data.contacts.id). This is the same id returned by get_company_decision_makers, lookup_contact_information, lookup_company_information's top_decision_makers block, and the decision_makers block on get_deal_attribution. Optional: - targeting_user_id: the row id on r1.client_targeted_users when the caller already has it (skips the row lookup). Useful when you got this id from add_contact_to_targeting earlier in the conversation. What the call does (matches the portal's "Remove from targeting" flow exactly): - Hard-deletes the contact's row on the targeted-users list. - INSERTs (or UPDATEs) the contact's identity on the exclusion list so the matching cron can't bring them back. - Logs the action in r1.user_change_log under "Updated Decision-Maker Targeting" with description "Removed a decision-maker from targeting". Returns: - action_taken: "removed" (had a targeting row), "added_to_exclusion_only" (contact existed in the directory but wasn't on the targeting list — exclusion still added so future matching can't add them), or "not_found" (contact id not in the directory) - audience_data_contact_id - targeting_user_id_removed: the row id that was hard-deleted (null when the contact wasn't on the targeting list) - excluded_targeting_user_id: the row id on the exclusion list - account_id, first_name, last_name, job_title, company_name - message: short human-readable summary Idempotent: re-removing a contact who's already off the targeting list just refreshes the exclusion row and returns action_taken="added_to_exclusion_only". This is a WRITE action, logged in the portal activity feed under the calling user.
Remove one custom job title from the targeted-job-title list for a RealtyAds account. Identify the row by row_id (preferred — surfaced by get_ad_targeting in filters.job_titles) or by LinkedIn title_id. Use this tool when the user wants to drop a job title from RealtyAds AI's job-title targeting — "stop targeting VP of Marketing on this account", "remove Heads of Workplace from our targeting". What it does (mirrors the portal): - DELETEs the matching row from r1.realty_client_targeted_job_titles. - Idempotent: an already-absent row returns action_taken="not_targeted" with no writes. - Logs to r1.user_change_log under "Updated Job Title Targeting" with action_source="mcp". The portal itself does not log this action. Identify the row to remove — provide one of: - row_id: the row id surfaced by get_ad_targeting in filters.job_titles[].row_id (preferred when you've just read state). - title_id: the LinkedIn title id (numeric string, tail of `urn:li:title:<n>`). If both are supplied, row_id wins. Returns: - action_taken: "removed" or "not_targeted" - row_id, account_id, title_id, title_name - message: short human-readable summary This is a WRITE action.
Remove one geography from the targeted-geographies list for a RealtyAds account. Identify the row by row_id (preferred — surfaced by get_ad_targeting in geography.submarkets) or by LinkedIn geo_id. Use this tool when the user wants to drop a geography from RealtyAds AI's geographic targeting — "stop targeting White Plains", "remove the Jersey City geography from our list". What it does (mirrors the portal): - DELETEs the matching row from r1.realty_client_targeted_geos. - Idempotent: an already-absent row returns action_taken="not_targeted" with no writes. - Logs to r1.user_change_log under "Updated Geography Targeting" with action_source="mcp". The portal itself does not log this action. Identify the row to remove — provide one of: - row_id: the row id surfaced by get_ad_targeting in geography.submarkets[].row_id (preferred). - geo_id: the LinkedIn geo id (numeric string, tail of `urn:li:geo:<n>`). If both are supplied, row_id wins. Returns: - action_taken: "removed" or "not_targeted" - row_id, account_id, geo_id, geo_name - message: short human-readable summary This is a WRITE action.
Generate the same Quarterly Executive Summary PDF the portal produces for one account and one quarter. Full-quarter recap: tenant reach, broker reach, website visitors, overview, and AI optimizations. Use this tool when the user wants the Quarterly Executive Summary — "give me the Q1 executive summary", "download the quarterly report for last quarter", "the quarterly PDF". What it does: - Generates the full-quarter Executive Summary PDF — the same report the Reporting Center produces. - Covers tenant reach, broker reach, website visitors, quarterly overview, and AI optimizations. Inputs: - account_id (required). - quarter (optional): "Q1-2026", "Q2-2026", etc. Defaults to the most recent eligible quarter. Returns a text summary containing the direct download URL (always show it to the user) + a resource_link to the PDF, 24-hour expiry. Gating: only the last four complete calendar quarters are available, and only when all three months in the quarter are active for the account. Returns a clear error if the requested quarter doesn't qualify or no eligible quarter exists.
Save the campaign's current live content as a new reusable saved ad. Does not change what is running. Use this only to snapshot what is currently live. It cannot add new copy or media. Use create_new_saved_ad to author new content, or duplicate_saved_ad to copy an existing saved ad.
How do I improve a ChatGPT Plugin's discoverability?
The levers are the listing surface agents actually read: names, descriptions, keywords, tool metadata, and registry health. Which lever matters depends on where discovery breaks, which is what continuous measurement shows.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.