Lev
Lev connects ChatGPT to a user's commercial real estate workspace. Users can inspect and manage deals, indexed deal facts, source documents, memos, checklists, companies, contacts, notes, lender placements, pipelines, term sheets, billing state, account access, and current market reference rates.
- Integration type
- Plugin
- Verification status
- Not applicable
- Platform
- ChatGPT
- Primary Subcategory
- Real Estate Agent & Deal Tools
- Secondary Subcategories
- Calendar & Scheduling Apps
- Brand
- Lev
- Access
- Account required
- First tracked
- 2026-06-22
- Tool count
- 60
- Geography
- US
The Primary Subcategory used for this profile’s headline score.
Other Subcategories where the Integration is visible.
ChatGPT Plugin Discoverability Score
ChatGPT organic discovery is not live yet
Lev is tracked in the ChatGPT Plugin registry. Public organic-discovery measurement is not live for ChatGPT yet, so there is no score to publish today.
Get notified when your score goes live
Enter your work email and we’ll notify you when ChatGPT Plugin organic discovery scoring launches.
No spam. Unsubscribe any time.
Competing in ChatGPT Real Estate Agent & Deal Tools
View CategoryHow the Discoverability Score works
Organic discovery scoring for Lev on ChatGPT is not live yet. The score will use measured agent conversations when it launches.
Organic discovery scoring is pending. Your Plugin score will appear on this scale when measurement goes live.
FoundDiagnostic
Whether Claude found your Plugin in connector search. It must be Found before it can reach the picker, but the score counts picker appearances—not search results.
PickedMain score
How often your Plugin appeared in the picker, or Claude invoked it directly, across contested conversations. This percentage is the Discoverability Score; the headline number is rounded.
PositionedDiagnostic
What position your Plugin appeared in when it was shown in the picker. This shows prominence, but it does not affect the score.
60 tools agents can invoke
Open a deal's document workspace — an inline browser of its vaults with the files and memos inside. Use for any broad "show me / what are the documents (files, attachments, paperwork) on this deal", "what's in the dataroom", or "browse / explore / look through the documents" ask — the user wants to see or work through a deal's documents, not find one named file. On MCP Apps hosts (Claude Desktop) this opens an inline browser of the deal's vaults, each expandable into the documents and memos it holds, with any PDF or image viewable inline. Other hosts get the deal's files (from Resources, its complete set) plus its memos as a list. Tool-use examples: show me the documents on deal 174124 -> this tool; what's in the dataroom for deal 174124 -> this tool. Use list_deal_documents instead to find one specific file or filter (a rent roll, an extension, one folder); list_deal_vaults for just the list of vaults; get_deal_document to open or download one specific file; and search_deal_index for what facts came from the documents.
Mark a checklist task done — the equivalent of checking it off in the deal's checklist. Use when a request or to-do is satisfied (e.g. the document was collected). Completing also moves the task to approved status and approves any pending files already attached to it, matching the in-app action. Idempotent: completing an already-complete task leaves it complete. To reopen a completed task use update_checklist_task with is_completed=false. task_id: the task to complete (from get_deal_checklist).
Add a new task to a deal's checklist — a document request or to-do to track on the deal. Use to create a checklist item (e.g. "Get the SREO from the sponsor"). To comment on an existing task use create_note ("checklist_task"); to record an extracted underwriting fact use record_deal_facts; to edit deal-level fields use update_deal — none of those create a checklist task. To mark an existing task done use complete_checklist_task. Anchor the task under exactly one parent (get the ids from get_deal_checklist), provide exactly one of: section_id: add it inside this section. checklist_id: add it at the checklist root, outside any section. parent_task_id: add it as a subtask of this task (one level deep). title: the task title (required, non-empty). description: optional longer detail. status: initial review state — "to_do", "requested", "reviewing", "updates_needed", "approved", or "cancelled". Defaults to "to_do". assigned_user_id: Lev user id to assign (from list_team_members or an assignee id on get_deal_checklist); must be an active teammate in your account. due_date: optional due date, YYYY-MM-DD. document_type_ids: optional expected document type ids for the request.
Create a new private company. company_type: "lender" or "sponsor" address: optional street address (free-form single line) city: optional city name state: optional US state as a 2-letter code (e.g. NY, CA) zip: optional postal code as a string (preserves leading zeros) linkedin_url: optional LinkedIn profile URL for the company org_id: optional ID of a platform-wide Organization record to link this company to. Omit unless you already know the exact ID — the MCP does not expose a tool to list or search organizations, so a guessed or hallucinated value will silently bind the company to the wrong real-world entity. When omitted, the backend finds or creates the Organization automatically from name/website.
Create a new contact linked to a company. contact_type: "lender_contact" or "sponsor" (creation is strictly limited to these two values) company_id: the ID of the company this contact belongs to (use list_companies to find it) email: optional email address. When supplied, it must be a valid email address; malformed values are rejected by the Lev API, not normalized or ignored. department: optional department or team name (e.g. Originations, Credit) address: optional street address (free-form single line) address2: optional apartment, suite, or unit line (e.g. Suite 400) city: optional city name state: optional US state as a 2-letter code (e.g. NY, CA) zip: optional postal code as a string (preserves leading zeros) linkedin_url: optional LinkedIn profile URL for the contact photo_url: optional URL to a profile photo for the contact phones: optional list of phone objects with keys raw, type, country, extension. raw takes any common format and is normalized to E.164 server-side; type is "mobile", "office", or "fax" (default mobile); country is a 2-letter ISO region used to parse numbers without a plus prefix (default US).
Create a new CRE financing deal. Requires at minimum a title. Enum values (exact): loan_type: "construction", "heavy_bridge", "light_bridge", "permanent", "land", "predevelopment", "tbd" transaction_type: "acquisition", "refinance", "new_construction", "tbd" business_plan: "stabilized", "value_add", "construction", "land" estimated_close_date: ISO 8601 date string (e.g. 2026-06-01) purchase_price / estimated_value / total_cost / total_cost_basis / land_cost: official financial denominators for leverage math. Use these for canonical values; use record_deal_facts / update_deal_index_fact for source-reported observations. Omit to leave unset. sponsor_private_company_id: optional ID of an existing sponsor company to link to the deal. Find it with list_companies (filter by company_type= sponsor) or create one with create_company. The sponsor's users are automatically added to the deal team when the deal is brokered. Use this in the onboarding flow: create_company → create_contact → create_deal(..., sponsor_private_company_id=<id>) so the sponsor is linked from the start rather than needing a follow-up update_deal call. pipeline_ids: optional list of pipeline IDs to associate with the deal at creation time (use list_pipelines to discover available IDs). To change pipeline/status after creation, use move_deal_to_pipeline_status — update_deal does not accept this field. properties: optional list of properties (max 25 per deal) to attach when creating the deal. Real-world deal authoring is property-first — the broker knows the address before the financing — so prefer this over creating the deal first and bouncing the user to the Lev UI to add properties later. Each entry is either a link or an inline-create (mutually exclusive per entry; duplicate property_id values are rejected): link form — {property_id: <int>}. The property must already be linked (via DealProperty) to a non-deleted deal owned by the caller's account; cross-account or policy-denied property_id → 404. inline create — at minimum {address: <str>}, plus any of {city, state, zip, asset_type_id, units, square_footage, year_built}. asset_type_id expects an asset sub-type id: use get_asset_types and pass property_sub_types[].id from the matching top-level type, not the top-level asset type id. Sub-type ids differ by environment. address must not be blank or whitespace-only. Field names follow the read serializer (asset_type_id, square_footage) — but GET output is not a drop-in POST body, because the read side returns DealProperty.id under id, not the property_id needed to link. Extended onboarding flow: create_company → create_contact → create_deal(..., sponsor_private_company_id=<id>, properties=[...]) so the sponsor and the first property both land in a single call. Response includes the same `urls` map as get_deal; the same no-volunteer rule applies. Never fabricate a url — links come only from the `urls` field, never the retired `levcapital.com` domain.
Log a free-text note on a contact, deal, placement, or company — or post a comment on a checklist task. Use for human-written commentary. To record a structured deal fact, use record_deal_facts instead — notes are not indexed facts. parent_type: "contact", "deal", "placement", "company", or "checklist_task" — which kind of record to note. Use "placement" for notes on one lender's outreach within a deal; "deal" for deal-wide notes; "company" for a lender or sponsor firm; "contact" for a specific person; "checklist_task" to comment on a checklist item (e.g. a document request) — these are the comments borrowers and your team see in the portal. parent_id: numeric ID of the contact, deal, placement, company, or checklist task text: the note content (required, non-empty). Simple HTML formatting is preserved; scripts and other unsafe markup are stripped. The note is attributed to you and visible in the Lev web app.
Create a new placement (record of lender outreach) on a deal. Use after the user picks a lender to reach out to: pair the deal with a lender company (and optionally a specific lender contact at that company). Subsequent term sheets are attached to this placement via create_term_sheet. Required: deal_id: numeric ID of the deal (use list_deals or get_deal to find it). private_company_id: numeric ID of the lender company (use list_companies filtered by lender company_type to find it). Optional: contact_id: numeric ID of the lender contact at that company. Must belong to the same lender — otherwise the request is rejected. When omitted, Lev may run AI contact-matching for the deal in the background: the placement returns with no contact, and a matched lender contact can land a moment later. Poll get_placement until contact_id appears (its name stays masked until paid), then reveal it with unlock_contact; if none appears, no contact was matched. Pass an explicit contact_id to tie a known contact and skip matching. status: placement status. Defaults to "new" if omitted. visibility: who can see this placement. The default depends on the deal-owner account's configuration (typically "hidden" for direct outreach, "shared" for customer-owned deals). description: free-text note, e.g. 08/11 soft quote received. score: manual relevance score (0-100). outreach_date: ISO 8601 timestamp when the lender was first contacted (e.g. 2026-05-01T00:00:00Z). lender_status: lender-side status flag. Enum values (exact): status: "new", "sent", "lender_reviewing", "terms_received", "term_sheet_received", "executed_ts_in_closing", "closed", "unresponsive", "willing_to_negotiate", "lender_passed" (archived is intentionally NOT a valid create status — it is the removal sentinel and only applies via update_placement on an existing row.) visibility: "hidden", "masked", "shared" lender_status: "origination", "new", "lead_qualification", "quotation", "negotiation", "offer", "term_sheet", "good_faith_deposit", "diligence", "in_closing", "closed", "archived" Duplicate guard: applies only when contact_id is provided. If a placement already exists for that deal + contact combination (on either the same lender or a different one), the request is rejected — use update_placement to edit the existing one, or PATCH status="archived" first if you want to recreate with a different contact. Without contact_id, the backend does not preflight duplicates, so multiple placements on the same deal + lender can coexist. There is no DELETE — to remove a placement, call update_placement with status="archived".
Create a new term sheet (lender loan quote) on a placement. Use after a lender returns a quote on an existing placement: record the headline economics (rate, loan amount, term, recourse, etc.) so the deal team can compare quotes across lenders. The placement must already exist on this deal — see create_placement. Required: deal_id: numeric ID of the deal. placement_id: numeric ID of the placement this quote belongs to. Must be a placement on deal_id; cross-deal IDs return 404. total_rate: rate as a percent (e.g. 7.53 for 7.53%). When base_rate names an index, total_rate is the SPREAD over it (e.g. 2.05 for +205 bps) and Lev computes all-in = base_rate + total_rate — never pass the all-in coupon here or it double-counts; when there is no base rate, total_rate is the all-in fixed rate. initial_funding: provided loan amount (whole dollars). quote_type: type of quote being recorded. rate_type: fixed or floating. Enum values (exact): quote_type: "guidance", "indication", "soft_quote", "hard_quote", "term_sheet" rate_type: "fixed", "floating" recourse: "personal_recourse", "fund_corporate_recourse", "non_recourse" recourse_type: "full", "partial", "burn_off" floor_type: "base_rate", "total_rate" prepayment_penalty: "step_down", "defeasance", "minimum_interest", "yield_maintenance", "minimum_multiple", "swap_breakage", "no_prepayment_penalty", "no_ability_to_prepay", "flat_fee", "other" payment_method: "accrued", "partial", "current_pay" capital_source_type: "balance_sheet", "agency", "cmbs_clo", "warehouse", "sba" base_rate: BaseRateNames member name (e.g. "treasury_y5", "sofr_m1", "prime_rate") OR the matching display value (e.g. "Treasury 5-Yr"). Use the literal string "none-fixed" for fixed- rate quotes that have no underlying base rate. Unknown names return 422 with the full valid list. Defaults applied by the backend when omitted: winning → false (only one term sheet per deal should be winning; this is not enforced server-side). is_visible_to_borrower → true. Visibility caveat: the read endpoint hides term sheets whose quote_type is outside the default-visible set or whose is_visible_to_borrower is false. A successful create followed by a 404 on get means the row exists but is hidden by policy — re-check those two values.
Delete a deal. This is a soft delete and can be reversed by Lev support.
Permanently delete a free-text note from a contact, deal, placement, or company — or a comment from a checklist task. Use only when the user asks to remove a human-written note. To remove another resource, use that resource's delete/archive tool instead — this only deletes notes. parent_type: "contact", "deal", "placement", "company", or "checklist_task" — which kind of record owns the note parent_id: numeric ID of the contact, deal, placement, company, or checklist task note_id: numeric ID of the note to delete This is a permanent hard delete with no undo. You can only delete a note you created and still have parent write access to; another user's note or a note on another parent returns not found.
Delete a term sheet. Soft delete — reversible by Lev support.
Get the list of property asset type classifications used in Lev. Returns top-level types like Office, Apartment/Multifamily, Industrial, Retail, Hotel, Self-Storage, etc., with nested property_sub_types. The top-level asset type id identifies the broad category; the create_deal/update_deal property asset_type_id field expects a nested property_sub_types[].id value, not the top-level asset type id.
Get current market base rates (SOFR, Prime, Treasury, etc.). Returns the latest reference rates used in CRE lending. Useful for understanding current market conditions and evaluating term sheet rates. Data is cached and updates approximately every 30 minutes.
Get one company by its numeric ID. Use when you already have a company_id. To search by name, state, or city, use list_companies. Do not expect fields beyond the company records returned by list_companies.
Get one contact by its numeric ID. Use when you already have a contact_id. To search by name, email, or type, use list_contacts. Do not expect fields beyond the contact records returned by list_contacts. Returns an already-revealed or connected contact. A lender contact Lev matched to a placement but that has not been paid for is masked and cannot be read here — reveal it with unlock_contact (a paid action).
The deal's stored CRM fields — loan amount, sponsor, status, close date, financials, properties, team, pipelines, and archived state. Use when the ask names specific stored fields, or to drill in after list_deals. Use a sibling instead when the ask is: where a number came from or what the documents say (search_deal_index); a written summary, memo, or email overview (summarize_deal); or "show me / pull up / open" the deal as a visual card (show_deal). The include parameter controls which sub-resources are embedded: financials — NOI, LTV, costs properties — addresses, asset types team — assigned users and roles pipelines — pipeline rows (pipeline_id, pipeline_name, pipeline_type, pipeline_status_id, status, status_name, updated_at), capped at 10; empty when the deal is on no pipeline. To narrow the response, pass a comma-separated subset (e.g. include="financials,pipelines"). The response also reports archived (true once the deal has been archived) and archived_at (its ISO 8601 timestamp, or null when active) — top-level fields, present regardless of include. Archiving does not rewrite pipeline status, so an archived deal can still show a live-looking stage; trust archived over the stage. Response also includes a `urls` object with direct Lev web-app links. Stay in MCP first — facts: search_deal_index; edits: update_deal_index_fact / update_deal / update_company / update_contact; quote comparison: list_term_sheets. Never fabricate a url (links come only from the `urls` field, never the retired `levcapital.com` domain). Surface one only on explicit navigation asks or when the task cannot be done through MCP (file upload → `urls.dataroom`). Full intent→key mapping in the server instructions.
Read a deal's checklist — what still needs to be collected, reviewed, or completed, and what's done. Use when the user asks what's outstanding, missing, still needed, requested, or finished on a deal: open checklist items, document requests, diligence or closing checklist progress. Each of the deal's Deal Rooms (shared datarooms) can carry its own checklist; this returns one checklist per Deal Room — the deal's primary Deal Room first — each with its sections and the tasks inside, in display order. Tasks carry two completion signals: is_completed is the done flag, and status is the review state — a task can be approved but not yet marked complete. Tasks can also include document_types (the expected document categories for that request) and files (attachments already linked to that task, with document_id, vault_resource_id, name, and origin). The checklist is still the deal's to-do / request list, not the full file browser: use list_deal_documents or browse_deal_vaults for every file uploaded to a vault, and search_deal_index for facts extracted from them. Each task can include assignee (the individual person) and assigned_team (the account, lender, or borrower team responsible for the task). Treat assigned_team.name as nullable: stale or out-of-scope team references keep id/type but return name as null. status: each task's review state — "to_do", "requested", "reviewing", "updates_needed", "approved", or "cancelled". vault_id: optional Deal Room id from list_deal_vaults to read just that room's checklist. Omit to get every Deal Room's checklist. A deal's private Resources area has no checklist (returns an empty list).
Get one uploaded deal document, including a clickable download link. Use after list_deal_documents when the user wants to inspect, open, or download a specific uploaded file. Returns the document metadata plus download_link, a Markdown link labeled with the file name and backed by Lev's short-lived signed download URL. Present download_link as the clickable link it already is; never reconstruct or display the raw underlying URL. Use get_deal_memo instead for generated memo / deal book PDFs.
Get one memo for a deal, including a downloadable PDF preview link. Use after list_deal_memos when the user wants to preview, open, or download a specific memo's PDF. memo_id is the memo's uuid from list_deal_memos. Returns the memo's metadata — including, when the workspace has them, who created it, when it was last modified, and which Deal Room(s) or Resources area it lives in — plus a pdf_link (a ready-to-click Markdown link to the rendered PDF) and a pdf_versions array with one link per rendered quality. On MCP Apps hosts (Claude Desktop) the memo renders inline as a scrollable PDF viewer (the ``ui://memo-view`` widget); other hosts see the markdown pdf_link. Present pdf_link to the user as the clickable link it already is; never reconstruct or display the raw underlying URL — it is a short-lived signed link. When the memo is an unpublished draft that has not been rendered yet, there is no PDF: pdf_link is absent and pdf_versions is empty (pdf_ready will be false). Say the PDF isn't available yet rather than implying one exists. quality: which rendered variant the top-level pdf_link points at. One of "original" (default, full fidelity), "high", "medium", "low" (progressively more compressed / smaller files). pdf_versions always lists every rendered variant regardless of this choice.
Get lender details including their lending programs. Programs describe specific loan products the lender offers: loan type, amount range, LTV/LTC limits, DSCR requirements, term length, and supported asset types. For the lenders best matched to a specific deal (rather than one lender you already know by id), use recommend_lenders_for_deal.
Retrieve the ranked lenders from a deal's AI match — scores, match reasons, and programs. Use after recommend_lenders_for_deal to read the results: the lenders Lev ranked for the deal, each with an AI score, the reasoning behind the match, and the lender's relevant loan programs (loan types, amount range, states, asset types). For one specific lender's full profile by id, use get_lender instead. On MCP Apps hosts the results also render as an interactive ranked-match card where the user can select lenders to add to the deal or unlock. If the match is still running, the response says so and carries no ranked lenders yet — wait briefly and retrieve again. If no match has been run for the deal, start one with recommend_lenders_for_deal first. limit: how many ranked lenders to list in the text summary, best first. Defaults to 10 and is capped at 25; page for more with offset. The card independently receives the top matches. offset: 0-based index of the first lender in the text summary. Defaults to 0. When the response indicates more remain, add limit to offset for the next page.
Get your Lev account's current subscription and credit balance. Returns two blocks: - subscription: the active plan's type, status, billing cycle, and end date - credits: whether the account is provisioned for credit-based billing, the current balance, and the unit (always "credits") Use this before suggesting work that consumes credits (e.g. AI actions, some placement flows) to confirm the user has headroom. An `enabled` value of false means the account is not provisioned for credits — balance will be null rather than 0 so you can distinguish "not provisioned for credits" from "provisioned with a zero balance". Cost-per-credit and transaction history are not currently returned — use the web app for those.
Get your Lev profile, currently-active account, subscription tier, and API capabilities. Returns your user details, active account, subscription status, granted scopes, rate limits, and API key quota. Call this first to confirm your connection and see what you have access to. To see all accounts you can switch into, use list_available_accounts. To switch, use switch_account. The `granted_scopes` field is internal context for your own reasoning — use it to decide which tools a workflow is allowed to call. Do not echo the raw scope list back to the user; summarize capabilities in plain language if they ask what access they have.
Get one placement by its numeric ID. Use when you already have a placement_id (e.g. 'show me placement 300'). To find placements by deal, lender, or status, use list_placements. Returns the same fields as a list_placements row — no additional detail. Rows include lender_name / contact_name, with masked placements showing non-owner viewers a generic lender_name (e.g. Lender A) and a null contact_name. The contact_id is still present on a masked placement — pass that contact_id (not the placement id) to unlock_contact to reveal the name and details (a paid action). score / lev_score are frequently null (scoring may not have run for the placement); treat null as 'no score available', not zero.
Get full term sheet details including rate structure, fees, recourse terms, and extensions. Contains all financial details of a lender's loan quote: rate type (fixed/floating), base rate, spread, origination fee, prepayment penalty, amortization, IO period, extension options, recourse terms, DSCR/debt yield requirements, and more. Same masked-label behavior as list_term_sheets.
List the Lev accounts you can switch into. Returns each account's name, slug, and type. Use this before switch_account when the user asks to switch accounts but you don't know the exact target — show the returned list and let them pick by name. If you need to know which account is currently active, call ``get_my_profile`` — the backend tracks the active account server-side.
Search private companies (lenders and sponsors) in your account by name, state, or city. Returns company records. Use get_company only with a known company_id. is_connected: true returns connected companies; false returns disconnected companies. Timestamp filters: min/max_created_at and min/max_updated_at are inclusive gte/lte bounds. Use ISO 8601 datetimes with timezone: trailing `Z` or `±HH:MM`, e.g. 2026-04-01T00:00:00Z. sort: pass a bare key for ascending; prefix with a minus sign for descending (e.g. -name). Defaults to descending created_at. Valid keys (exact): "name", "city", "state", "created_at", "updated_at" Pagination: - Default (sort set): offset mode. Walk pages with offset=N using the value surfaced in the previous response's hint. - Stable paging for bulk sync: pass sort=None; walk pages with cursor=<value> from the hint. cursor and sort cannot be combined — passing both returns a 400.
Search contacts (lender contacts and sponsor contacts) by name, email, or type. contact_type: one of "lender_contact", "sponsor", "legal" (the filter accepts any backend ContactType value; these are the externally useful ones) Timestamp filters: min/max_created_at and min/max_updated_at are inclusive gte/lte bounds. Use ISO 8601 datetimes with timezone: trailing `Z` or `±HH:MM`, e.g. 2026-04-01T00:00:00Z. Returns contact records. Use get_contact only with a known contact_id. sort: pass a bare key for ascending; prefix with a minus sign for descending (e.g. -last_name). Defaults to descending created_at. Valid keys (exact): "first_name", "last_name", "email", "created_at", "updated_at" Pagination: - Default (sort set): offset mode. Walk pages with offset=N using the value surfaced in the previous response's hint. - Stable paging for bulk sync: pass sort=None; walk pages with cursor=<value> from the hint. cursor and sort cannot be combined — passing both returns a 400.
Find specific uploaded files on a deal — by name, type, folder, or vault. Use when the user wants particular uploaded documents: a named file, a rent roll, an appraisal, a budget, closing docs, files of one extension, or the contents of one folder or one vault. Returns file metadata only; no signed download links. Each file is tagged with the container it lives in (Resources, or a Deal Room / shared dataroom). When naming a container to the user, use its title, never the raw type value. For a broad "what documents are on this deal / what's in the dataroom" ask — where the user wants to see or browse everything rather than find one file — use browse_deal_vaults instead: it opens the deal's document workspace and shows uploaded files and generated deal books together (users don't distinguish Lev's uploaded-documents-vs-memos split). Stay on this tool when the user names a specific file or filter (a rent roll, an extension, one folder, "how many"). Example: find the rent roll PDF on deal 174124 -> this tool; show me the documents on deal 174124 -> browse_deal_vaults. Use list_deal_vaults to see the deal's vaults themselves, get_deal_document when the user wants to open or download a specific file, and search_deal_index when the user asks what facts came from the documents. search: optional file-name search text. extension: optional file extension filter, with or without the leading dot; case is normalized before calling Lev. folder_id: optional folder id to list only files in one vault folder. vault_id: optional vault id to list only the files in one of the deal's containers (a Deal Room or Resources); ids come from list_deal_vaults. Omit to list across every container. limit: maximum documents to return. Defaults to 20, clamped by Lev to 1-200. cursor: pagination cursor from the previous response hint.
List the metrics that CAN be recorded on a deal, with a routing hint. The tool for 'what metrics can I record / track on this deal?' and for finding a metric's id before recording a brand-new fact — it tells you which metrics exist (e.g. NOI, occupancy, purchase price) and, for each, the recommended way to write it. To find or change a fact the deal ALREADY has, use search_deal_index (it returns the fact's identifier directly); reach for this catalog to discover what's recordable. Each metric carries a suggested_write_via routing hint: - index — record it with record_deal_facts (a measured / extracted underwriting fact: NOI, occupancy, expenses, or source-reported valuation). Pass this metric's id to that tool. - deal_record — write it on the deal's canonical record instead; the metric also carries write_via_tool naming which tool to use (update_deal, update_company, or update_contact). - clarify — the metric can live in BOTH places and the right one depends on what the user means. Ask them: are they setting the deal's official value (→ the named CRM tool), or logging what a source reported (→ record_deal_facts)? Loan amount and deal financials are common cases. Do not pick a door without asking. suggested_write_via is a best-effort hint, not a guarantee — confirm the intended change with the user in plain English before any write, and never surface the hint, the metric id, or write_via_tool to them. metric_label: optional case-insensitive search term to narrow the catalog to matching metrics (e.g. occupancy, loan). category_id: optional numeric category filter. limit: maximum metrics to return per page. Defaults to 100, clamped by Lev to 1-200. The catalog is usually small — narrowing with metric_label or category_id is often easier than paging. offset: 0-based index of the first metric to return. Defaults to 0. When the response has has_more=true, walk to the next page by passing the offset emitted in the response hint; keep limit constant across pages.
Show the per-document values our extractors pulled for a deal fact. Use when the user wants to know where a fact came from, see every value we extracted for it across documents (e.g. 'what NOIs do we have on file?', 'where did this loan amount come from?'), or pick among multiple extracted values during an edit. The user will describe the fact in plain English — they will not know its internal identifiers, and you should never ask for one. Resolve the right identifier from a prior search_deal_index result yourself. Prefer promoting an extracted value over a free-text override when the user is choosing among candidates — it preserves the source document, page range, and confidence score. Translate everything back to plain English when speaking to the user: never surface the word 'observation' or echo any internal identifier. Frame it as 'extracted values' or 'what we found in the documents'. sot_id: identifier carried by a prior search_deal_index result (e.g. d:5362, a:123:property:690). Preferred filter — returns only the extracted values tied to that specific fact. metric_id: numeric metric definition id. Use to fetch every extracted value for a metric across entities (broader than what the current canonical value picked). Combine with entity_ref to scope to a single property or group. entity_ref: optional entity scoping (e.g. property:690). Used alongside metric_id; ignored without one. limit: maximum results to return. Defaults to 20 and is clamped by Lev to 1-200. Most facts have only a handful of extracted values, so the default is usually plenty. offset: 0-based index of the first result to return. Defaults to 0 (first page). When the response has has_more=true, walk to the next page by passing the offset emitted in the response hint. Keep limit constant across pages; mixing limits mid-walk can skip or duplicate items. include_signed_urls: default false. When true, document-backed source records may include short-lived signed attachment URLs for inspection or download. The response converts returned signed URLs into source.file_link Markdown hyperlinks and omits raw source.signed_url. Keep false when the user asks only what the source is; set true only when the user asks to open or inspect the source document. Never show a bare signed URL in the final user answer; present only the file name as a hyperlink. At least one of sot_id or metric_id must be provided. Each result carries the extracted value, metric metadata, context and summary text, confidence, weight, and the same source metadata shape as search_deal_index. When the user is choosing among candidates to update a fact, pass the chosen result's ``observation_id`` back to update_deal_index_fact — silently, behind a plain-English confirmation. All identifiers here (sot_id, metric_id, entity_ref, observation_id) are internal — never surface to the user.
List the memos (generated CRE deal books) for a deal. Use when the user asks what memos or deal books exist for a deal, or as the first step before fetching one to preview. Returns both published memos and unpublished drafts so a user can find work in progress, most recently active first. Narrow the result server-side with the filters below — published memos first, then drafts — rather than pulling every memo and filtering client-side. On MCP Apps hosts (Claude Desktop) the list renders inline as a memo browser (the ``ui://memo-view`` widget) where each memo expands into a PDF preview; other hosts see this JSON list. Each row carries the memo's publish status (draft or published), when it was published (null for drafts), its type, and a pdf_ready flag telling you whether a downloadable PDF has been rendered yet; when the workspace has them, a row also carries when the memo was last modified, who created it, and which Deal Room or Resources area it lives in. The list does not include the PDF link itself — call get_deal_memo for the downloadable preview link. A row also carries a memo_url deep link into the Lev web app; surface it only when the user explicitly asks to open the memo in Lev, and never fabricate one — use only the value present in the response. Filters below are optional and combine; pagination reflects the narrowed set. There is no sort control — ordering is fixed (published first). status: return only memos in one publish state. Values (exact): "draft", "published". Omit to return both. search: case-insensitive substring match on the memo title. Pass a distinctive fragment of the title, not the user's whole sentence. Omit to match every title. memo_type: return only memos of one kind. Values (exact): "debt_financing_om", "credit_memo", "investment_sales", "debt_brokerage", "equity_raise", "broker_opinion_of_value", "investment_committee", "invoice", "other". Omit to return all types. pdf_ready: pass true for only memos whose downloadable PDF has finished rendering, false for only those without a rendered PDF yet. Omit to return both. vault_id: optional vault id to list only the memos in one of the deal's containers (a Deal Room or Resources); ids come from list_deal_vaults. Omit to list memos across every container. limit: maximum memos to return. Defaults to 20, clamped by Lev to 1-200. offset: 0-based index of the first memo to return. Defaults to 0. When the response has has_more=true, walk to the next page by passing the offset emitted in the response hint; keep limit constant across pages.
See a deal's vaults — its Deal Rooms (shared datarooms) and its private Resources area. Use when the user asks what vaults, datarooms, or Deal Rooms a deal has, how its documents are organized into rooms, or wants to pick one to look in. To customers "vaults" usually means the shared Deal Rooms; a deal also has one private Resources area for its own working files. Returns each one with its title, whether it is the deal's primary Deal Room, and how many documents it holds. When naming one to the user, use its title (the Resources area shows as Deal Resources; Deal Rooms carry names like Deal Room, Closing, or a per-lender room) — never the raw type value. This returns the rooms (the containers), not the files inside them — use list_deal_documents to browse the files, optionally passing a vault_id from here to list just one room's files.
Find, filter, and list CRE financing deals in your account. The home for "find / show me / which deals…" requests: search by name, or filter by loan type, transaction type, business plan, loan-amount range, created/updated timestamp range, which pipeline / pipeline status a deal is currently in, or whether it has been archived. For the deals *in* a pipeline, filter here by pipeline_id — list_pipelines only describes the pipelines themselves, and summarize_pipeline gives a narrative book-level read. Returns deal summaries; use get_deal for one deal's full detail, or summarize_deal for a written snapshot. search: the canonical path for resolving a deal by name — find the deal called X, pull up 23 Spruce Street. Case-insensitive substring match across deal title, property city/state, and sponsor company name. Pass the distinctive fragment (Spruce Street), not the user's whole sentence. Results are unranked — if too many match, narrow the term or add filters; never page the full account list to match names client-side when this parameter can do it server-side. Enum values (exact): loan_type: "construction", "heavy_bridge", "light_bridge", "permanent", "land", "predevelopment", "tbd" transaction_type: "acquisition", "refinance", "new_construction", "tbd" business_plan: "stabilized", "value_add", "construction", "land" Synonyms: a plain 'bridge' request spans both heavy_bridge and light_bridge — list both, or leave loan_type unset, rather than declining for lack of an exact match. Caveat on transaction_type: deals commonly have a null transaction_type — it is not required at creation and is often filled in later. Filtering by transaction_type silently excludes every deal that hasn't been categorized yet, so prefer leaving it unset unless you specifically want the categorized subset. Timestamp filters: min/max_created_at and min/max_updated_at are inclusive gte/lte bounds. Use ISO 8601 datetimes with timezone: trailing `Z` or `±HH:MM`, e.g. 2026-04-01T00:00:00Z. Pipeline filters (exact match only — one value each, no range or "in" support): pipeline_id: numeric ID of a pipeline (from list_pipelines). Returns only deals currently on that pipeline. pipeline_status_id: numeric ID of a pipeline status (from list_pipelines, which embeds statuses with IDs). Returns only deals currently in that specific status. Use this for stage-specific filtering and stuck-deal audits. archived: filter by lifecycle state. Omit (the default) to return active and archived deals together; pass false for only active deals, true for only archived ones. Archiving is a separate action from setting pipeline stage — an archived deal keeps its last stage, so filter on this rather than inferring archived-ness from a stalled status. Each returned row reports archived (true/false) and archived_at (ISO 8601 timestamp, or null when active). sort: pass a bare key for ascending; prefix with a minus sign for descending (e.g. -loan_amount). Defaults to descending created_at. Valid keys (exact): "title", "loan_amount", "created_at", "updated_at" Pagination: - Default (sort set): offset mode. Walk pages with offset=N using the value surfaced in the previous response's hint. - Stable paging for bulk sync: pass sort=None; walk pages with cursor=<value> from the hint. cursor and sort cannot be combined — passing both returns a 400. Each row also carries a `urls` object for direct navigation into the Lev web app. Stay in MCP first; never fabricate a url (links come only from the `urls` field, never the retired `levcapital.com` domain); surface a URL only on explicit navigation asks or when MCP can't fulfill the task (file upload → urls.dataroom). Full URL rules live in the server instructions.
Read the notes logged on a contact, deal, placement, or company — or the comment thread on a checklist task. Use for human-written notes like call logs or relationship context. For structured underwriting facts (NOI, loan amount, where a number came from) use search_deal_index instead — that is not what notes are. parent_type: "contact", "deal", "placement", "company", or "checklist_task" — which kind of record to read from. "checklist_task" returns the comment thread shown on that checklist item in the borrower portal. parent_id: numeric ID of the contact, deal, placement, company, or checklist task Returns each note's text, author, and timestamps in chronological order (oldest first). Internal or private notes are not returned. Pagination: uses cursor pagination. To walk beyond the first page, pass the cursor value surfaced in the previous response's hint; the most recent notes are on the last page.
List the pipelines themselves — their names, ordered statuses, and IDs. Each pipeline has ordered statuses that deals can be moved through (e.g., "New Lead" → "Under Review" → "In Closing" → "Closed"). Use this to discover pipeline and status IDs before calling move_deal_to_pipeline_status. This does NOT return the deals in a pipeline — to list those, use list_deals with pipeline_id (or summarize_pipeline for a narrative overview). Each status carries both a raw `status` (wire form, e.g. under_review) and a `custom_status_name` (display form, e.g. "Under Review"). When speaking to the user about a status, use `custom_status_name`; the raw `status` is for filtering and for the move_deal_to_pipeline_status call.
List lender placements (outreach) across your deals. Shows which lenders have been contacted for each deal and their response status. Filter by deal_id to see all placements for one deal, or by status to find placements in a specific stage. Filter by contact_id or private_company_id to see every outreach aimed at a specific lender contact or lender company. Use get_placement only with a known placement_id. Rows include lender_name / contact_name with private_company_id / contact_id, so no follow-up get_lender / get_contact call is needed. Masked placements show non-owner viewers a generic lender_name (e.g. Lender A) and null identity / contact fields. Enum values (exact): status: "new", "sent", "lender_reviewing", "terms_received", "term_sheet_received", "executed_ts_in_closing", "closed", "unresponsive", "willing_to_negotiate", "lender_passed", "archived" lender_status: "origination", "new", "lead_qualification", "quotation", "negotiation", "offer", "term_sheet", "good_faith_deposit", "diligence", "in_closing", "closed", "archived" visibility: "hidden", "masked", "shared" Identity filters (exact match, no range): contact_id: numeric ID of a lender contact (use list_contacts or get_contact to find it). private_company_id: numeric ID of a lender company (use list_companies to find it). Timestamp range filters (ISO 8601 datetime with explicit timezone — trailing `Z` or `±HH:MM` — e.g. 2026-04-01T00:00:00Z; date-only and naive local forms are not guaranteed to parse): min_created_at / max_created_at: inclusive bounds on created_at (gte / lte). min_updated_at / max_updated_at: inclusive bounds on updated_at (gte / lte). sort: pass a bare key for ascending; prefix with a minus sign for descending (e.g. -score). Defaults to descending created_at. Valid keys (exact): "status", "score", "created_at", "updated_at" Pagination: - Default (sort set): offset mode. Walk pages with offset=N using the value surfaced in the previous response's hint. - Stable paging for bulk sync: pass sort=None; walk pages with cursor=<value> from the hint. cursor and sort cannot be combined — passing both returns a 400.
List active team members in your Lev account. Returns each member's name, email, role, and title. /account/team uses offset pagination — walk subsequent pages with the offset value from the returned hint.
List term sheets (loan quotes from lenders) for a specific deal. Shows each lender's quote summary: lender name, rate, loan amount, and status. Masked non-owner reads may show generic lender_name (e.g. Lender A) and org_id=null. Use get_term_sheet for the full breakdown including fees, recourse, extensions, and prepayment terms. Pagination: uses cursor pagination. To walk beyond the first page, pass the cursor value surfaced in the previous response's hint.
Move a deal to a specific status in a pipeline. Use list_pipelines first to see available pipelines and their statuses (with IDs). Example: move a deal to "Under Review" in the Financing pipeline.
Stream an uploaded document's bytes in chunks for the inline viewer widget. Internal plumbing for the vault-browser widget — the model should not call this directly. Given a document's identifiers, the server re-resolves its short-lived signed download link (re-applying the caller's authorization on every call) and returns the requested byte range. The widget loops this, advancing offset until has_more is false, then renders or downloads the assembled bytes. Identifiers (not a URL) are passed in so no signed link is ever exposed to the client and the fetch target can't be tampered with; streaming through the server keeps the browser off S3 (no CORS) and bounds each response. deal_id, document_id: identify the document (same as get_deal_document). offset: 0-based byte offset to start at. byte_count: bytes to read this call (clamped to 512KB). The response carries total_bytes and has_more so the widget knows when to stop.
Stream a memo PDF's bytes in chunks for the inline viewer widget. Internal plumbing for the memo-view widget — the model should not call this directly. Given the same identifiers as get_deal_memo, the server re-resolves the memo's signed PDF link (re-applying the caller's authorization on every call) and returns the requested byte range. The widget loops this, advancing offset until has_more is false, then renders the assembled bytes with PDF.js. Identifiers (not a URL) are passed in so no signed link is ever exposed to the client and the fetch target can't be tampered with. Streaming through the server keeps the browser off S3 (no CORS) and bounds each response. deal_id, memo_id, quality: identify the memo (same as get_deal_memo). offset: 0-based byte offset to start at. byte_count: bytes to read this call (clamped to 512KB). The response carries total_bytes and has_more so the widget knows when to stop.
Run Lev's AI lender match for a deal — the ranked lenders to take this deal to. The home for "which lenders should I approach for this deal", "find me lenders", "run lender matching". Triggers an AI-ranked search that scores the lenders most likely to finance the deal. To look up one lender you already know by id, use get_lender instead; this discovers and ranks lenders for a specific deal. Paid action — running the match costs about 2,000 credits. It runs in two steps so the cost is never charged without agreement: called without confirmation it charges nothing and returns the cost so you can tell the user and ask whether to proceed; once they agree, run it again with confirmation to start the match. State the credit cost in plain language and get the user's agreement first; never expose the confirmation parameter or ask the user to set it. Matching runs in the background, so this returns the search status, not the ranked lenders — retrieve those with get_lender_recommendations once ranking completes. Re-running for the same deal reuses a recent in-progress or completed match rather than charging again. confirm: leave unset to preview the cost; set only after the user has agreed in plain language to the credit charge.
Add a metric value the deal doesn't have yet — record one or more user-supplied or sourced values. Use this to record a measured or extracted underwriting fact — NOI, occupancy, expenses, or source-reported valuation/purchase price — that the deal does not have yet, or to log an additional sourced observation for one it does. Discover the metric and its id with list_deal_index_metric_definitions. To change or correct a fact the deal already shows (e.g. 'fix the NOI to $1.25M'), don't use this tool — use search_deal_index to find it, then update_deal_index_fact, which sets the canonical value directly. Reach for this tool to add a value, not to edit one in place. Route by the catalog's suggested_write_via before recording here: index → this tool; deal_record → the named CRM tool (update_deal / update_company / update_contact), NOT this one; clarify (loan amount and deal financials are common cases) → ask whether the user is setting the deal's official value (CRM tool) or logging what a source reported (here). Don't guess. How recording behaves: think of the SOT as a fact slot keyed by metric_id + entity_ref. This logs a new observation into that slot; it does not erase prior observations or create a separate fact slot for the same metric/entity pair. Repeating the same metric/entity keeps the same sot_id and creates a new observation_id. The displayed value follows Lev's promotion logic, so it may not change after recording succeeds. Always confirm the concrete change with the user in plain English first. This does not create entities. To record a value for a property the deal doesn't have yet, add the property via update_deal (add_properties) first, then record against its entity_ref. values: a list of values to record, each an object with: metric_id: numeric id from list_deal_index_metric_definitions. value: the value to record, as text (e.g. 1250000, or 92%). entity_ref: optional. Target an existing entity, such as `property:702` or `sponsor_contact:55`, taken from the catalog or a search_deal_index result. Omit for deal-level facts; on a single-property deal Lev can infer it. group_ref: optional. Use only to group several values for the same entity when no entity_ref is available yet. Each value is recorded independently: the response reports how many were recorded and surfaces any the backend rejected, so report the true outcome — never claim a value was saved if it appears under failed.
Where a deal's numbers come from and what its documents say — indexed facts, metrics, and their source documents. The tool for "what's the NOI / occupancy / DSCR", "where did this number come from", and the first step to correct a fact (find it here, then update_deal_index_fact). Broader than in-place NOI: loan terms, proceeds, LTV/LTC, DSCR, debt yield, occupancy, rent roll, revenue/expenses, valuation, capex, property facts, sponsor or borrower background, dates. For the deal's plain stored CRM fields (loan amount, sponsor, status, close date) use get_deal instead; for a written summary use summarize_deal. Finds facts the deal ALREADY has; to discover what metrics CAN be recorded, use list_deal_index_metric_definitions instead. Do not conclude that source documents are unavailable just because get_deal does not list files — inspect this tool's source metadata first. context: required natural-language search phrase. Be specific about the metric or topic you want. For broad discovery, use a context like: key underwriting facts, loan terms, property facts, financial metrics, sponsor, valuation, rent roll, occupancy, capex, and source documents. min_score: similarity threshold from 0 to 1. Defaults to 0.3; raise it for narrower matches, lower it only when recall matters more than precision. limit: maximum ranked facts to return. Defaults to 20 and is clamped by Lev to 1-200. For broad fact-discovery (e.g. a complete editable picture), set min_score=0 and limit=200. This is high-recall, not exhaustive: Lev clamps at 200 per call (under the cap the result set is deterministic across differently-phrased contexts; over it, context-driven ranking picks which 200 you see). If ``total`` or ``has_more`` indicates more facts exist, treat the result as the top page, not the full inventory. High-recall responses can be large. For deeper inspection of one fact, follow up with list_deal_index_observations on its sot_id. include_signed_urls: default false. When true, document-backed source records may include short-lived signed attachment URLs; the response converts them into source.file_link Markdown hyperlinks (raw source.signed_url is omitted). Keep false when the user asks only what the source is (summarize file_name, pages, source.type, observation_count); set true only on links/downloads or open/inspect asks. Never show a bare signed URL in the final user answer; present only the file name as a hyperlink. If signing fails, source.file_link is absent and source.signed_url_error explains the typed reason. Results carry ranked metric/value fields, context and summary text, score, and source metadata (document id/type, file name, page range, observation count). source.type=user_input means user-entered data rather than an attachment; say no document-backed indexed facts were found when every relevant result is user_input. Each result also carries an editable hint (true / false / null) for whether update_deal_index_fact can change the fact. Hint only — the backend re-checks at update time and rejects non-editable facts with a clear message. Use it to decide whether to offer an edit, never as a security boundary. The ``sot_id`` field on each result is the fact identifier you pass back to list_deal_index_observations and update_deal_index_fact — internal, never surface it to the user. Scope of editable=false: the flag covers ONLY update_deal_index_fact — do NOT tell the user a fact is read-only based on it alone. Consider these alternative update paths before concluding anything is unsupported: - Deal-level fields (loan_amount, business_plan, transaction_type, loan_type, title, description, estimated_close_date, sponsor_private_company_id, purchase_price, estimated_value, total_cost, total_cost_basis, land_cost) → update_deal. - Sponsor profile facts → update_company on the linked company_id, resolved from deal.sponsor_private_company_id (get_deal returns it). - Broker profile facts → update_company on the broker's company. Resolve via list_contacts (filter by email, or first/last name from get_deal's team row — there is no generic name arg), then get_contact for the company_id if the summary lacks it. - Broker team / contact facts → update_contact. Resolve the contact_id the same list_contacts way; do not pass the team row's id or user_id directly to update_contact — those are different identifiers. - Property identity fields (address, city, state, zip) → update_deal property sub-ops (update_properties on the existing property_id, or add_properties) — a canonical CRM write path. A small set has no alternate standard CRM write path today: property-canonical fields without an update_deal sub-op (street, property type, legal description — still index-overridable via update_deal_index_fact when editable=true), sponsor financials, contact phone, and broker_profile Additional States. Reach that conclusion AFTER considering the alternatives. Before any write, confirm the concrete change with the user. Recording a fact the deal does NOT have yet (search returns nothing): use list_deal_index_metric_definitions to find the metric and its write path. Loan amount and deal financials are both-doors cases: official value → update_deal; source-reported value → the index. When intent is unclear, ask rather than guessing.
Show one deal visually — an interactive overview card of its headline terms, property, status, and key facts. Use when the user wants to see a deal: "show me the deal", "pull up deal X", "open the deal card / overview / dashboard". On MCP Apps hosts (Claude Desktop) this renders an inline card with the deal's headline (amount, loan type, transaction), property, pipeline stage, an Archived badge when the deal has been archived, key financials, deal team, and its indexed facts grouped by category with source-document tags. Other hosts get a compact text summary. Archiving is separate from pipeline stage, so an archived deal still shows its last stage. Use this ONLY for a visual look at one deal. For a written summary or narrative overview, use summarize_deal. For raw CRM fields, use get_deal. For one specific metric or where a number came from, use search_deal_index. Resolve a deal name to its deal_id with list_deals first.
Write up one deal in prose: a narrative summary, briefing, memo, or shareable one-pager — including an overview to paste into an email. The tool for "tell me about deal X", "summarize this deal", "put together a memo / overview / write-up for an investment committee". Consolidates get_deal + search_deal_index + list_term_sheets + list_placements into one call and returns prose, at three detail levels. Use a sibling instead for: raw CRM fields (get_deal); a single metric or its source (search_deal_index); an interactive visual card (show_deal). detail: one of "brief" — 1-paragraph headline (~80 words) "standard" — ~200 words: title, property, financials, loan request, activity, open items (default) "memo" — ~600 words, lender-shareable 1-pager structure Every fact-derived quantitative claim cites its source via search_deal_index's source.file_name. Facts without a document-backed observation render as "(user input)". This tool's structuredContent intentionally omits term-sheet/placement lists so calls stay cheap. Resilient to partial backend failures: if term-sheet or placement data is unavailable, the summary still renders from deal + facts with a graceful degradation note. If the deal endpoint itself fails, returns a friendly error. Never fabricate URLs — only emit links present in structuredContent.urls.
Narrative pipeline snapshot at three detail levels. Aggregates pipeline stages + per-stage deal counts + total loan amounts + highlighted deals (stuck longest, closing soon) into one call, producing prose suited for chat surfaces where the user wants a book-level read without paging through list_deals per stage. pipeline_id: optional. When omitted, the tool picks the lowest-order pipeline (matches the Lev UI ordering — for most brokers that's the Financing pipeline). If the account has multiple pipelines, the chosen one is announced in the output so the user can rerun with an explicit id to target a different pipeline. detail: one of "brief" — 1-paragraph headline (~80 words) "standard" — ~200 words: totals, stage distribution, stuck longest, closing soon, open items (default) "memo" — ~600 words, full per-stage breakdown with top 5 deals per stage "Stuck longest" highlights use deal.updated_at as a proxy for in-stage time. Caveat: deal.updated_at advances on any field change, not just stage transitions, so a deal that's been in a stage for months but had its title edited yesterday reads as fresh. The accurate signal (pipeline-row updated_at) requires per-deal fetches we skip in v1. "Closing soon" highlights are drawn from the same per-stage top-page sample used for stuck-longest. On stages with more than 50 deals, a deal with an imminent close date but a fresher updated_at can fall outside the sample — the standard view flags this in Open items. Use list_pipelines for raw status definitions, list_deals for filterable per-stage queries, this tool for narrative synthesis.
Narrative comparison of all term sheets on a deal at three detail levels. Aggregates list_term_sheets + get_deal (for context) + lender-label resolution into one call, producing prose suited for chat surfaces where the broker is deciding which quote to take. Computes two "leaders" — lowest computed all-in rate, and lowest all-in cost (computed all-in rate + origination_fee / term_years) — and surfaces tradeoffs across rate, fees, and term. deal_id: required. The deal whose term sheets to compare. Use list_deals or get_deal to discover the id; use list_term_sheets to confirm a deal has at least one quote. detail: one of "brief" — 1-paragraph headline (~80 words): N quotes, leaders, key tradeoff "standard" — ~250 words: summary, leaders, 5-column comparison table, tradeoffs, open items (default) "memo" — ~600 words, full per-quote detail blocks with every surfaced field Quote labels prefer backend lender_name (including masked Lender A), then placement lender_name, then private_company → name, then cleaned ts.title. Edge cases: - No term sheets on the deal → friendly error suggesting create_term_sheet / list_placements - Single term sheet → mini-summary instead of a 1-row comparison ("Only one quote on file — consider sourcing more") - Mezz / second-lien quotes → flagged in Open items; v1 treats every quote as a standalone senior in the comparison Resilient to partial backend failures: degrades lender resolution per TS when placements or companies fail; surfaces a degraded flag in structuredContent. Re-raises only when list_term_sheets itself fails. On busy deals the backend term-sheet endpoint paginates; this tool walks pages up to a safety cap and exposes ``total_on_deal`` plus a ``partial`` flag in structuredContent. The renderer marks leaders as computed over the fetched subset when ``partial=true`` so the agent doesn't claim a global winner from a prefix.
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.
What are Lev alternatives on ChatGPT?
As of 2026-08-14, Lev competes with Agree Zone, Comuro, Connectlinx, Flatre, GetAgent, HAVN, Propalt in ChatGPT Real Estate Agent & Deal Tools, ranked by public Discoverability Score.
Where is this profile measured?
This profile uses the geography attached to the latest public registry snapshot: US. Locale tags are intentionally omitted.