API & MCP

Authentication

Create a key from the app and send it with every request:

curl https://modellus.ai/api/v1/check_replies \
  -H "Authorization: Bearer mll_your_key" \
  -H "Content-Type: application/json" \
  -d '{}'

From another AI (MCP)

Connect Claude, ChatGPT, or any MCP-compatible client to this address, with the same key:

https://modellus.ai/api/mcp

Specification

The full OpenAPI spec, with every parameter and response, lives at /api/v1/openapi.json.

Available actions (249)

  • check_replies
    Communication
    Writes data

    Reads the connected email inbox (Gmail or Outlook) right now and brings any new replies into Modellus, filing each one on the loan it belongs to. Replies arrive on their own every couple of minutes, so use this when the user does not want to wait: "did they answer yet?", "check my email", "look for new replies", "I just got an email from her, pull it in". Only mail that answers something Modellus sent, or that comes from someone in the rolodex, is brought in — the rest of the personal inbox is never touched. If no mailbox is connected, say so and offer connect_email. With `address` it SYNCS that one mailbox: the new mail plus the next stretch of its older history (or the last 24 hours again once the history is all in) — the "Sync emails" button in Settings. Use that for "sync my work email", "my emails from X are missing", "pull in the old emails".

    addressstring
    Only this mailbox, as the user says it, and with its history too. Left out: the new mail of every mailbox with emails on.
  • reassign_message
    Communication
    Writes data

    Moves an incoming message (email, text, WhatsApp) to the right loan file or the right person, when it was filed on the wrong one. Use it when the user says "this email is about the Garcia file, not the Smith one", "that reply belongs to her refinance", "file this under Maria" or "this got attached to the wrong loan". Get the message id from view_inbox or view_conversation. It never deletes the message and never changes what it says.

    messageintegerrequired
    The id of the incoming message, as the inbox lists it.
    loanstring
    Which loan file it belongs to: a borrower name, a property address or a loan number. Use "none" to detach it from any loan.
    contactstring
    Who it is from, when the sender was matched to the wrong person: a name, email, phone or contact id.
  • resumen_cuenta
    Account
    Read-only

    Returns the asking account's own data: display name and when it was created. Use it at the start of a conversation to know who you are talking to, or when asked "who am I?".

    No parameters.

  • export_data
    account
    Read-only

    Exports this account's data as JSON: contacts, loans and pre-quals, the people on each file, financial items, the document checklist, tasks and messages. Use it when the user wants a backup, wants to take their data somewhere else, or asks for "everything on the Martinez file" in one piece. Ask for one table with `que` when they only need part of it. Uploaded files themselves are not included — their paths and status are.

    quearray
    Which tables to include. Omit for all of them.
    limiteinteger
    Max rows per table. Default 1000.
  • save_day_note
    Tasks
    Writes data

    Writes, rewrites or removes a note on a DAY of the calendar — the loose line of a day planner that does not belong to any one file: "note for today: no showings after 4", "remind me on Friday that the office closes early", "scratch that note". Say the day as the user says it ("today", "tomorrow", or a date); leave it out and it goes on today. To rewrite or remove one, pass its note_id — the ids come back in view_dashboard (today) and in view_calendar (any period); only the person who wrote a note can change or remove it. Use add_comment instead when the note is ABOUT a loan, a pre-qual, a person or a task, and save_task when it is something to do that needs to be checked off.

    notestring
    What the note says. Required to write a new one or to rewrite an existing one.
    datestring
    Which day it belongs to: ISO (YYYY-MM-DD) or "today"/"tomorrow"/"yesterday". Defaults to today.
    note_idinteger
    The note to rewrite or remove. Leave empty to write a new one.
    removeboolean
    True removes the note named by note_id.
  • search
    Account
    Read-only

    Searches the whole account at once — contacts, loans, pre-quals and tasks — and returns the top matches per group. Use it when the user searches for something and it is not clear what kind of thing it is ("search Robert Miller", "anything on 412 Elm?", "find insurance"). If you already know it is a loan or pre-qual, use find_loan; if you know it is a person, use find_contact — those return the full record. Accepts a name, an email, a phone fragment, a property address, a loan number or a task title.

    querystringrequired
    What to look for, as the user says it
  • adjust_view
    Pipeline
    Writes data

    Adjusts the list screens: the pre-qual pipeline, the loan pipeline, the contacts list, or the TASKS screen. On Tasks it switches between the task LIST and the CALENDAR (vista 'tasks' with forma 'lista' or 'calendario': "show my tasks as a calendar", "back to the task list") and GROUPS the task list (vista 'tasks' with agrupar 'borrower': one group per borrower, by last name, 'No borrower' last — "group my tasks by borrower"; agrupar 'default' goes back to the sections, or to due date when there are no sections); both are remembered per person. On the other lists it shows or hides columns ("show the loan number in the pipeline"), REORDERS a column ("put the amount column first", "move closing date before created"), expands or collapses COLUMN GROUPS ("expand the property columns"; the pipelines have the twelve sections of the file: contacts (Contact Information), loan (Loan Information), dates, rate (Rates), property (Subject Property), title, reo (Real Estate Owned), income, borrower, asset and underwriting (Underwriting Conditions) — only contacts and dates exist on the pre-qual pipeline, since a pre-qual has no loan, property or rate yet — and the contacts list has profile, reach, work, followup, business (stage, loans, closings, closed volume, last closing) and notas), turns a WHOLE GROUP of columns on or off at once ("show me all the title columns", "hide every date"), REORDERS THE GROUPS themselves ("put the documents block first", "move dates before property"), PINS a column to the left or right edge so it stays in view while scrolling sideways ("keep the loan amount visible", "pin the closing date to the right", "unpin the rate"), switches the LIST LAYOUT between the table of rows, the grid of cards and the KANBAN board of stage columns ("show the loans as cards", "show me the pipeline as a kanban", "show my contacts as a board", "back to the table view") — each list remembers its own; on a phone table and cards are the same list of cards, while kanban shows there too — GROUPS the contacts kanban and cards BY STAGE (New, Contacted, Nurturing, Active, Client, Past client — the default) or BY ROLE (one column/section per contact type: Realtor, CPA / Accountant, Title Company…): "group my contacts by stage", "show the board by role" — changes row density (compact/standard/comfortable), SORTS the list by a column ("sort the loans by amount, biggest first", "sort my contacts by closings" -> contacts column closings; "most recent closing first" -> last_closing desc; "newest contacts first" -> created desc, which is also the contacts default (shown as "Date added"); the sort applies to the table, the cards and inside each kanban column) and FILTERS it by the values of a column ("only show FHA loans", "just the ones assigned to Ana", "clear the filters"). The sort and the filters are what the column header menus do, and they stick for next time. Everything here is PER PERSON: it changes how the caller sees the list, never how their teammates see it. To read the pipeline itself use view_pipeline; to change the stage of one file use move_stage.

    vistastringrequired
    Which list to adjust: the pre-qual pipeline, the loan pipeline, contacts, or 'tasks' (the Tasks screen: only forma and agrupar apply).
    mostrararrayrequired
    Column ids to turn on. Empty array if none.
    ocultararrayrequired
    Column ids to turn off. Empty array if none.
    moveranyrequired
    Use when the user asks to reorder a column ("put amount first", "move closing date before created"). Give exactly ONE of antes, despues or posicion. In the pipelines a column always stays inside its group, so it lands at the closest spot within it. Null if the user did not ask to reorder.
    densidadanyrequired
    Row density, if the user asked to change it. Null otherwise.
    formaanyrequired
    Tasks only: 'lista' (the task list) or 'calendario' (the calendar with the tasks on their due dates). Other lists: how to lay the list out: 'tabla' is the row table with all the columns, 'tarjetas' is the grid of cards, 'kanban' is the board with columns where cards are dragged between them (the loan stages in the pipelines; in contacts, roles or CRM stages as `agrupar` says). It is the layout in the View menu above the list, and it sticks per list. Null if the user did not ask to change it.
    agruparany
    Contacts: how the kanban and the cards are grouped — 'role' (one column per contact type) or 'stage' (one per CRM stage, the default). Tasks: 'borrower' (one group per borrower) or 'default' (by section, or by due date without sections). Null if the user did not ask to change it.
    expandir_gruposarrayrequired
    Column groups to expand into their child columns. Empty array if none.
    colapsar_gruposarrayrequired
    Column groups to fold back to ONE read-only summary column — only when the user wants them out of the way; folded columns cannot be edited. Empty array if none.
    mostrar_gruposarrayrequired
    Groups whose EVERY column should be turned on at once ("show all the title columns", "I want the whole dates block"). This is about WHICH columns exist in the table, not about folding: use expandir_grupos when the user only wants a folded group opened back up. The group is expanded too, since turning columns on means wanting to see them. Empty array if none.
    ocultar_gruposarrayrequired
    Groups whose every column should be turned off at once ("get rid of all the document columns"). Prefer colapsar_grupos when the user just wants them out of the way for now — folding keeps them one click away, this one takes them out of the table. Empty array if none.
    mover_grupoanyrequired
    Use when the user asks to move a whole BLOCK of columns ("put the documents group first", "move dates before property"). Give exactly ONE of antes, despues or posicion. To move a single column use mover instead. Null if the user did not ask.
    ordenanyrequired
    Sort the list by a column. Pass null to LEAVE THE SORT AS IT IS. To remove it, use quitar_orden.
    quitar_ordenbooleanrequired
    true = go back to no sorting. false otherwise.
    filtrosarrayrequired
    Filters by column value, like the header menu. Each entry REPLACES that column's filter. Empty array if the user did not ask to filter.
    quitar_filtrosbooleanrequired
    true = clear every column filter. false otherwise.
    fijararrayrequired
    Columns to pin to an edge so they stay visible while scrolling sideways, or to unpin. Empty array if the user did not ask. A hidden column cannot be pinned: show it in the same call.
  • cambiar_nombre
    Account
    Writes data

    Changes the account's display name. Use it only when explicitly asked to change or correct how the user is called.

    nombrestringrequired
    The new name, exactly as they want it displayed
  • set_area_code
    Account
    Writes data

    Sets the account's default area code, used to complete a 7-digit phone number typed without it ("555-0142" saves as "(786) 555-0142" with area code 786). Use it when the user says something like "set the default area code to 786", "our office moved to Orlando, use 407", or asks what the area code is set to. Without one set, 305 is assumed.

    area_codestringrequired
    The 3-digit area code, e.g. "786".
  • view_profile
    Account
    Read-only

    Returns the profile of the person asking: their display name, sign-in email, contact email (the one clients see on letters and the portal), phone, photo, NMLS number, the name of the team they work in, whether the app is white-labeled with their company logo, whether their email is verified, whether an email change is still waiting to be confirmed, and their role in this account (owner, loan officer, or assistant). Use it when the user asks "what is my name here", "what email am I signed in with", "what email do clients see", "what is my team called", "is my email verified", "did my email change go through", "what can I do in this account", or before changing any of it with update_profile or change_email.

    No parameters.

  • update_profile
    Account
    Writes data

    Changes the asking person's own profile: display name, phone number, contact email, NMLS number, profile photo, brand logo, company logo, brand color, or bio — the last four are the white label of the borrower portal (logo on top of the portal sidebar, company logo on the phone header, brand color on the buttons and links, bio under their name). Use it when the user says "change my name to...", "my phone is...", "clients should email me at...", "put ana@office.com on my letters", "update my NMLS", "remove my profile picture", "set my bio to ...", "take my logo off the portal". Only the fields given are touched; the rest stay as they were. To see what they are now, use view_profile.

    namestring
    The new display name, exactly as they want it shown.
    phoneany
    Their phone number, as they say it. null clears it.
    contact_emailany
    The email clients see: the signature of letters and PDFs and the borrower portal. It is NOT the sign-in email (that one changes with change_email). null clears it and clients see the sign-in email again.
    nmlsany
    Their NMLS license number — it goes on the pre-approval letters. Only the account owner has one. null clears it.
    photo_urlany
    The URL of their profile photo. Pass null to remove it. Uploading a new picture is done from the settings screen — from here only removing it makes sense.
    logo_urlany
    The loan officer's own brand logo, shown at the top of the borrower portal sidebar. null removes it. Uploading a new file is done from the settings screen; from chat, removing it or pasting an image link.
    company_logo_urlany
    The company logo, shown in the header of the borrower portal on the phone. null removes it (and its dark version). A pasted link is saved as is; to also get the clean transparent version and the one for dark mode, use regenerate_company_logo with that link instead.
    company_logo_dark_urlany
    The company logo for dark mode (dark ink turned white). regenerate_company_logo fills it; set it by hand only if the user gives a separate dark-mode logo. null removes it.
    company_logo_original_urlany
    The logo file exactly as uploaded, before cleaning — what regenerate_company_logo works from. It fills it; not for the chat.
    brand_colorany
    The accent color of the borrower portal (buttons, links, highlights) — the last piece of the white label, so the portal looks like their brand and not like everyone else's. A 6-digit hex ("#1d4ed8"). Use it when the user says "my brand color is...", "make the portal green", "use the color of my logo". null puts the default accent back.
    bioany
    A short introduction borrowers read in their portal, in the words the user gives ("15 years helping Miami families buy their home"). null or an empty text clears it.
  • reset_password
    Account
    Writes data

    Emails the signed-in person a link to set a new password. Use it when the user says "I want to change my password", "reset my password", "I forgot my password". Never ask them to type the new password here — the link is where they set it.

    No parameters.

  • resend_email_verification
    Account
    Writes data

    Resends the email that confirms the signed-in person's address. Use it when the user says "I never got the confirmation email", "resend the verification", or after view_profile shows their email is not verified yet.

    No parameters.

  • change_email
    Account
    Writes data

    Starts changing the email address the signed-in person uses to sign in. Use it when the user says "change my email to...", "I lost access to my email", "I want to sign in with another address", or "update my login email". It does not change anything on its own: it sends a confirmation link to the new address and to the current one, and the change only takes effect once both are opened. Calling it again with the same address sends the links again. To see whether a change is still waiting, use view_profile.

    emailstringrequired
    The new address they want to sign in with. Ask for it if they did not say it — never guess it from a contact or from a message.
  • view_integrations
    Account
    Read-only

    Shows EVERYTHING this account has connected and whether each one is actually working: Arive (the loan origination system), the user's own email account (Gmail/Outlook) and Google Contacts — status, when each last worked, and what the last failure said. Use it when the user asks what is connected, how their integrations are doing, where their messages are sent from, why their emails are not going out from their own address, why their contacts are not syncing, or right after they finish any authorization, to confirm it worked. To test a connection right now use check_integration; for just the mailboxes (which one is the default, who owns each) use view_connected_mailboxes; to change any of it use connect_arive, connect_email, disconnect_email, set_default_mailbox, connect_google, sync_google_contacts, push_contacts_to_google or disconnect_google. It also shows the Arive cutoff date — from when loans get imported — which set_arive_cutoff changes, and whether Arive live updates are on.

    No parameters.

  • view_connected_mailboxes
    Account
    Read-only

    Lists the mailboxes connected to this account: which one is the DEFAULT (the one every email leaves from when no sender is chosen — the starred one in Settings), who on the team owns each one, and which ones YOU can send from. Use it when the user asks what mailboxes are connected, "which email do I send from", "whose mailbox is that", before sending an email from a specific address (send_email / send_message take `from`), or before changing the default with set_default_mailbox. It also says what each one is used for: emails, contacts or both (set_mailbox_uses changes it). One thing it does NOT say is whether each connection is healthy — that is view_integrations. Replies are the exception to the default: an answer always goes out from the mailbox the original email arrived at, whatever the default is. Careful: this is NOT view_mailbox, which opens the inbox and lists the conversations inside one of these mailboxes.

    No parameters.

  • check_integration
    Account
    Writes data

    Tests ONE connection right now and reports whether it actually works: arive (authenticates and reads a loan), google (reads a contact from the linked Google address book), or email (the connected sending address). Use it when the user suspects something is down or wants it checked — "is Arive working?", "my emails are not going out from my address", "is Google still connected?", "my contacts stopped syncing", "test my Google connection", "check the connection" — and after they reconnect or fix credentials, to confirm the fix. To just see how all three are doing without testing anything, use view_integrations. If it comes back expired or denied, the fix is connecting it again with connect_arive, connect_google or connect_email — retrying will not help. Testing has no side effects: it never sends an email and never writes to the user's Google contacts.

    integrationstringrequired
    Which connection to test.
  • connect_email
    Account
    Writes data

    Starts connecting the user's own email account (Gmail or Outlook) so their messages go out from their real address instead of the generic Modellus one, and so their address book can be imported. Use it when the user asks to connect their email, or when they want to import their contacts and no email account is connected yet. Several mailboxes can be connected (a personal one, the company one, a teammate's) — use it again to add another one ("also connect my work email"), or with `replace` to swap one of them. Anyone on the team can connect THEIR OWN mailbox this way; only the account owner can replace someone else's. Reconnecting the same address (an expired authorization) needs no `replace`. It returns an authorization link — show it to the user and tell them to open it, sign in, and come back; then check view_integrations to confirm it worked. Ask what the new mailbox is for when it is not obvious: `use` = "emails" (read into the inbox and send from it), "contacts" (only sync the Google address book — Gmail only) or "both". Change it later with set_mailbox_uses.

    providerstringrequired
    Which email provider the user wants to connect.
    replacestring
    Only when two mailboxes are already connected and the user wants to swap one: the address of the mailbox this one replaces.
    usestring
    What the mailbox is for. Outlook is always "emails". Left out: emails, and the address book stays where it is.
  • disconnect_email
    Account
    Writes data

    Disconnects one of the user's own email accounts (or all of them). Use it when the user asks to disconnect, unlink or remove their Gmail/Outlook connection. With two mailboxes connected, say which one (`address`); the other one becomes the default. With none left, messages go back out through the generic Modellus sender and replies are no longer read from the inbox. Messages already in the queue leave from whatever is connected when they go out. Each person can only disconnect THEIR OWN mailbox: the one connected by another member of the team can only be removed by the account owner. Disconnecting also removes that mailbox's emails from Modellus — only our copies; nothing in their real mailbox is ever deleted or moved, and emails Modellus SENT stay. So call first with confirm=false, tell the user how many emails will be removed from Modellus, and call again with confirm=true once they agree.

    addressstring
    The mailbox to disconnect. Required when more than one is connected; with just one it can be left out.
    confirmboolean
    true = disconnect now. false or left out = only count the emails that would be removed from Modellus, and change nothing.
  • view_google_contacts
    Account
    Read-only

    Shows ONLY the Google Contacts connection: which Google account is linked (name and email), whether it is working, whether that connection can only READ the address book (read_only: then Google contacts come in but nothing Modellus creates goes out, and it is fixed by connecting Google again and accepting the contacts permission), whether Modellus is writing into Google (pushing_to_google), how many contacts already exist on both sides, how many are still only in Modellus, how many are waiting because Google could not be reached, and when it last ran. Use it when the user asks specifically about Google — whether it is connected, why their contacts are not syncing, how the sync is going, or right after they finish the Google authorization. If they ask about their connections in general, or about Arive or their email too, use view_integrations instead: it reports all three at once. To change any of it: connect_google to connect or reconnect, sync_google_contacts to run a sync now, push_contacts_to_google to send Modellus contacts to Google right away or to stop writing to Google, disconnect_google to stop syncing altogether.

    No parameters.

  • connect_google
    Account
    Writes data

    Starts connecting the user's Google account so their contacts stay in sync between Modellus and contacts.google.com, in both directions. Use it when the user asks to connect Google, sync their Google contacts, bring their Google address book in, or when they ask for contact sync and no Google account is connected yet. It returns an authorization link — show it to the user and tell them to open it, sign in, and accept the permissions; then call view_google_contacts to confirm it worked and to start the first import. One authorization covers both their mail and their address book, so connect_email opens the same link — there is no second step to send the user to.

    No parameters.

  • disconnect_google
    Account
    Writes data

    Disconnects the Google account used for contact sync, so contacts stop flowing between Modellus and contacts.google.com. Use it when the user asks to disconnect, unlink or stop syncing Google contacts. Nothing is deleted on either side — the contacts already imported stay, and the ones already in Google stay too; they simply stop updating each other. This does not touch their Gmail sending connection (that one is disconnect_email).

    No parameters.

  • sync_google_contacts
    Contacts
    Writes data

    Runs a Google contact sync right now: brings in contacts from contacts.google.com that Modellus does not have, matches the ones it already has instead of duplicating them, and sends the other way the ones that are only in Modellus. It runs BOTH ways by default: nothing has to be turned on first. Use it when the user asks to sync, refresh or update their Google contacts, when they just connected Google, or when they say a contact they changed has not shown up on the other side. It NEVER deletes anything on either side. Large address books are done in batches: if it says more is left, just call it again.

    No parameters.

  • preview_google_push
    Contacts
    Read-only

    Counts how many Modellus contacts are already in the user's Google address book and how many are still on their way there, without writing anything. Use it when the user asks whether their contacts are all in Google, how many are missing, or how the sync is coming along, and to check progress after push_contacts_to_google. If they also want to know whether the connection is healthy or when it last ran, view_google_contacts tells the whole story instead.

    No parameters.

  • push_contacts_to_google
    Contacts
    Writes data

    Pushes the Modellus contacts that are still missing from the user's Google address book RIGHT NOW, writing the Modellus contact id into a Google custom field so nothing is ever duplicated. Contacts sync both ways on their own, so you never need this to switch anything on: call it when the user wants their contacts in Google immediately instead of waiting for the next scheduled sync, when they just fixed the Google connection, or when they ask why something they created here is not in Google yet. It never deletes anything in Google. Large books go in batches: if it says more is left, call it again, or let the scheduled sync finish it. Use stop=true ONLY when the user explicitly asks Modellus to stop writing into their Google contacts — everything already there stays, and calling it again with stop=false resumes.

    stopbooleanrequired
    True to STOP writing Modellus contacts into Google from now on. Nothing already in Google is removed, and their Google contacts keep coming into Modellus. False to push now (and resume pushing if it had been stopped).
  • view_onedrive
    Account
    Read-only

    Shows whether OneDrive is connected and whether it is actually answering right now — whose account it is, if an authorization is half done, and what to do when something is wrong. Use it when the user asks if OneDrive is connected, why Modellus cannot see their folders, or right after they finish the OneDrive authorization, to confirm it worked. It also says whether OneDrive is switched on for documents and the file-naming style learned from the drive. To connect it use connect_onedrive, to drop it use disconnect_onedrive, to switch it on or off for documents use set_drive_for_documents, to learn the naming use scan_drive_naming, and to actually look at the folders use list_onedrive_files.

    No parameters.

  • connect_onedrive
    Account
    Writes data

    Starts connecting the user's OneDrive so Modellus can READ the work folders where they keep their real loan files — TEAMGM WORKFOLDERS, with LOANS and PREQS inside. Use it when the user asks to connect OneDrive, to let Modellus see their folders or spreadsheets, or when list_onedrive_files or read_onedrive_file says nothing is connected yet. It returns an authorization link: show it, and tell them to open it, sign in with their Microsoft account and accept. Then call view_onedrive to confirm it worked. This is separate from their email connection — connecting Outlook again does NOT give access to files. Modellus only ever reads; it never changes or deletes anything in OneDrive.

    No parameters.

  • disconnect_onedrive
    Account
    Writes data

    Disconnects OneDrive: Modellus stops being able to read the user's files. Use it when they ask to disconnect OneDrive, to revoke that access, or when they want to connect a different Microsoft account — in that case disconnect first and then connect_onedrive. Nothing in OneDrive is changed or deleted, and anything already brought into Modellus stays. To connect it again use connect_onedrive.

    No parameters.

  • view_calendars
    Account
    Read-only

    Lists the calendars Modellus is reading (Google Calendar, Outlook). Use it when the user asks whether their calendar is connected, why their meetings are not showing, or before connecting another one.

    No parameters.

  • connect_calendar
    Account
    Writes data

    Connects the user's own calendar — Google Calendar or Outlook — so their meetings show up next to the tasks and the loan dates in the Modellus calendar. Use it when they ask to connect, sync or see their calendar, when they ask why their meetings are not showing, or when they want to check their availability from here. It is read-only: Modellus never creates, moves or deletes anything in their calendar. For Google it returns an authorization link — show it and tell them to open it and accept. For Outlook there is nothing to authorize as long as their Outlook mailbox is connected: it is done when this returns.

    providerstringrequired
    Whose calendar: google = Google Calendar, outlook = Microsoft Outlook. Ask if the user did not say.
    mailboxstring
    Outlook only, and only when more than one Outlook mailbox is connected: which address the calendar comes from.
  • disconnect_calendar
    Account
    Writes data

    Stops showing a connected calendar in Modellus. Use it when the user asks to disconnect, unlink or stop seeing their Google or Outlook calendar here. Their calendar is not touched: only Modellus stops reading it.

    providerstringrequired
    Which one to stop reading.
  • list_onedrive_files
    archivos
    Read-only

    Lists what is inside the user's OneDrive: the top level when nothing is given, the contents of a folder, or everything whose name matches a search. Use it when the user asks what is in their OneDrive, what is in a folder of theirs, where a file is, or to find a loan folder before reading something from it — their work lives in TEAMGM WORKFOLDERS, with LOANS and PREQS inside. Name the folder the way they do ("LOANS", "TEAMGM WORKFOLDERS/PREQS"), never an id. To read what is in one of the files use read_onedrive_file. If it says OneDrive is not connected, use connect_onedrive.

    folderstring
    The folder to open, by path ("TEAMGM WORKFOLDERS/LOANS") or by name ("LOANS"). Leave it out for the top level of the drive.
    searchstring
    Look for files and folders whose name matches this, anywhere in the drive. Use it when the user names something but not where it is. Ignores folder.
    folders_onlyboolean
    Only folders, to show the user how their drive is laid out.
  • list_onedrive_loan_folders
    archivos
    Read-only

    Lists the loan files the user keeps as folders in their OneDrive work folders, split into loans and prequals, with the borrower name and the file number read off each folder name. Use it when the user asks what files or folders they have in OneDrive, how many loans or preqs are sitting there, whether a particular borrower has a folder, or before opening one of those folders. It only reads the folder names — to see what is inside one use list_onedrive_files, and to read a document use read_onedrive_file. These folders are NOT the loans in Modellus: nothing here is imported, so do not claim a borrower is in the system because a folder exists. If it comes back not connected, tell the user to connect OneDrive in Settings → Connections, or use connect_onedrive.

    typestring
    Only loans, or only prequals. Leave it out for both, which is what to do when the user just asks what they have.
    searchstring
    Only the folders whose name or number matches this — a borrower surname or a file number, as the user says it.
    folderstring
    The work folder to look in. Leave it out: it is "TEAMGM WORKFOLDERS". Only pass something when the user says their files live somewhere else.
  • read_onedrive_file
    archivos
    Read-only

    Reads what is inside a file in the user's OneDrive: a spreadsheet comes back as rows, and a PDF or a photo comes back read and summarised. Use it when the user asks what a file of theirs says, to pull numbers out of one of their spreadsheets, or to check a document in a loan folder. Name the file the way they do ("Smith prequal.xlsx", "TEAMGM WORKFOLDERS/LOANS/Smith/appraisal.pdf"); use list_onedrive_files first when you are not sure it exists. Reading never changes the file. This is for files in OneDrive — read_document is for the ones already attached to a loan in Modellus.

    filestringrequired
    The file, by path or just by name, as the user says it. The name alone is searched across the whole drive.
    sheetstring
    Which tab of a spreadsheet to read. Leave it out for the first one; the reply lists the others.
  • find_contact
    Contacts
    Read-only

    Search the rolodex by anything the user says: a name (even partial or misspelled), a phone number or its last digits, an email, a tag, or a role like "realtor" or "title company". Use it whenever the user asks about a person ("what is Maria's number?", "show me my appraisers"), before saving someone you are not sure exists, and to get the contact details other actions need. Returns matching contacts with their roles, tags, CRM stage and key data; when few match, it includes their latest activity. Pass `stage` to list who is at one step of the contacts board ("who is in nurturing?", "my past clients"). Listing and selling agents are one contact type, "realtor": asking for either finds them all; a query that is just a type ("accountants", "realtors") lists that type (CPA is "CPA / Accountant"). Pass `sort` to order the list: "created" for "my newest contacts", "who did I add this week", or to match the Contacts screen, whose default order is date added, newest first; "last_closing" for "my realtors by closings, most recent first"; "closings" for "who closed the most with me". Every contact comes with its closings count and last closing date.

    querystring
    Free text: name, email, phone or fragment. Omit to browse by role or tag.
    rolestring
    Only contacts of this type, e.g. "realtor" or "title_company". "listing_agent" is its own type; "selling_agent" means realtor here.
    stagestring
    Only contacts at this CRM stage: "new" (New), "contacted" (Contacted), "nurturing" (Nurturing), "active" (Active), "client" (Client), "past_client" (Past client).
    tagstring
    Only contacts carrying this tag.
    limitinteger
    Max results, default 10.
    sortstring
    Order of the results: "created" = most recently added first (the Contacts screen default), "last_closing" = most recent closing first, "closings" = most closed loans first (both put people who never closed last), "name" = A to Z. Omit for best match / recently touched.
  • set_contact_stage
    Contacts
    Writes data

    Moves a contact to another stage of the contacts CRM board (New, Contacted, Nurturing, Active, Client, Past client). Use it when the user says where a relationship stands: "I just called Maria, mark her contacted", "move the Laventi lead to nurturing", "John is a client now", "put Ana back to new". This is the stage of the PERSON, not of a loan — to move a loan file use move_stage. To see who is at a stage use find_contact with `stage`.

    contactstringrequired
    Who, as the user says it: a name ("the Laventi lead", "Maria"), an email, a phone, or "#123" with the id find_contact returned.
    stagestringrequired
    The new stage as the user says it: "New", "Contacted", "Nurturing", "Active", "Client", "Past client".
  • change_contact_type
    Contacts
    Writes data

    Swaps ONE contact type of a person for another, keeping the rest: "Ana is not a realtor, she is an accountant", "move John from borrower to past client", "make Maria a title company too" (only `to`), "she is no longer an attorney" (only `from`), "Laura is a listing agent, not a realtor" (Listing agent is its own type; a selling agent is a Realtor). It is what dragging a card between role columns of the contacts board does. To replace the whole list of types at once, or to change anything else about the person, use save_contact; to move the CRM stage use set_contact_stage.

    contactstringrequired
    Who, as the user says it: a name ("the Laventi lead", "Maria"), an email, a phone, or "#123" with the id find_contact returned.
    fromstring
    The type to take away, as the user says it ("realtor", "accountant"). Omit to only add `to`.
    tostring
    The type to put instead ("cpa", "title company"). Omit to only remove `from`.
  • save_contact
    Contacts
    Writes data

    Create a new contact or update an existing one. Use it when the user introduces someone new ("add Maria Torres, she's a realtor, 704-555-0142") or changes someone's details ("John has a new email"). Updates when given an id or when the email/phone matches an existing contact exactly; if the new person looks like a probable duplicate it does NOT create — it returns the candidates so you can confirm with the user and either update/merge them (merge_contacts) or retry with create_anyway. When provided, roles and tags REPLACE the existing lists — to remove one ("she is not the listing agent anymore", "drop the vip tag") send the list without it. NOTHING IS EVER ERASED BY LEAVING IT BLANK: empty strings and empty lists are ignored, and what you do not send stays as it was. To erase something the user asked you to erase ("he has no company", "remove her home phone"), name those fields in clear_fields. When someone works through an assistant ("her assistant is Dana, dana@titleco.com"), save assistant_name, assistant_email and assistant_phone: from then on every email sent to that contact is copied to the assistant by email, and every WhatsApp message by WhatsApp. SMS is never copied to an assistant.

    idinteger
    The contact id, when updating someone find_contact already returned.
    namestring
    Full name, when the person is named in one piece ("save Ana Alvarez"). It gets split into first and last name on its own. Required when creating, unless first_name or last_name are given instead.
    first_namestring
    First name on its own. Use it when the person spells the two parts apart, or to FIX a split that came out wrong ("her last name is Alvarez Acosta, not just Alvarez"). Wins over `name`.
    last_namestring
    Last name(s) on their own, both surnames together when there are two. Leave it out for a company, an HOA or a title agency: those are not people and have no surname. Wins over `name`.
    emailstring
    phonestring
    Any format; stored as E.164, US +1 assumed for 10 digits.
    rolesarray
    Contact types, e.g. ["realtor", "referral_source"]. Replaces the list. Listing and selling agents are saved as "realtor" (the side they play is a role on each loan, not a contact type).
    tagsarray
    Replaces the list.
    addressstring
    companystring
    nmls_licensestring
    preferred_languagestring
    referral_sourcestring
    Who or what referred them.
    notesstring
    Free-form background notes.
    work_phonestring
    Office line. Same format as phone; stored as E.164.
    home_phonestring
    Home line. Same format as phone; stored as E.164.
    phone_extensionstring
    Extension for the office line.
    occupationstring
    Job title (shown as "Job title"). E.g. "Senior Underwriter".
    birth_datestring
    ISO date (1985-04-12). Worth having: birthdays keep a rolodex warm.
    frequencyany
    How often to touch base with them. Empty string clears it.
    last_contactedstring
    ISO date of the last real conversation with them.
    assistant_namestring
    Who handles this person's calendar and inbox.
    assistant_emailstring
    The assistant gets a copy of every email sent to the contact.
    assistant_phonestring
    The assistant gets a copy of every WhatsApp message sent to the contact (SMS is never copied to an assistant). Same format as phone; stored as E.164.
    create_anywayboolean
    Set true ONLY after the user confirmed the probable duplicate is a different person.
    clear_fieldsarray
    The ONLY way to erase something. List here the fields the user asked to remove ("he left the company" -> ["company"]). Sending a field empty does nothing.
  • merge_contacts
    Contacts
    Writes data

    Merge two contacts that are the same person into one. Use it after save_contact or the import reported a probable duplicate and the user confirmed they are indeed the same, or when the user says "these two are the same person". Takes the two ids (find_contact gives them). The FIRST contact wins on conflicting fields; roles, tags and data are combined, and a non-null email/phone is never lost. Every role the absorbed contact had on a loan or pre-qual file moves to the survivor, so no file loses a participant. The second contact is then deleted. Never call it without the user confirming which two to merge.

    keep_idintegerrequired
    The contact that survives and wins on conflicts.
    merge_idintegerrequired
    The duplicate that gets absorbed and deleted.
  • review_contact_import
    Contacts
    Writes data

    FIRST step of importing contacts from a CSV (from another CRM, a phone export, a spreadsheet). Use it when the user pastes or uploads CSV data. It parses the text, auto-maps the columns by header name (pass mapping to correct it, e.g. {"Cell": "phone"}), normalizes every row, flags probable duplicates against the existing rolodex, and stages everything under a batch id WITHOUT touching the contact list. Show the user the summary and, once they confirm, run import_contacts with the batch id. Nothing is imported until then. To import from their connected Gmail or Outlook account instead, use review_email_contacts.

    csv_textstringrequired
    The raw CSV content, headers in the first row.
    mappingobject
    Column-to-field overrides, e.g. {"Cell Phone": "phone"}. Fields: name, first_name, last_name, email, phone, company, address, role, tags, notes, nmls_license, referral_source. Map a column to "skip" to ignore it.
  • review_email_contacts
    Contacts
    Writes data

    FIRST step of importing the user's contacts from their CONNECTED email account (Gmail or Outlook). Use it when the user asks to import or sync their contacts from their email, Google or Outlook. It reads the address book, normalizes every entry, flags probable duplicates against the existing rolodex, and stages everything under a batch id WITHOUT touching the contact list. Show the user the summary and, once they confirm, run import_contacts with the batch id. Needs the email connected first (connect_email); both providers include contacts in that same authorization.

    No parameters.

  • import_contacts
    Contacts
    Writes data

    SECOND step of a contact import (CSV or connected email account): executes a batch that review_contact_import or review_email_contacts staged, after the user confirmed the summary. Creates the clean rows, merges the exact duplicates (matching email/phone) into their existing contact — filling only what the existing contact is missing, never replacing a value it already has — and discards rows flagged for review. Pass treat_duplicates_as if the user decided differently for the flagged ones: "merge" folds them into their closest match, "create" imports them as new contacts anyway, "skip" leaves them out (the default for name-only matches). Pass overwrite ONLY when the user explicitly says the file should replace what is saved.

    batch_idstringrequired
    The batch id the review step returned.
    treat_duplicates_asstring
    Override for rows flagged as probable duplicates. Default: each row's suggestion.
    overwriteboolean
    When merging into an existing contact, let the imported row replace fields the contact already has, instead of only filling in what is missing. Default false. Set true ONLY when the user explicitly says the file should replace what is saved.
  • log_note
    Contacts
    Writes data

    Write a dated note on a contact's timeline. Use it whenever the user tells you something worth remembering about a person: "note that Maria prefers texts after 5pm", "log that I called John about his rate", or after a call/meeting they want recorded. The contact is whatever the user calls them — a name, email or phone fragment. Do NOT use it to change contact fields; that is save_contact.

    contactstringrequired
    Who, as the user says it: name, email or phone fragment.
    notestringrequired
    The note text.
    datestring
    When it happened (ISO date), only if different from today.
  • add_comment
    Pipeline
    Writes data

    Add a comment to the Notes & Comments thread of a loan, a pre-qual, a contact or a task. Use it when the user wants something written down on a record for the team to read later: "comment on the Garcia file that the appraisal came in low", "add a note to 412 Elm: seller wants to close in October", "leave a comment on Maria that she prefers texts", "comment on the appraisal task that the report is in review". Name the file the way the user does — borrower name, property address or loan number — the person by name, email or phone, or the task by words from its title. This does NOT change any field on the file: to update data use update_loan, to replace the file's single free-form Notes field use update_loan (notes) or save_contact (notes), and to change the task itself use save_task.

    filestring
    The loan or pre-qual, as the user says it: borrower name, address or loan number. Leave empty when commenting on a person.
    contactstring
    The person, as the user says it: name, email or phone fragment. Leave empty when commenting on a file.
    taskstring
    The task, as the user says it: its id or words from its title. Leave empty when commenting on a file or a person.
    commentstringrequired
    What to write in the thread.
  • read_comments
    Pipeline
    Read-only

    Reads the Notes & Comments thread of a loan, a pre-qual, a contact or a task: what the team wrote about it, newest first, with who wrote it and when. Use it when the user asks "what did we say about the Garcia file", "read me the comments on 412 Elm", "any notes on Maria", "comments on the appraisal task", or before answering a question about a record whose background lives in the thread. For the change history (stage moves, documents, syncs) use view_logs instead; for the file's single free-form Notes field, it comes back in find_loan / find_contact.

    filestring
    The loan or pre-qual, as the user says it: borrower name, address or loan number.
    contactstring
    The person, as the user says it: name, email or phone.
    taskstring
    The task, as the user says it: its id or words from its title.
    limitinteger
    How many comments. Default 20, newest first.
  • edit_comment
    Pipeline
    Writes data

    Rewrite a comment YOU wrote in the Notes & Comments thread of a loan, a pre-qual, a contact or a task. Use it when the user wants to fix or change a comment they already posted: "fix my comment on the Garcia file", "change that last comment to say the appraisal came in at 500K", "edit my note on Maria — it should say she prefers texts". You need the comment id: read_comments returns it for each line, so read the thread first if you do not have it. Only the author can edit a comment. This does NOT touch the file's single free-form Notes field (that is update_loan / save_contact with notes) nor any other field.

    filestring
    The loan or pre-qual the comment is on, as the user says it: borrower name, address or loan number. Leave empty for a person.
    contactstring
    The person the comment is on, as the user says it: name, email or phone fragment. Leave empty for a file.
    taskstring
    The task the comment is on, as the user says it: its id or words from its title. Leave empty for a file or a person.
    comment_idintegerrequired
    The id of the comment, as returned by read_comments.
    commentstringrequired
    The new text that replaces what the comment said.
  • delete_comment
    Pipeline
    Writes data

    Delete a comment YOU wrote from the Notes & Comments thread of a loan, a pre-qual, a contact or a task. Use it when the user wants one of their own comments gone: "delete my comment on the Garcia file", "remove that last comment I left on 412 Elm". You need the comment id: read_comments returns it for each line, so read the thread first if you do not have it, and confirm with the user which line goes when more than one could match. Only the author can delete a comment, and there is no undo. This does NOT delete the file or the contact (that is delete_loan / delete_contact) nor clear the Notes field.

    filestring
    The loan or pre-qual the comment is on, as the user says it: borrower name, address or loan number. Leave empty for a person.
    contactstring
    The person the comment is on, as the user says it: name, email or phone fragment. Leave empty for a file.
    taskstring
    The task the comment is on, as the user says it: its id or words from its title. Leave empty for a file or a person.
    comment_idintegerrequired
    The id of the comment, as returned by read_comments.
  • set_communication_preferences
    Contacts
    Writes data

    Turns email or SMS on or off for one person. Use it when someone asks not to be contacted on a channel ("don't email the Garcias", "Maria only wants texts"), or to undo it. Omitting a channel leaves it as it is. Note: a borrower who replies STOP to a text is opted out of SMS automatically and by law — do not turn that back on unless they ask. Turning SMS on lifts an opt-out. Texts go to every contact except who replied STOP: no consent or permission is needed (since 06/10/2026), so never ask the loan officer for it. `sms_permission` is still accepted and recorded, but it no longer changes who gets texts.

    contactostringrequired
    Who, as the user says it: name, email or phone fragment.
    emailboolean
    true = they accept email, false = do not email them.
    smsboolean
    true = lift an SMS opt-out, false = do not text them (same as STOP).
    sms_permissionstring
    No longer needed: texts go to everyone except who replied STOP. Kept for older callers: 'granted_by_loan_officer' / 'revoked' only record a note; it never lifts a STOP.
  • set_contact_language
    Contacts
    Writes data

    Sets the language a contact gets their messages in: English or Spanish. Use it whenever the user says someone prefers Spanish ("the Garcias speak Spanish", "write to Maria in Spanish", "send her everything in English from now on"). Every template, reminder and automatic update to that person switches to that language from the next send on; messages already queued keep the language they were written in.

    contactostringrequired
    Who, as the user says it: name, email or phone fragment.
    languagestringrequired
    'en' for English, 'es' for Spanish.
  • delete_contact
    Contacts
    Writes data

    Permanently deletes a person from the rolodex. Use it for duplicates or someone added by mistake. It refuses when the person is on a loan or pre-qual — merge them with merge_contacts instead. Ask the user to confirm before calling with confirmar: true.

    contactostringrequired
    Who, as the user says it: name, email or phone fragment.
    confirmarbooleanrequired
    Must be true to delete. Call with false first to check.
  • view_pipeline
    Pipeline
    Read-only

    Shows the pipeline: how many pre-quals and loans sit in each stage, the borrower and who the file is assigned to, how many days each has been in its current stage, and which ones are stalled (more than 7 days in an active stage). By default it counts ONLY OPEN files — exactly what the Loans and Pre-Q tabs show by default: active stages (loans Contract Received…Docs Signed, pre-quals No Status…Ready for Review), not archived. Then `nota` says what was left out (on hold, closed, archived…): mention it briefly, e.g. "plus 3 on hold". Use the default for "how does my pipeline look", "how many loans do I have", "what is stuck". Use `include` only when the user asks about files that are not open: on hold, closed/funded, cancelled, suspended, archived, or everything ("all", "including closed"). Always say which set you counted (`alcance`). For one specific file use find_loan; for the numbers of the month (closings, volume) use view_dashboard.

    tipostringrequired
    Which pipeline to show. Use 'both' unless the user asks only about pre-quals or only about loans.
    estadostring
    Only files in this stage, by its name as people say it ('clear to close', 'docs received'). A partial name covers every stage that contains it: 'processing' = Submitted to Processing + Resubmitted to Processing. Use it to answer "how many loans in X": the pipeline total is then the count for those stages only. If no stage matches, the error lists the real stage names. Leave out for the whole pipeline. A stage named here is honored even if it is not open ('on hold', 'loan funded'); 'closed', 'cancelled', 'suspended' and 'archived' mean the whole tab of that name.
    includearray
    Which set of files to count. Default ['open'] = the tab's default view. 'on_hold', 'closed' (Funded, Closed, Broker Check Received, Commission Paid), 'cancelled', 'suspended', 'looking_for_properties', 'credit_impaired', 'converted_to_loan' = that tab, not archived; 'archived' = everything archived; 'all' = everything. Combine them for "open and on hold": ['open', 'on_hold']. Leave it out unless the user asks for files that are not open.
  • show_pipeline_view
    Pipeline
    Read-only

    Opens or switches the Loans or the Pre-Q list to one of its views — the same selector the screen has: Open (the default: active stages, not archived), On Hold, Closed (Funded, Closed, Broker Check Received, Commission Paid), Cancelled, Suspended, Archived and All; Pre-Q also has Ready for Review, Looking for Properties, Credit Impaired and Converted to Loan. Use it when the person asks to SEE, OPEN, GO TO or SWITCH a list: "show me my closed loans", "open the pre-quals on hold", "take me to archived", "back to the open loans". It returns the link to that view and how many files it lists: give the number and let the person tap the button. For counts by stage, stalled files or pipeline analysis use view_pipeline; for one file use find_loan; to change columns, layout or sorting use adjust_view.

    pipelinestringrequired
    Which list, as the person says it: "loans", or "pre-quals" ("pre-q", "prequals", "pre-qualifications" also work).
    viewstringrequired
    Which view, as the person says it: "open", "on hold", "closed", "cancelled", "suspended", "archived", "all"; on pre-quals also "ready for review", "looking for properties", "credit impaired", "converted". Use "open" when they just want the list.
  • find_loan
    Pipeline
    Read-only

    Finds ONE loan or pre-qual and returns its full file: stage, amounts, property, borrowers, every other participant (realtor, title company…), the financial items collected so far, and the dated milestones. Use it whenever the user asks about a specific file — "how is the Garcia loan going", "what do we have on 412 Elm St", "show me loan 1002941". Accepts a borrower name, a property address, or a loan number. By name it prefers OPEN files (what the Loans/Pre-Q tabs show by default); if only a non-open one matches (on hold, closed, cancelled, suspended) it still returns it with a `nota` saying so — tell the user. To ask for a non-open one on purpose, say it in the phrase: "the closed Garcia loan", "Garcia on hold". Archived files only resolve by their id.

    prestamostringrequired
    The file, as the user says it: borrower name, property address, or loan number
  • create_prequal
    Pipeline
    Writes data

    Creates a new pre-qualification for a borrower and puts it in the pipeline at "To Be Contacted". Use it when a new lead comes in: "add a pre-qual for Maria Garcia", "new lead: John Smith, 555-0142". If the borrower is not a contact yet, pass their email or phone and the contact is created too. It also takes co-borrowers (up to 3 besides the main borrower: "a pre-qual for the Hassans, Ali and Noor"), priority, notes and who referred the lead. To move an existing file forward use move_stage, not this; to add a co-borrower to a file that already exists use assign_loan_contact.

    borrowerstringrequired
    The borrower, as the user says it: a name, an email, or a phone
    first_namestringnull
    First name on its own, for a NEW borrower — use it whenever you can tell the two parts apart ("Ana Maria Alvarez Acosta" -> "Ana Maria"). Null if the borrower already exists or you only have the phrase.
    last_namestringnull
    Last name(s) on their own, both surnames together when there are two. Leave it null for a trust, an LLC or a company: those have no surname.
    emailanyrequired
    Email for a NEW contact. Null if the borrower already exists or no email was given.
    telefonostringnullrequired
    Phone for a NEW contact. Null if the borrower already exists or no phone was given.
    co_borrowersanyrequired
    The other borrowers on the file — a spouse, a partner. Up to 3 besides the main one. Null if there is only one borrower.
    prioridadanyrequired
    How hot the lead is, if the user said it. Null otherwise.
    notasstringnullrequired
    Notes about the lead, if the user gave any. Null otherwise.
    referralstringnullrequired
    Who referred the lead, as the user says it (an existing contact). Null if not mentioned.
  • prequal_form
    Pipeline
    Read-only

    Opens an interactive pre-qualification form right in the chat, pre-filled with whatever the user already said. Use it when the user wants to create a pre-qual but has not given the details yet ("I want to create a pre-qual", "new lead"), or asks for a form. If they already gave borrower plus phone or email, call create_prequal directly instead — do not make them fill a form they already dictated.

    nombrestringnullrequired
    The borrower's full name, if the user said it in one piece. Null otherwise, or when you already split it into first_name/last_name.
    first_namestringnullrequired
    The borrower's first name on its own, whenever you can tell the two parts apart. Null otherwise.
    last_namestringnullrequired
    The borrower's last name(s), both surnames together when there are two. Null otherwise.
    emailstringnullrequired
    The borrower's email, if given. Null otherwise.
    telefonostringnullrequired
    The borrower's phone, if given. Null otherwise.
    prioridadanyrequired
    Priority, if the user said it. Null otherwise.
    notasstringnullrequired
    Notes about the lead, if any. Null otherwise.
  • create_loan
    Pipeline
    Writes data

    Creates a loan directly in the pipeline, without going through a pre-qualification. Use it when a deal arrives already under contract: "create a loan for Robert Miller", "new loan: the Hassans, contract received". Takes up to 4 borrowers (the first is the main one), the initial status (defaults to Contract Received), notes, and the selling agent, listing agent or referral. If the borrower is not a contact yet, pass their email or phone and the contact is created too. To turn an existing pre-qual into a loan use convert_to_loan, not this.

    borrowerstringrequired
    The main borrower, as the user says it: a name, an email, or a phone
    first_namestringnull
    First name on its own, for a NEW borrower — use it whenever you can tell the two parts apart ("Ana Maria Alvarez Acosta" -> "Ana Maria"). Null if the borrower already exists or you only have the phrase.
    last_namestringnull
    Last name(s) on their own, both surnames together when there are two. Leave it null for a trust, an LLC or a company: those have no surname.
    emailanyrequired
    Email for a NEW contact. Null if the borrower already exists or no email was given.
    telefonostringnullrequired
    Phone for a NEW contact. Null if the borrower already exists or no phone was given.
    co_borrowersanyrequired
    Co-borrowers, as the user says them (existing contacts). Null if none.
    estadostringnullrequired
    Initial loan status value if the user said one (e.g. "contract_received", "qualification"). Null for the default (Contract Received).
    notasstringnullrequired
    Notes about the loan, if the user gave any. Null otherwise.
    selling_agentstringnullrequired
    The selling agent, as the user says it (an existing contact). Null if not mentioned.
    listing_agentstringnullrequired
    The listing agent, as the user says it (an existing contact). Null if not mentioned.
    referralstringnullrequired
    Who referred the deal, as the user says it (an existing contact). Null if not mentioned.
  • loan_form
    Pipeline
    Read-only

    Opens an interactive loan creation form right in the chat, pre-filled with whatever the user already said. Use it when the user wants to create a loan but has not given the details yet ("I want to create a loan", "new loan"), or asks for a form. If they already gave the borrower plus phone or email, call create_loan directly instead — do not make them fill a form they already dictated.

    nombrestringnullrequired
    The borrower's full name, if the user said it in one piece. Null otherwise, or when you already split it into first_name/last_name.
    first_namestringnullrequired
    The borrower's first name on its own, whenever you can tell the two parts apart. Null otherwise.
    last_namestringnullrequired
    The borrower's last name(s), both surnames together when there are two. Null otherwise.
    emailstringnullrequired
    The borrower's email, if given. Null otherwise.
    telefonostringnullrequired
    The borrower's phone, if given. Null otherwise.
    estadostringnullrequired
    Initial loan status value, if the user said one. Null otherwise.
    notasstringnullrequired
    Notes about the loan, if any. Null otherwise.
  • contact_form
    contactos
    Read-only

    Opens an interactive new-contact form right in the chat, pre-filled with whatever the user already said. Use it when the user wants to add a contact but has not given the details yet ("add a new realtor", "I met someone new"), or asks for a form. If they already dictated name plus email or phone, call save_contact directly instead.

    nombrestringnullrequired
    The contact's full name, if said in one piece. Null otherwise, or when you already split it into first_name/last_name.
    first_namestringnullrequired
    The contact's first name on its own, whenever you can tell the two parts apart. Null otherwise.
    last_namestringnullrequired
    The contact's last name(s), both surnames together when there are two. Null for a company, an HOA or a title agency.
    emailstringnullrequired
    Email, if given. Null otherwise.
    telefonostringnullrequired
    Phone, if given. Null otherwise.
    rolstringnullrequired
    Their role slug if the user said it (e.g. 'borrower', 'listing_agent', 'referral_source'). Null otherwise.
    empresastringnullrequired
    Company, if given. Null otherwise.
    notasstringnullrequired
    Notes, if any. Null otherwise.
  • check_duplicates
    contactos
    Read-only

    Checks whether a person is already in the rolodex before creating them, and says WHY each match looks like the same person (same email, same phone, similar name) with a 0-1 score. Use it when the user is about to add someone and you want to avoid a second copy, when they ask "do I already have X?", or before create_prequal / create_loan with a brand-new borrower. To create despite the matches, call save_contact with create_anyway.

    nombrestringrequired
    The name to check. Required.
    emailstringnullrequired
    Email, if known. Null otherwise.
    telefonostringnullrequired
    Phone, if known. Null otherwise.
    solo_probablesbooleanrequired
    When true, only matches at or above 0.8 (almost certainly the same person). When false, also returns weaker name matches worth a look.
  • task_form
    tareas
    Read-only

    Opens an interactive new-task form right in the chat, pre-filled with whatever the user already said. Use it when the user wants to add a task but has not given the details yet ("add a task", "remind me of something"), or asks for a form. If they already dictated the task ("remind me to call Maria tomorrow"), call save_task directly instead.

    titulostringnullrequired
    The task title, if already said. Null otherwise.
    vencestringnullrequired
    Due date in YYYY-MM-DD, if said. Null otherwise.
    descripcionstringnullrequired
    Longer detail, if any. Null otherwise.
    prestamostringnullrequired
    The loan or borrower this task is about, as the user says it. Null otherwise.
    asignadostringnullrequired
    Who it is for, if said: a teammate name or email, or "me". Null otherwise.
    seccionstringnullrequired
    Which section of the task list it goes into, if said. Null otherwise.
  • check_missing_data
    Pipeline
    Read-only

    Shows what DATA is still missing on a file — not documents, but facts: FICO score, income on file, purchase price, loan program, closing date… — for the current stage and the next one, with who owes each (borrower, loan officer, realtor, lender, title). Use it for "what is missing on the Garcia file?", "is this file ready to move?", "what do I need before review?". For missing DOCUMENTS use check_documents.

    loanstringrequired
    The file, as the user says it: borrower name, address, or number
  • move_stage
    Pipeline
    Writes data

    Moves one or several loans or pre-quals to another pipeline stage and stamps the milestone date. Use it whenever the user reports progress: "the Garcia docs came in" → docs_received, "submitted Elm St to underwriting" → submitted_to_underwriting, "put it on hold", or a batch at once (pass them in prestamos) — with several it moves as many as it can and reports which ones failed, one by one. Some transitions notify the borrower or the realtor automatically: with preview=true it only answers WHAT would be sent, without moving anything — use that when the user asks "what happens if…". With skip_notifications=true it moves silently (e.g. correcting a mistake). The valid stages depend on whether the file is a pre-qual or a loan; if unsure, view_pipeline lists them. To turn a pre-qual into a loan use convert_to_loan instead.

    prestamostring
    The file, as the user says it: borrower name, property address, or loan number. For several files use prestamos instead.
    prestamosarray
    Several files at once, each one as the user says it. They all move to the same stage.
    estadostringrequired
    The target stage, in snake_case: 'docs_received', 'clear_to_close'…
    previewboolean
    true = do NOT move; only report which notifications the move would send. For "what would happen if…" questions.
    skip_notificationsboolean
    true = move without notifying anyone. For silent corrections.
    forceboolean
    true = advance EVEN IF documents or UW conditions are still owed. Only when the user explicitly says to move it anyway.
  • convert_to_loan
    Pipeline
    Writes data

    Converts a pre-qualification into an active loan, starting it at "Contract Received". Use it when a pre-qual borrower goes under contract: "Garcia got the house!", "we have a contract on Elm St", "convert Maria to a loan". Only works on pre-quals; an active loan moves with move_stage.

    prestamostringrequired
    The pre-qual, as the user says it: borrower name, address, or number
  • update_loan
    Pipeline
    Writes data

    Updates fields on a loan or pre-qual: amount, closing date, tags, file data (address, program, transaction type — purchase or refinance — and what kind of refinance, purchase price, down payment, FICO, DTI, rates and lock terms, appraisal status/value, income verification, notes…) or a milestone date (disclosures, lock, appraisal, title, insurance, credit, contract, closing). Use it when the user gives new facts about a file: "the Garcia loan is for $420k", "the Smith file is a cash-out refi", "rate locked at 6.5 until Sep 15", "appraisal came in at $510k", "closing moved to October 3", "tag it VIP". Only pass what changed. To change the pipeline stage use move_stage instead.

    prestamostringrequired
    The file, as the user says it: borrower name, address, or number
    montoanyrequired
    New loan amount in USD. Null if unchanged.
    fecha_cierreanyrequired
    New closing date: ISO (YYYY-MM-DD) or "today"/"tomorrow"/"yesterday". Null if unchanged.
    etiquetasanyrequired
    The FULL new list of tags (replaces). Null if unchanged.
    datosanyrequired
    File data to merge in. Property: property_address, property_type, property_usage, property_value, structure_type, appraisal_status, appraisal_value, number_of_units, title_under_a_corporation, corporate_name. Loan: loan_number (broker), loan_number_lender, program, transaction_type, refinance_type, fico_score, purchase_price, down_payment, down_payment_percentage, loan_amount_2, loan_to_value, combined_loan_to_value, dti, amortization_type, amortization_term_months, interest_only, income_verification, waive_escrows, lender_program, prepayment_penalty_term/type. Rates: rate, note_rate, interest_rate_locked, interest_rate_disclosed, interest_rate_buydown, interest_rate_cost, lock_cost, rate_cost_credit, credit_to_borrower, interest_rate_cost_credit_percent, rate_lock_extension_cost, rate_locked_type, lock_expires. Also compensation_pct, priority, notes, and notas_secciones — a map of short per-section notes (borrower, credit, property, income, assets): pass only the sections to change, an empty string clears that note. WHAT THE DEAL IS, in two separate fields: transaction_type is "Purchase" or "Refinance" — set it whenever the user says what kind of deal it is ("this one is a refi", "she is buying"). refinance_type is "Rate & Term", "Limited Cash-out" or "Cash-out", and ONLY applies when transaction_type is Refinance — if the user says "cash-out refi", set both. Never write the old "purpose" field: it is legacy and no longer shown anywhere. DOWN PAYMENT: pass whichever one the user said — down_payment in USD or down_payment_percentage — and the server fills the other from the purchase price. Pass both only if the user dictated both. Null if unchanged.
    fechasanyrequired
    Milestone dates to set by name, like {"appraisal_received": "2026-09-01"} or {"cd_sent": "today"} — each value is an ISO date or "today"/"tomorrow"/"yesterday", resolved on the server. Valid names are pipeline stages — which is also how you CORRECT the day a file entered a stage without moving it again: contract_received, loan_setup, loan_disclosed, disclosures_signed, preparing_to_submit_to_uw, submitted_to_processing, submitted_to_underwriting, approved_with_conditions, resubmitted_to_processing, submitted_for_clear_to_close, clear_to_close, docs_out, docs_signed, on_hold, loan_closed, loan_cancelled, loan_archived, loan_suspended, loan_funded, commission_paid — and named milestones — disclosures: initial_disclosures_sent, intent_to_proceed, le_sent, le_signed, le_received, revised_le_sent, revised_le_signed, cd_requested, cd_sent, cd_signed, revised_cd_sent, revised_cd_signed; lock: lock_date, lock_extension, lock_expiration; appraisal: appraisal_ordered, appraisal_received; title: title_ordered, title_received; insurance: hoi_ordered, hoi_received; credit: credit_ordered, credit_expiration, tax_transcript_ordered, tax_transcript_received; processing: processing, submitted_to_clear_conditions; contract: sales_contract_date, appraisal_contingency, loan_contingency, closing_contingency, earliest_closing; closing: estimated_funding, first_payment, date_to_avoid_epo, pre_approval_expiry, underwriting_approval. A custom date this file already has (its key starts with custom_) also works here; to create, rename or remove one use set_custom_date. Null if unchanged.
    clear_fieldsarray
    The ONLY way to erase something. List the fields the user asked to remove or leave blank ("take the priority off" -> ["priority"], "we do not have a closing date yet" -> ["fecha_cierre"]): any file data name from datos, "monto", "fecha_cierre", "etiquetas", or a milestone name from fechas. Sending a field empty does nothing.
  • set_custom_date
    Pipeline
    Writes data

    Creates, renames, dates or removes a date the loan file needs but the standard milestone catalog does not have. Use it when the user names a deadline that is not one of the built-in milestones: "add an HOA docs due date of Sep 15 to the Garcia file", "rename that date to Attorney Review", "drop the HOA docs date". For a milestone that already exists in the catalog (appraisal, lock, CD, closing…) use update_loan instead. To move a custom date that already exists, either tool works.

    prestamostringrequired
    The file, as the user says it: borrower name, address, or number
    nombrestringrequired
    What the date is called, as the user says it ("HOA docs due"). For an existing custom date, words from its name are enough.
    fechaany
    The date itself: ISO (YYYY-MM-DD) or "today"/"tomorrow"/"yesterday". Null to create or rename without dating it yet.
    renombrarany
    The new name, when the user is renaming an existing one.
    quitarbooleannull
    True to remove the custom date from the file entirely.
  • update_loan_items
    Pipeline
    Writes data

    Records or removes financial items and properties on a loan file: jobs (W2, 1099, VOE), other income (P&L, child support, IRS transcripts), bank accounts, retirement accounts, gift funds, asset depletion, liabilities (incl. IRS or government payment plans, child support payments), and real estate. Use it whenever the loan officer mentions a borrower's income, assets, debts, or properties — e.g. "she works at Amazon, W2, $85k" or "they have a checking account at Chase". For a property, proposed_status in datos says if it is retained, pending sale, or sold with this loan. datos also holds the fields each type uses: company (W2, 1099, self-employed), bank_name / account_name / account_number (bank statements), ownership_percentage (business). When adding an income item you can also pass documentos — the exact documents to request for it, per year ("the W-2s for 2025 and 2024") or covering a date range ("statements from January to March") — and each becomes a checklist row tied to the item. The rest of the document checklist regenerates automatically from these items.

    prestamostringrequired
    The file, as the user says it: borrower name, address, or number
    agregaranyrequired
    Items to add. Null if only removing.
    editaranyrequired
    Corrections to items already on file — a mistyped amount, the employer that was missing. Null if not correcting anything. ALWAYS prefer this over removing and re-adding: removing an item takes its documents with it.
    quitaranyrequired
    Item ids to remove (find_loan lists them). Null if only adding.
  • archive_loan
    Pipeline
    Writes data

    Archives one or several loans or pre-quals, or brings archived ones back into the pipeline. Modellus already hides files with no activity for 39 days — use this to disagree with that in either direction: "bring the Garcia loan back", "unarchive 412 Elm", "this one is still alive", "archive the Miller file, it is dead", or a whole batch at once (pass them in prestamos). With several it archives as many as it can and reports which ones failed, one by one. Your choice sticks: the automatic rule will not undo it. This is NOT how you close a loan — to record that a loan closed or was cancelled use move_stage.

    prestamostring
    The file, as the user says it: borrower name, property address, or loan number. For several files use prestamos instead.
    prestamosarray
    Several files at once, each one as the user says it. Use it when they clear out a batch ("archive all of these").
    archivarbooleanrequired
    True takes them out of the pipeline, false brings them back.
  • assign_loan_contact
    Pipeline
    Writes data

    Adds or removes a participant on a loan or pre-qual by role: borrowers and co-borrowers (up to 4, ordered), realtor, listing agent, title company, appraiser, insurance company, account executive, HOA office, developer, or the file's alt contact — the extra person to call about it, with no particular role. Use it when the user connects people to a file: "the realtor on Elm St is Susan Chen", "add Carlos as co-borrower on the Garcia loan", "the second number on 412 Elm is his daughter", "remove the appraiser from 412 Elm". The person is usually already a contact; if they are not, pass their email or phone and the contact is created and attached in one go.

    prestamostringrequired
    The file, as the user says it: borrower name, address, or number
    contactostringrequired
    The person, as the user says it: name, email, or phone. A contact id also works — it is what the pipeline cells send to remove exactly who was there, with no name ambiguity.
    rolstringrequired
    Their role on this file, in snake_case: 'borrower', 'co_borrower', 'realtor', 'title_company', 'appraiser'…
    accionstringrequired
    'add' to attach the person, 'remove' to detach them
    first_namestringnull
    First name on its own, when adding someone who is not in the rolodex yet — use it whenever you can tell the two parts apart ("Ana Maria Alvarez Acosta" -> "Ana Maria"). Null otherwise.
    last_namestringnull
    Last name(s) on their own, both surnames together when there are two. Leave it null for a title company, an HOA or a bank: those have no surname.
    emailstringnull
    Email for a NEW contact, when adding someone who is not in the rolodex yet. Null if they already exist or none was given.
    telefonostringnull
    Phone for a NEW contact, when adding someone who is not in the rolodex yet. Null if they already exist or none was given.
  • assign_loan
    Pipeline
    Writes data

    Assigns one or several loans or pre-quals to someone on the team — who owns the file and shows in the Assigned To column. Use it when the user hands files over: "give the Garcia loan to Ana", "assign 412 Elm to me", "take Ana off the Miller file" (pass asignado: null to leave it unassigned), "put all of these under Ana" (pass them in prestamos). With several files it does as many as it can and reports which ones failed, one by one. To attach a realtor, title company or any outside party use assign_loan_contact instead — that is about contacts, this is about your own team.

    prestamostring
    The file, as the user says it: borrower name, property address, or loan number. For several files use prestamos instead.
    prestamosarray
    Several files at once, each one as the user says it. Use it when they hand over a batch ("all of these go to Ana").
    asignadostringnullrequired
    Who takes it: a teammate name, their email, or "me". Null leaves the files unassigned.
  • update_conditions
    Pipeline
    Writes data

    Manages the underwriting conditions of a loan: lists them, adds new ones, or changes one — its status, who has to get it (one person or several), or its internal note. Use it when the loan comes back approved with conditions ("UW wants 2023 tax returns and a gift letter"), when one was asked for and the ball is on the other side (estado 'solicitado', Requested), when what it asked for comes in or the underwriter signs off on it ("VOE approved", "gift letter is in" — estado 'recibido', Received, which closes it), when it does not apply (estado 'no_aplica', N/A), or when the user reassigns one ("that one is on the realtor and the title company"). Sending one back is not a status of its own: put it back to 'pendiente' or 'solicitado' and say why in the note. A condition uses the SAME four-step scale as paperwork. To just read the conditions without changing anything, use view_conditions instead. A condition is NAMED by a short plain-English title (what the borrower reads in the portal and in emails, at most 70 characters); pass 'titulos' when adding and the bank wording is kept apart on its own (the internal note stays for the team). Conditions added from here are marked as written by AI so the team reviews them. Every condition added without a usable title gets one written automatically. To change a title later use rename_document. Marking one received stamps the day on its own, and if the condition asks for one of the six the office orders from third parties (title work, appraisal, HOA docs, HOI, payoff, LLC docs) it also shows up as received there — no need to mark it twice. Every condition belongs to one category — the same sections as the loan summary: Borrower, Income, Subject property, Title, Credit, Assets or Other — and the file lists them split that way: pass 'categoria' when adding ("add a property condition: HOA budget and bylaws") or with 'resolve' to move one ("that one goes under Title").

    prestamostringrequired
    The loan, as the user says it: borrower name, address, or number. Keep the words "loan" or "pre-qual" if the user said them — they pick the right file when the borrower has both.
    accionstringrequired
    'list' to see the conditions, 'add' to create new ones, 'resolve' to change the status of one
    condicionesanyrequired
    For 'add': the text of each new condition — ALL of them in this one call when the user lists several ("add these: VOE, 2 months of bank statements, gift letter"); they go in on top of the list in the order given. Null otherwise.
    condicionstringnullrequired
    For 'resolve': which condition, by a few words of its text. Null otherwise.
    condicion_idany
    For 'resolve', ONLY when the caller pointed at one exact row — the screen does, by its id. Never guess it: in conversation say which condition in 'condicion', with a few words of its text.
    asignadostringnull
    Who has to get it — a name, or a role like 'the borrower', 'the processor'. With 'add' it applies to every condition in the batch; with 'resolve' it reassigns that one. Empty string clears it. For more than one person, use 'asignados' instead.
    asignadosany
    Everyone who has to get it, when it is more than one person (names or roles, e.g. ["Maria", "the title company"]). Replaces the whole list; an empty array unassigns everyone. Overrides 'asignado' when both come.
    categoriaany
    Which section the condition goes under — the SAME sections as the loan summary: 'property', 'title', 'borrower', 'income', 'assets', 'credit', 'other'. With 'add' it applies to every condition in the batch (pick it from what the condition is about — ID, citizenship or a letter of explanation → 'borrower'; pay stubs, W-2s, tax returns or a VOE → 'income'; appraisal, insurance, HOA docs or the home itself → 'property'; title commitment, survey or payoff → 'title'; a credit inquiry or a disputed tradeline → 'credit'; bank statements, gift letters or reserves → 'assets'; anything else → 'other'); with 'resolve' it moves that one without touching its status. Null or omitted leaves it as is.
    estadoanyrequired
    For 'resolve': the new status, the same scale as paperwork. 'pendiente' = on the list, nobody asked yet; 'solicitado' = requested, waiting on them; 'recibido' = it came in, it no longer blocks the close; 'no_aplica' = N/A. Defaults to 'recibido' when null, because the usual reason to resolve one is that it came in.
    notasany
    Internal team notes on the condition — the borrower never sees them. Use it when the user adds context ("waiting on the CPA", "underwriter said a screenshot works"). With 'add' it applies to every condition in the batch; with 'resolve' it sets or replaces the note on that one without touching its status (unless a status is also passed). Empty string removes the note.
    titulosany
    For 'add': the short plain-English TITLE of each new condition (what document to bring, at most 70 characters — "Last 2 months of bank statements, all pages"), aligned one-to-one with 'condiciones'. The title becomes its name; the text in 'condiciones' (the bank wording) is kept apart as the original condition text, not in the team note. Plain everyday words, no codes (write "letter explaining…", not "LOE"; "homeowners insurance", not "HOI"), no <> or [ ] blanks. Comes from read_approval_conditions. Null entries, and titles with codes or blanks, get a title written automatically.
    texto_borrowerany
    Old name, kept for compatibility: with 'resolve', a non-empty value becomes the title of that condition (prefer rename_document). Leave it out.
    textos_borrowerany
    Old name of 'titulos', kept for compatibility. Leave it out.
    documento_origenstring
    For 'add': the name of the approval document these conditions were read from ("Approval_Miller.pdf"), so the file history says where they came from. Pass it when they came out of read_approval_conditions.
    redactar_borrowerbooleannull
    For 'add': leave it out. It only exists so the screens can save a condition instantly: they pass false and the short title is written in the background instead of before answering. From the chat you want the default (null).
  • view_conditions
    Pipeline
    Read-only

    Reads the underwriting conditions of a loan without changing anything: each condition with its status, its category (the same sections as the loan summary: Borrower, Income, Subject property, Title, Credit, Assets or Other), who has to get it, the borrower-facing wording, the internal notes, and the day it came in. Use it whenever the user asks what conditions are open or pending on a file ("what are the pending conditions for the Villegas loan?"), what is still missing from underwriting to get to clear to close, who a condition is assigned to, or whether something already came in. A condition uses the same scale as paperwork: pending and requested are open, received and N/A are closed. When listing conditions to the team, name each one by its titulo_en_lista (the short note the team wrote, e.g. "Trace ALL Emds", which is how their screen shows it); use texto only for what goes to the borrower. notas is the team note on each one (its own line under the title on their screen; the borrower never sees it). To add conditions or change one — including adding, changing or removing its note — use update_conditions ('resolve' with notas).

    prestamostringrequired
    The loan, as the user says it: borrower name, address, or number. Keep the words "loan" or "pre-qual" if the user said them — they pick the right file when the borrower has both.
  • resend_status
    Pipeline
    Writes data

    Re-sends the status messages the file already earned, without moving it. Use it when a borrower or realtor says they never got the update, or lost the link: "resend the status to Maria", "send the link again". It sends exactly what that stage sends — to write something different use send_message.

    prestamostringrequired
    The file, as the user says it: borrower, address or number.
  • view_logs
    Pipeline
    Read-only

    Shows the change history of one loan, pre-qual or contact: what changed, when, and what triggered it. Use it when the user asks "what happened with the Garcia file", "when did this move to underwriting", "history for Maria", "view logs". It also says why a text, email or document request did NOT go out (entries "envio_bloqueado"): use it for "why didn't the text to Carlos send?". Name the record the way the user does — borrower name, address, loan number, person name.

    prestamostring
    The loan or pre-qual, as the user says it.
    contactostring
    The person, as the user says it.
    limiteinteger
    How many entries. Default 50.
  • delete_loan
    Pipeline
    Writes data

    Permanently deletes a loan or pre-qualification and everything hanging off it: participants, documents, financial items and history. Use it ONLY for a file created by mistake or a duplicate. A file that did not close is NOT deleted — move it to Cancelled or Archived with move_stage so its history survives. Ask the user to confirm before calling with confirmar: true.

    prestamostringrequired
    The file, as the user says it: borrower, address or number.
    confirmarbooleanrequired
    Must be true to delete. Call it first with false to see what would be lost, show that to the user, and only then call with true.
  • view_arive_loans
    Arive
    Read-only

    Lists loans that live in Arive, the external loan origination system where the team builds the lender package. Use it when the user asks what is in Arive, wants to search Arive by borrower name, email, phone or loan number, or wants to compare Arive against the files tracked here. Read-only: nothing in Modellus can change Arive. For files tracked in Modellus use view_pipeline or find_loan instead. For the full detail of one Arive loan use view_arive_loan.

    searchstring
    Borrower name, email, phone, or Arive loan number to search for. Leave out to list the most recently updated loans.
    limitinteger
    How many loans to return. Default 20.
  • view_arive_loan
    Arive
    Read-only

    Shows the full file of ONE loan as it stands in Arive, the external loan origination system: status, amounts, rate and lock, key dates, borrowers, loan team and business contacts (title, escrow…), plus the direct link to open it in Arive. Use it when the user asks how a specific loan looks in Arive, for a rate/lock/key-date that only Arive has, or to compare an Arive file against the one tracked here. Accepts a borrower name or an Arive loan number. Read-only: to change anything, the team edits it in Arive itself.

    loanstringrequired
    The loan, as the user says it: a borrower name or an Arive loan number.
  • connect_arive
    Arive
    Writes data

    Connects this account to Arive, the external loan origination system, using API credentials from Arive (client id, secret key and API key). Use it when the user pastes their Arive API credentials, asks to connect or reconnect Arive, or when an Arive action failed because Arive is not connected yet. It validates the credentials live against Arive before saving, so wrong keys never get stored. Never repeat the credentials back in chat.

    client_idstringrequired
    The client id of the Arive API client.
    secret_keystringrequired
    The secret key of the Arive API client.
    api_keystringrequired
    The API key of the Arive API client.
  • set_arive_cutoff
    Arive
    Writes data

    Sets (or clears) the Arive cutoff date: loans CREATED in Arive before this date are never brought into Modellus, so a migration from the old system does not get duplicated by the sync. Loans already here keep being refreshed no matter how old they are. Use it when the user asks to only bring loans from a date onward, to change or remove that date, or when import_arive_loans reported older loans left out and they want them in from now on. Pass an empty string to remove the cutoff entirely (everything in Arive becomes importable). view_integrations shows the date currently in effect.

    created_afterstringrequired
    The cutoff date as YYYY-MM-DD: only loans Arive created after it get imported. An empty string removes the cutoff.
  • sync_arive_now
    Arive
    Writes data

    Runs the Arive sync for this account right now instead of waiting for the next automatic run, and reports what moved. Use it when the user says a loan changed in Arive and does not show here yet, asks to refresh, resync or "pull the latest from Arive", or right after reconnecting or fixing the connection, to confirm data is flowing again. It is safe to run as often as needed: it only pulls what Arive changed since the last run and never duplicates a file. Anything arriving for the first time lands in the New Client inbox, not straight in the pipeline. If the connection had been lost, this restores it from the saved copy and says so. To only check whether the connection works without pulling anything, use check_integration; to see how it is doing without touching it, view_integrations.

    fullboolean
    true = ignore the watermark and re-read everything Arive has, not just what changed since the last run. Slower; use it only when data looks wrong and a normal sync did not fix it.
  • set_arive_live
    Arive
    Writes data

    Turns Arive live updates on or off. With them on, a change made in Arive shows up here within seconds instead of waiting for the sync that runs every 15 minutes (that sync keeps running either way, as a safety net). Use it when the user says Arive changes take too long to appear, asks for real-time or instant sync, or wants to stop the live updates. Pass action "status" to just report whether they are on.

    actionstringrequired
    Turn live updates on, off, or just report the current state.
  • import_arive_loans
    Arive
    Writes data

    Imports the active/pending loans from Arive into the Modellus pipeline: creates each loan with its borrowers AND everyone on the file — listing/selling agent, title, insurance, attorney, HOA, appraiser and the rest of the business contacts, plus the processor and loan officer assistant — each linked to the loan with their role and deduplicated against existing contacts (existing contact data is never overwritten), along with mapped stage, amounts, key dates and the link back to Arive. Closed, cancelled, funded and archived loans stay in Arive. Safe to run again: a loan already imported is refreshed (stage, data, dates, and any contacts still missing are added — never removed), never duplicated. Use it when the user asks to bring, sync or import their Arive loans or pipeline into Modellus. ALWAYS run it first with preview=true and show the user what would be imported; only run with preview=false after they confirm. Requires Arive to be connected on this account (connect_arive). What it brings in for the first time lands in the New Client inbox waiting to be reviewed (view_new_clients / review_new_client), not straight into the pipeline. By default it only brings what Arive created AFTER the account cutoff date; older_than_cutoff in the result says how many were left out, so tell the user "there are N older ones, want them too?" and re-run with include_older=true if they say yes (set_arive_cutoff changes the date for good).

    previewbooleanrequired
    true = only count and list what would be imported, writing NOTHING. false = actually import. Always preview first.
    limitinteger
    Import at most this many loans (most recently updated first). Leave out to import all active/pending loans.
    include_olderboolean
    By default only loans Arive created AFTER the account cutoff date come in — that is what keeps a migration from the old system from being duplicated. true also brings the older ones. Only when the user asks for them on purpose.
  • connect_loan_to_arive
    Arive
    Writes data

    Links a file in Modellus to its file in Arive, so the automatic sync starts keeping it up to date. Use it when the user says a loan or pre-qual "is not updating from Arive", "is not connected to Arive", "stopped syncing", "still shows the old stage", or when another Arive action failed because the file did not come from Arive. Most of these are older files that came over from the previous system and never got matched. If that Arive loan is already connected to a different file in Modellus, this MOVES the connection here and tells you which file it came from — say so before the user confirms. Takes the file as the user names it (borrower or address) and the Arive loan number the user reads off the Arive URL. ALWAYS call it first with confirm: false: it answers whose Arive file that number is, and you must show that name and address to the user and get a yes before calling again with confirm: true. Linking the wrong number pours somebody else's loan data into this file. To pull an already linked file right now use resync_loan; to bring in files that are not in Modellus at all use import_arive_loans.

    prestamostringrequired
    The file, as the user says it: borrower name, property address, or loan number.
    arive_loan_idintegerrequired
    The Arive loan number, the one the user reads in the Arive URL or on the Arive file itself.
    confirmbooleanrequired
    Must be true to link. Call it first with false to see whose Arive file that number is, show the borrower and address to the user, and only call again with true once they confirm it is the same person.
  • disconnect_loan_arive
    Arive
    Writes data

    Disconnects a file in Modellus from its Arive loan, so the automatic sync (the 15-minute cron and the webhooks) stops touching it. Use it when the user wants to "stop syncing this file with Arive", "disconnect from Arive", or says a file "is linked to the wrong Arive loan" — disconnect it first with this, then use connect_loan_to_arive to link the right number. What already came from Arive (amounts, dates, notes) stays on the file; only the connection itself is removed. Takes the file as the user names it: borrower, address, or loan number.

    prestamostringrequired
    The file, as the user says it: borrower name, property address, or loan number.
  • resync_loan
    Pipeline
    Writes data

    Pulls ONE loan from Arive right now and applies what changed, instead of waiting for the sync that runs every 15 minutes. Use it when the user says something was just changed on the Arive side and they want it here: "refresh the Garcia loan from Arive", "the processor just updated 412 Elm, pull it", "this one looks out of date". Hand-edited fields are kept unless Arive changed that same field. To bring in loans that are not in Modellus yet, use import_arive_loans instead.

    prestamostringrequired
    The file, as the user says it: borrower name, property address, or loan number
  • view_new_clients
    Arive
    Read-only

    Lists the New Client inbox: loans that came in from Arive and nobody has reviewed yet — each one still has to be accepted as a loan, accepted as a pre-qualification, or ignored. Use it when the user asks what came in from Arive, what is waiting for review, what is in the New Client list, or how many new clients are pending. Pass `query` to look for one of them by borrower, email, phone, address or loan number. Each row brings the borrower with their email, phone and property, the Arive id and link, and how many files that person already has here. To act on one of them use review_new_client. For the files already being worked use view_pipeline instead.

    showstring
    'pending' (default) = waiting for review. 'ignored' = the Arive loans the team told Modellus to stop importing; use it when they ask what was ignored or want one back.
    querystring
    Narrows the inbox to the rows that mention this: borrower name, email, phone, property address or loan number. Use it when they ask something like "did anything come in for the Millers" or "is that Oak Street file in the new client list".
    limitinteger
    How many rows to return. Default 50.
  • review_new_client
    Arive
    Writes data

    Decides what happens with one loan sitting in the New Client inbox (the ones imported from Arive that nobody has reviewed). Use it when the user says to accept, take, keep, convert or ignore something that came in from Arive: "keep the Garcia one as a loan", "that one is just a pre-qual", "ignore the 412 Elm file". decision=loan keeps it as an active loan, decision=prequal turns it into a pre-qualification, and decision=ignore DELETES it here and stops future imports from bringing it back — always confirm with the user before ignoring. decision=restore undoes an ignore (pass the Arive id) so the next import brings that loan again. List what is waiting with view_new_clients.

    loanstringrequired
    Which one, as the user says it: borrower name, property address or Arive number. For decision=restore it must be the Arive id of the ignored loan (view_new_clients with show=ignored lists them).
    decisionstringrequired
    'loan' = accept it as an active loan. 'prequal' = accept it as a pre-qualification. 'ignore' = delete it here and never import it again. 'restore' = un-ignore an Arive id.
  • check_documents
    Documents
    Read-only

    Shows the document checklist. With a loan (a phrase like "the Martinez loan" or an address), it lists every document grouped by status and by who owes it. Without a loan, it gives a cross-pipeline report of every loan with something still outstanding and how many days it has been waiting. Use it whenever the user asks what is missing, what came in, or what is stuck. PAPERWORK and UNDERWRITING CONDITIONS are counted separately but with the same rule: outstanding while pending or requested, done once received (or N/A). A file is only clean when both are at zero.

    loanstring
    The loan, as the user says it ("the Martinez loan", "123 Main St"). Leave empty for the cross-pipeline report.
  • request_documents
    Documents
    Writes data

    Prepares the document request for a loan: refreshes the checklist, groups what is missing by who owes it (borrower, realtor, title company, HOA, and whoever each underwriting condition is assigned to), creates a secure upload portal link for each party, and queues a message (by email, and by text to everyone who owes something — borrower, realtor, title company, HOA, insurance… — never to anyone who replied STOP; no consent or permission is needed) that says what we already received from them and what is still needed. The email asks them to reply with the documents attached (no upload link, so it does not land in spam); the text carries the upload link. Use it when the user wants to chase, collect or request the missing documents of a loan, or to follow up on what was already requested ("remind them", "follow up in two days", "nudge the realtor next week" — pass follow_up). By default every assigned person gets only their own items; pass `solo` to send just some documents. The messages go out within a minute (or on the scheduled day for a delayed follow-up), each email 20–45 s after the previous one so a batch never leaves all at once; the response says exactly what was queued to whom. `template` picks which request template to use (the stock "Documents still pending" or one of the account’s own, by key or by name — "the friendly one") and `subject` names this request: it becomes the email subject. `channels` picks how it goes out and takes SEVERAL at once: ["email","whatsapp"] sends by email and WhatsApp but not SMS ("email and WhatsApp only", "no texts on this one"). Default is email plus SMS to everyone who owes something. If WhatsApp is not connected yet the request still goes by the others and the response says so. `reminder_every_days` sets how often this request keeps nagging: 3 means every 3 business days, 0 means send it once and never repeat ("remind them every week", "just send it once"); omit to use the account cadence. `send_in` schedules the whole request for later ("send it in two days"). Sending it for real moves the paperwork it asked for to "requested" and stamps the day, and stamps the last-reminder day on what was already requested — the preview changes nothing. It is THE way to send someone their pending underwriting conditions or missing documents ("send a text to Carlos with his pending conditions"): it writes the real open list, one per line with "- ". Always call it first WITHOUT confirmar (also when the user orders the send): the preview carries the email draft and the text draft of each person, drawn on screen; one yes sends it. `recipients` limits who gets it, as the user says it ("only the realtor", "just Maria") — people outside it are skipped and listed in `omitidos`. Whenever the user names a person or a role ("send it to Carlos", "ask the title company", "email the borrower"), ALWAYS pass `recipients` with exactly them: they get only the items they are responsible for (the borrower gets the borrower’s own) and nobody else gets anything. Omit `recipients` only when the user asks to chase everyone. Never ask the loan officer for SMS permission: texts go to everyone except who replied STOP.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    soloarray
    Document ids to ask for, when only some of what is missing goes out. Omit to ask for everything that is missing.
    sectionstring
    A whole section of the checklist, as the user says it: "income", "subject property", "title", "borrower", "credit", "assets". Use it for "ask them for everything missing under income". Combines with `solo`: both sets go out together. "conditions" (or "underwriting conditions") picks every open underwriting condition — use it for "send him his pending conditions".
    all_assignedboolean
    Kept for compatibility; it no longer changes anything. Every assignee of a document always gets it in their own message, with or without `solo`.
    follow_upstring
    Follow up on what was ALREADY requested (status 'solicitado'): 'now' queues the reminder right away, 'in_2_days' and 'in_1_week' schedule it. Only requested items go out; pending ones that were never asked for are left alone. Stamps the last-reminder day on each item. OMIT it for a new or first request ("ask for", "request", "send them the missing docs") — only pass it when the user says remind / follow up / nudge. If nothing was requested yet it is ignored and the first request is prepared; `modo: 'request'` also overrides it.
    modostring
    'request' is the first ask; 'reminder' is the nudge for what was already asked (same as follow_up: now). Default is request. Usually omit it; 'request' wins over follow_up.
    channelsarray
    Which channels this request goes out by — SEVERAL at once. ["email","whatsapp"] sends by email and WhatsApp and NOT by SMS; ["sms"] only texts; texts reach everyone who owes something (never anyone who replied STOP). Omit for the usual email plus SMS. Use it whenever the user names the ways it should go ("email and WhatsApp", "text only", "no emails on this one").
    channelstring
    The single-channel form, kept for older callers; prefer `channels`. 'all' sends by email plus text to everyone who owes something; 'email', 'sms' or 'whatsapp' send by that one only. Ignored when `channels` is given.
    reminder_every_daysinteger
    How often this request keeps reminding, in BUSINESS days: 3 = every 3 business days, 7 = weekly, 0 = send it once and never repeat. Use it when the user says "remind them every week", "chase this one every other day", "just send it once, no reminders". OMIT it unless the user said how often (or said no reminders): omitted keeps the account-wide cadence (view_doc_tracking shows it). Never pass 0 by default.
    send_instring
    When the request goes out: 'now' (default), 'in_2_days' or 'in_1_week'. Unlike follow_up, this schedules the WHOLE request, pending items included. Use it when the user says "send it in two days" / "ask them next week".
    templatestring
    Which document-request template to use, as the user says it: its key ("docs_request_friendly_reminder") or its name, even loosely ("the friendly one", "last call"). Omit for the stock "Documents still pending". view_templates lists the "Document requests" family; edit_template creates new ones.
    subjectstring
    Only for the Request modal on screen (the person typing it). From the assistant it is ignored: the email keeps the template subject, exactly like the Request button. Omit it.
    bodystring
    Only for the Request modal on screen; from the assistant it is IGNORED — the message is always the template with the real list, like the Request button. Omit it. (Screen use: the email body for this one send, replacing the template’s.) Keep the {{variables}} — {{borrower_name}}, {{missing_docs}} — so each recipient gets their own list; the preview’s `variables` lists every one it fills. Emails never carry the upload link (it reads as phishing to spam filters): they ask the person to reply with the documents attached, and any {{portal_link}} line is swapped for that on send. Texts keep the link. Omit to use the template as it is. Use edit_template instead when the change should stick for every future request.
    recipientsarray
    Who gets this request, as the user says it: names or roles of people on the loan ("Maria Lopez", "the realtor", "title company"). Only those among the people who owe the selected items get a message; the rest is skipped and listed in `omitidos`. Whenever the user names someone ("send it to Carlos", "the title company"), pass them here so ONLY their items go out. Omit only when they ask for everyone who owes something.
    confirmarboolean
    false (or omitted) previews what WOULD go out to whom — always the first call. true sends it, after the user said yes to the preview you showed in your previous turn.
    sms_permission_confirmedboolean
    No longer needed (06/10/2026): texts go to everyone except who replied STOP. Accepted and ignored so older calls keep working; do not ask for it.
  • review_document
    Documents
    Writes data

    Returns a document, flags it as incomplete, or approves it. Identify it by document id, or by loan plus document type ("return the bank statement on the Martinez loan"). Use 'incomplete' when what arrived is right but partial (only page 1 of 4 came through) — it asks for the missing piece instead of the whole document again; use 'return' when it is the wrong or unusable document. Both REQUIRE a reason: the person who has to fix it sees it in their portal and gets it by email (one email per person the document is assigned to, the borrower if nobody is), so write it for them, never with internal notes. The document ends up Returned or Incomplete; approving leaves it Approved and takes optional notes. Use it whenever the user says a document has to be sent again, is missing something, or is good. If the user did not say why it is being returned, ask before calling. To say a document is still pending, requested or received, use update_document.

    document_idinteger
    The document id, when it is already known (e.g. from check_documents).
    loanstring
    The loan, as the user says it. Needed when there is no document_id.
    document_typestring
    The document type, e.g. "w2", "bank_statement_personal", "paystub".
    decisionstringrequired
    'approve' (good to go), 'return' (wrong or unusable — send it again) or 'incomplete' (right but partial). 'reject' and 'missing_information' are the old names of 'return' and 'incomplete' — never pick them.
    reasonstring
    Why it is returned, or exactly what is missing — written for the person who has to fix it: they read it in their portal and in the email. Required for return and incomplete.
    notesstring
    Only when approving: what to leave written on the file about this document ("accepted without the stamp, spoke to the bank").
  • update_document
    Documents
    Writes data

    Sets what is expected of one document on a loan: the period it has to cover ("bank statements from January to March", "the 2024 tax return"), a note for whoever provides it, and where it stands on the scale a piece of paperwork moves through: requested (asked for — the ball is on their side), pending (on the list, nobody has asked for it), received (it came in and is in our hands), approved (reviewed and good to go — where a paper stops), returned (wrong or unusable, they have to send it again) or incomplete (partial, they have to send what is missing) — those two REQUIRE `reason`, which the person sees in their portal and gets by email — plus not_applicable to take it off this file. It is ALSO how you change WHO the document is asked from ("ask the realtor for the HOA questionnaire on this one", "the insurance binder goes to the insurance agent, not the borrower") — there is no rule per document type, the loan officer decides case by case, and the request messages follow whoever is set here. Any document can be asked from SEVERAL people at once: pass `assignees` with all of them ("ask Maria and the title company for the payoff") and each one gets it in their own request. Use it when the user says "the statements should be Jan through Mar", "I already have the W-2, mark it in" (received), "the W-2 is good, approve it" (approved), "I just chased him for the paystub" (requested), "we do not need the survey here" (not_applicable), or "ask Maria for that one instead". If the document is not on the loan’s checklist yet it gets added, so you can set a status on any document type without a second step. Every status change stamps its own date — you only pass status_date when the user names a different day. This is for PAPERWORK: an underwriting condition runs on a different scale (received does NOT close one) and goes through update_conditions. To approve a file that came in, or send it back to be redone, use review_document (returned / incomplete here do exactly the same). A condition can also be reassigned here the same way; its other fields (note, category, adding) stay in update_conditions. For the six the office orders from third parties (title work, appraisal, HOA docs, HOI, payoff, LLC docs) order_docs says it in one word and covers the whole package.

    document_idinteger
    The document id, when known (e.g. from check_documents).
    loanstring
    The loan, as the user says it. Needed when there is no document_id.
    document_typestring
    The document type, e.g. "bank_statement_personal", "w2".
    period_fromstring
    First day the document has to cover (ISO date). Empty string clears it.
    period_tostring
    Last day the document has to cover (ISO date). Empty string clears it.
    notestring
    What to tell whoever provides it. Empty string clears it.
    wordingstring
    No longer used: what the person reads is the document NAME. To change how it reads, rename it with rename_document. Leave it out.
    team_notestring
    An internal note for your team about this document ("waiting on the CPA, called twice"). Only the team sees it — never the borrower or the portal. Empty string clears it.
    request_fromstring
    Who this document is asked from, when it is ONE person, as the user says it: a name ("Maria", "Robert") or a role on this file ("the realtor", "title company", "the HOA"). They have to already be a participant on the loan. An empty string puts it back on the borrower. Same as `assignees` with a single entry; for more than one person use `assignees`. The same document goes to different people on different files — never assume from the document type.
    assigneesarray
    EVERYONE this document is asked from, as the user says them: names or roles on this file (["Maria Lopez", "the realtor", "borrower"]). Replaces the whole list; each one gets the document in their own request message. An empty array puts a paper back on the borrower and leaves a condition unassigned. Every entry has to be someone already on the loan. Overrides `request_from` when both come.
    statusstring
    Where the document stands. Pick by whose court the ball is in: 'pending' when it is on the list but nobody has asked for it yet (also the way to undo a request the user says never went out); 'requested' the moment it is asked for or chased — the ball is on their side and the wait starts counting from that day; 'received' when it is in our hands, typically paperwork that came in outside the portal ("I already have the W-2"); 'approved' when it was looked at and is good — the end of the line for a paper (review_document does the same and also records the verdict on the uploaded version); 'returned' when it is wrong or unusable and has to be sent again, 'incomplete' when it is right but partial — both need `reason` and email it to whoever the document is assigned to; 'not_applicable' takes it off this file without erasing its history; 'archived' keeps it but out of the active list (archive_document / restore_document do the same by name). ('follow_up' is the old name of 'requested' — never pick it, it is only accepted so older integrations keep working.)
    reasonstring
    Required with status 'returned' or 'incomplete': why it goes back, written for the person who has to fix it — they read it in their portal and in the email. If the user did not say why, ask first.
    status_datestring
    The day the status change happened (ISO date), when it was NOT today: "I ordered the appraisal on Monday", "the payoff came in on the 3rd". Leave it out and the date is stamped on its own — never ask the user for it.
    due_datestring
    The deadline for this document (ISO date), when the user sets one: "the HOA docs are due Friday", "we need the payoff by the 25th", "push the W-2 deadline to next week". Empty string clears it. It is only a date on the list — setting it does not request anything.
  • update_documents
    Documents
    Writes data

    Changes the responsible person, the due date and/or the status of SEVERAL documents on one loan in a single step. Use it whenever the user talks about more than one document at once: "put all the income documents on the processor", "the subject property docs are due Friday", "mark the W-2, the paystubs and the bank statements as received", "everything in loan documents is not applicable here". Pick the documents by `section` (a whole section of the checklist: borrower, income, subject property, title, credit, assets, other documents, underwriting conditions), by `documents` (their names, as the user says them) or by `document_ids` (from check_documents) — they can be combined and the union is updated. A section never includes what is already not applicable. Only the fields you pass change; the rest stays as it was. For ONE document, or to set a period, a note or the wording, use update_document. This does not send anything: to ask people for the documents use request_documents.

    loanstringrequired
    The loan, as the user says it: a borrower name, a property address or a loan number.
    document_idsarray
    Document ids on that loan, when known (e.g. from check_documents).
    documentsstring
    The documents by name, as the user says them: "the W-2, the paystubs and the bank statements".
    sectionstring
    A whole section of the checklist, as the user says it: "income", "subject property", "other documents", "borrower", "title", "credit", "assets", "underwriting conditions".
    assigneesarray
    EVERYONE responsible for these documents, as the user says them: names or roles on this file, or people on your team (["Maria Lopez", "the realtor"]). Replaces the whole list on every document. An empty array puts papers back on the borrower and leaves conditions unassigned. Leave it out to keep who has them.
    due_datestring
    The deadline for all of them (ISO date, e.g. 2026-09-25). Empty string clears it. Leave it out to keep each one as it is.
    statusstring
    Where they all stand now: 'requested' (asked for — the ball is on their side), 'pending' (on the list, nobody asked yet), 'received' (in our hands), 'approved' (looked at and good), or 'not_applicable' (off this file, history kept), or 'archived' (kept, out of the active list; archive_document says it by name).
    status_datestring
    The day the status change happened (ISO date), only when the user names a day other than today. Never ask for it.
  • set_document_reminder
    Documents
    Writes data

    Sets how often the borrower (or whoever has them) gets reminded about one or several documents or underwriting conditions on a loan. Use it when the user says things like "remind them about the payoff every 2 days", "no reminders for the title documents", "put the income docs back on the default reminder". Pick the documents by `section`, by `documents` (names as the user says them) or by `document_ids` (from check_documents); they combine. `every_business_days`: a number of business days (1-30), 0 for no reminder, or null to go back to the account's default. This does not send anything now: to send a reminder right away use request_documents.

    loanstringrequired
    The loan, as the user says it: a borrower name, a property address or a loan number.
    document_idsarray
    Document ids on that loan (e.g. from check_documents).
    documentsstring
    The documents by name, as the user says them.
    sectionstring
    A whole section of the checklist: "income", "subject property", "title", "credit", "assets", "borrower", "underwriting conditions"…
    every_business_daysanyrequired
    Business days between reminders. 0 = no reminder. null = the account default.
  • rename_document
    Documents
    Writes data

    Changes what one line of a loan file is called — a document on the checklist or an underwriting condition. Use it when the user wants to fix or reword the name itself: a typo, a condition the approval reader garbled, or a letter of explanation that has to say what it is about ("change that letter of explanation to say it is about the 2023 late payments", "rename that condition to..."). For a condition this rewrites its title — the short plain-English summary the borrower reads in the portal and in emails (keep it under ~70 characters; the bank's full wording stays in the internal note). For a checklist document it rewrites what tells two of the same type apart — the document TYPE and its rules do not change, so this will not turn a W-2 into a paystub; to add or remove lines use adjust_checklist and delete_document.

    documentstringrequired
    Which line, as it reads today: its id, or the words it shows on the list.
    namestringrequired
    What it should say from now on.
    loanstringnull
    The loan it is on, as the user says it: borrower name, address, or number. Pass it whenever the user named a file — without it the search runs across every file.
  • add_sub_document
    Documents
    Writes data

    Adds a sub-document under a document or underwriting condition of a loan file — for when one line is really several things to collect separately ("split the bank statements into March and April", "the HOA condition needs the budget and the bylaws as two pieces"). The new one hangs under its parent on the list, is asked from the same people, starts Pending, and from then on is its own document: its own status, file and request, and its own line in the portal. Call it once per piece. Deleting the parent deletes its sub-documents.

    documentstringrequired
    The parent document or condition, as it reads on the list (a few words of its name or title), or its id.
    loanstringnull
    The loan it is on, as the user says it: borrower name, address, or number. Pass it whenever the user named a file.
    nameany
    What the new sub-document is called ("March statement"). Leave it out for "<parent> — part 2".
  • delete_document
    Documents
    Writes data

    Permanently removes ONE line from a loan file — a document from the checklist or an underwriting condition, they work the same way. Use it ONLY for something that should never have been on the file: a duplicate, a typo, a condition the approval reader split in two, a document added by mistake ("delete that second W-2", "that condition is duplicated, remove it", "I typed this one wrong"). Something that IS on the file but is not needed on THIS loan is NOT deleted — that is a decision worth keeping, so use remove_from_summary (N/A); to keep it but out of sight, archive_document. Deleting also throws away its history and any file uploaded against it. Call it first with confirmar: false to see exactly which line it would remove, show that to the user, and only call with confirmar: true once they say yes.

    documentstringrequired
    Which line: its id, or the words it shows on the list — the name of the document ("Survey", "Letter of Explanation — the gap") or a few words of the condition text.
    loanstringnull
    The loan it is on, as the user says it: borrower name, address, or number. Pass it whenever the user named a file — without it the search runs across every file and a common name comes back as "which one?".
    confirmarbooleanrequired
    Must be true to delete. Call it first with false to see which line it would be, show that to the user, and only then call with true.
  • open_page
    Account
    Read-only

    Opens a screen of the app for the user: a section by name ("take me to settings", "go to tasks", "open integrations", "show me the calendar", "ajustes", "configuración"), a loan or pre-qual with one of its tabs ("open the loan summary of Carlos Barreto", "open the documents tab of the Garcia loan"), or a contact's card ("open Ana Lopez"). Use it whenever the user asks to GO somewhere, open, show or navigate to a screen — not to answer a question about data (for that, use find_loan, find_contact, etc.; the screen follows on its own). It returns the route and the app opens it right away; just confirm in a few words ("Opening Settings"). Screens: dashboard, contacts, pre-q, loans, inbox, tasks, calendar, templates, document templates, marketing, tools, pricing, loan finder, production report, new client, assistant chat, settings (profile, company, messages, connections/integrations), team, closing costs. Loan tabs: summary (conditions live there), pricing, loan finder, documents, tasks, inbox, portals.

    pagestring
    The screen as the user says it: "settings", "integrations", "tasks", "the calendar", "ajustes". Leave it empty when opening a loan or a contact.
    loanstring
    A loan or pre-qual as the user says it: borrower name, address or loan number ("Carlos Barreto", "412 Elm", "this loan").
    contactstring
    A contact as the user says it: name, email or phone.
    tabstring
    The tab to land on, if they named one: for a loan summary, pricing, loan finder, documents, tasks, inbox or portals; for settings profile, company, messages or connections.
  • order_docs
    Documents
    Writes data

    The "Docs Ordered" board of a loan: the paperwork the office orders from third parties — Title Work, Appraisal, HOA Docs, HOI, Payoff, LLC Docs, Vesting. Unlike the rest of the checklist, nobody chases these from the borrower: they are ordered from title, the appraiser, the HOA or the insurance agent, and what matters is WHAT DAY they went out, so someone can call when they take too long. Use it when the user says "I ordered the appraisal", "title work is out", "the appraiser confirmed for Thursday", "HOA docs came back today", "payoff received", "did we order HOI on the Miller file?", or "what is still not ordered". Four steps: not_ordered → requested (it went out) → pending (the third party confirmed, it is on its way) → received. Ordering stamps the date on its own — only pass status_date when they name a different day ("I ordered it Monday"). Leave `document` out to see the whole board. HOA Docs and LLC Docs are packages: one word covers every paper in them. For any other document type use update_document, and for underwriting conditions use update_conditions — a condition that asks for one of these seven already shows up here as received on its own.

    loanstringrequired
    The loan, as the user says it: borrower name, address, or number.
    documentstring
    Which one, as the user says it: "title work", "appraisal", "HOA docs", "HOI", "payoff", "LLC docs", "vesting". Leave it out to just see the board.
    statusstring
    'requested' means it went out and we are waiting; 'pending' means the third party confirmed and it is on its way (the appraiser scheduled the inspection, title is working on it) — no need to chase yet; 'received' means it came in; 'not_ordered' undoes everything — use it when they say they had not actually ordered it. Leave it out to only read. ('ordered' is the old name of 'requested' — never pick it, it is only accepted so older integrations keep working.)
    status_datestring
    The day it happened (ISO date), when it was NOT today: "I ordered it Monday", "the payoff came in on the 3rd". Leave it out and the date is stamped on its own — never ask the user for it.
  • send_initial_requests
    Documents
    Writes data

    Sends the initial third-party requests of a loan — the HOI quote request, the title request and the HOA certs request — each by email to its own parties on the loan (HOI: broker and insurance agent; Title: broker, title company, processor and selling agent; HOA: broker, processor and HOA management). Use it when the user says "request HOI, title and HOA for the Garcia loan", "send the title request", "order the initial docs", "what is the status of the initial requests", or asks who those emails would go to. HOA certs normally apply only to condo/PUD properties (or a loan with HOA dues): "request all" skips them otherwise, but if the user names HOA explicitly it is sent anyway. Every third-party recipient gets their own private upload link in the email (no login; it only uploads that request's documents) — con_enlace says who. To get one of those links to share yourself (copy and paste), use create_initial_upload_link. If the broker already sent one on their own, use mark_initial_request instead of sending it again. IMPORTANT: two-step action — call it first WITHOUT confirm to get each draft, its recipients and the current status, show that to the user, and only when they approve call it again with confirm=true.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    requestsarray
    Which ones: "hoi", "title", "hoa". Leave it out for all that apply and have not been requested yet ("request all"). A request named here is sent even if it does not apply to the property (e.g. HOA certs on a non-condo) — only name it when the user asked for it.
    editsarray
    Only when the user changed an email before sending ("change the title email to say…", "send the HOI to quotes@agency.com and cc Ana", "subject: …"): the new subject, body, To and/or CC for THIS send. Subject and body are template text that may keep {{variables}} ({{borrower_name}}, {{property_address}}…). Pass the same edits on the draft call and on the confirm call. The saved template is not changed. **bold** and lines starting with "- " are kept as bold and bullets.
    confirmboolean
    true = the user already saw and approved the drafts: send them. Never set it on the first call.
  • create_initial_upload_link
    Documents
    Writes data

    Creates a private upload link for ONE recipient of an initial request (HOI, title or HOA certs) of a loan, for the user to share themselves (copy and paste). Modellus sends nothing with it. The link needs no login and only lets that person upload the documents of that request — it shows no loan amounts, no other documents and cannot download anything. Use it when the user says "give me the upload link for the title company on the Garcia loan", "copy the HOI upload link for the insurance agent", or wants to send that link outside email. The broker (our office) never gets one. Valid 30 days. With revoke=true it does the opposite: turns off every active upload link that recipient has for that request (the emailed one and any copied one) — use it when the user says "kill / revoke / turn off the title upload link for Maria" or a link was sent to the wrong person.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    requeststringrequired
    Which request: "hoi", "title" or "hoa".
    recipientstringrequired
    Who, as the user says it: their name, email or role ("the title company", "State Farm agent", "maria@title.com").
    revokeboolean
    true = revoke that recipient's active upload links for this request instead of creating one. Only when the user asked.
  • regenerate_company_logo
    Account
    Writes data

    Cleans up the company logo and makes its two versions: one with a transparent background and no margins for light screens (and emails), and one for dark mode with the dark text turned white, keeping the brand colors. Use it when the user says "my logo looks bad in dark mode", "the logo has a white box around it", "remove the logo background", "the logo is too small / has too much margin", "regenerate my logo", or gives a new logo link to use ("use this logo: https://…"). Without image_url it works again from the original file they uploaded. Takes up to a minute. To only remove the logo, use update_profile with company_logo_url null.

    image_urlstring
    A new logo to use, as an https link to a PNG, JPG or WEBP. Leave it out to regenerate from the logo they already uploaded.
  • mark_initial_requests
    Documents
    Writes data

    Marks the status of SEVERAL initial third-party requests of a loan (HOI, title, HOA certs) at once, WITHOUT sending any email. Use it when the user talks about more than one: "the broker already ordered HOI and title on the Lopez file", "mark all the initial requests as requested", "undo all of them, nothing went out". Leave `requests` out to mark all three. For one of them use mark_initial_request; to actually send the emails use send_initial_requests.

    loanstringrequired
    The loan, as the user says it ("the Lopez loan", "12 Oak Ave").
    requestsarray
    Which ones: "hoi", "title", "hoa". Leave out for all three.
    statusstringrequired
    'requested_by_broker' = the broker sent them on their own; 'requested' = they went out some other way from the office; 'not_requested' = undo, nobody has requested them.
  • delete_documents
    Documents
    Writes data

    Permanently removes SEVERAL lines from one loan file at once — documents from the checklist and/or underwriting conditions. Use it when the user wants a batch gone because it should never have been on the file: "the approval was read twice, delete all the conditions and I will import it again", "remove those three duplicated W-2s". Pick them by `document_ids` (from check_documents or view_conditions) or with `all_conditions: true` for every underwriting condition of the loan. Something that is on the file but not needed on THIS loan is NOT deleted — use remove_from_summary (N/A) or archive_document. For one line use delete_document. Call it first with confirmar: false to see the exact list, show it to the user, and only call with confirmar: true once they say yes.

    loanstringrequired
    The loan, as the user says it: borrower name, property address or loan number.
    document_idsarray
    Ids of the documents or conditions on that loan.
    all_conditionsboolean
    True to include every underwriting condition of the loan. Can be combined with document_ids.
    confirmarbooleanrequired
    Must be true to delete. Call it first with false to see the list, show it to the user, and only then call with true.
  • view_condo_questionnaires
    Documents
    Read-only

    Lists the account's condo questionnaires: the questions sent to a condo building's HOA or management company before financing a unit (units, owner-occupancy, delinquencies, litigation, master insurance…). Use it when the user asks "what do we ask the HOA?", "show me the condo questionnaire", or before adding, removing or rewording a question. An account that never saved one sees the standard Fannie Mae limited-review questionnaire.

    buscarstring
    Filter by name or a word in the questions ("rocket", "insurance").
  • save_condo_questionnaire
    Documents
    Writes data

    Creates or edits a condo questionnaire (the questions sent to the HOA or management company of a condo building). Use it when the user says "add a question about short-term rentals to the condo questionnaire", "make a Rocket condo questionnaire with …", "send it to the management company instead", "rename it". To add or remove one question, first read the current list with view_condo_questionnaires and send the full resulting list. A questionnaire with the same name is updated; otherwise a new one is created.

    nombrestringrequired
    Questionnaire name as the user says it ("Condo questionnaire").
    destinatariostring
    Who usually fills it: hoa or management_company_building. Omit to keep it.
    preguntasarray
    The FULL list of questions, in order; replaces the list. Omit to keep it. Required for a new one.
    nuevo_nombrestring
    Only to rename it.
  • delete_condo_questionnaire
    Documents
    Writes data

    Deletes one of the account's condo questionnaires. Use it when the user says "delete the Rocket condo questionnaire" or "remove that questionnaire". To remove a single question, use save_condo_questionnaire instead.

    nombrestringrequired
    Questionnaire name as the user says it.
  • view_mailbox
    Communication
    Read-only

    Lists the user's real email inbox (their connected Gmail or Outlook), newest conversations first, 20 per page, with search. Use it when the user asks "what's in my inbox", "any new emails", "did the title company write", "find the email from Laventi about the appraisal". `q` searches like the mail app does (sender, subject, words). To open a conversation use read_email_thread with its id; to answer it, reply_email_thread. This is the whole personal mailbox as the mail app shows it — for what Modellus already has filed (emails, texts and WhatsApp, grouped by email thread and by loan file) use view_inbox.

    qstring
    Search words, e.g. "from:laventi appraisal". Leave out for the inbox.
    mailboxstring
    Which connected mailbox to read, when there are two. Default: the default one.
    pagestring
    The next_page value from a previous call, to see older conversations.
  • read_email_thread
    Communication
    Read-only

    Opens one email conversation from the user's connected mailbox and returns every message in it — sender, recipients, date, full text — and its attachments with a download link. Use it after view_mailbox when the user wants to read an email ("open the one from the appraiser", "what did she say?") or before replying, so the reply answers what was actually written. To answer it use reply_email_thread.

    thread_idstringrequired
    The thread_id from view_mailbox.
    mailboxstring
    The mailbox it lives in, when it is not the default one.
    include_htmlboolean
    Only for screens that render the email as it was sent. NEVER pass it when reading to reason or to answer: the raw HTML of a corporate thread is tens of thousands of tokens and says nothing that text does not.
  • reply_email_thread
    Communication
    Writes data

    Replies to an email conversation from the user's connected mailbox, inside the same thread (the recipient sees it as a reply, not a new email). IMPORTANT: two steps, like send_message — call it first WITHOUT confirm to get the draft (who it goes to, subject, text), show it and ask for approval, then call again with confirm=true. Use it when the user says "reply to her that…", "answer the title company", "tell him yes". Read the thread first with read_email_thread so the reply fits. By default it answers the last person who wrote; reply_all adds everyone else in copy. It can attach loan documents (ids from check_documents). Test mode applies.

    thread_idstringrequired
    The thread_id from view_mailbox.
    bodystringrequired
    The reply text. The previous message is quoted below it.
    mailboxstring
    The mailbox the thread lives in, when it is not the default one.
    reply_allboolean
    Also copy everyone else in the thread.
    ccstring
    Extra addresses in copy, comma-separated.
    attachmentsarray
    Loan document ids to attach (check_documents).
    confirmboolean
    false/omitted returns the draft; true sends it.
  • send_email
    Communication
    Writes data

    Writes a brand-new email to any address(es) from the user's connected mailbox — choosing which one with `from` when they have two ("send it from my work email"). IMPORTANT: draft first, one yes — call it WITHOUT confirm (also when the user orders the send) to get the draft; on their yes call again with confirm=true. Use it for "email the title company…", "write to john@… that…" when it is not a reply (for replies use reply_email_thread so it stays in the thread). NEVER for pending conditions or missing documents ("email Carlos his pending conditions"): that is request_documents, the same template and list as the Request button. To message a contact with a template, by SMS or WhatsApp, use send_message. It is ALSO the way to send a loan's documents/files to anyone — a participant of the loan, the title company, an appraiser or any address ("email the W-2 and the bank statements to escrow@…"): put the document ids from check_documents in `attachments`; the email is logged on that loan's history. Prefer it over send_document when the recipient is a raw address or several people at once. Files over 20 MB go as a download link. Test mode applies.

    tostringrequired
    Recipient address(es), comma-separated.
    subjectstringrequired
    The subject line.
    bodystringrequired
    The email text, as the user dictated it. Any list (items, dates, steps) goes ONE item per line starting with "- ", never in a sentence. Never use it to ask for pending conditions or missing documents: that is request_documents.
    ccstring
    Addresses in copy, comma-separated.
    fromstring
    Which connected mailbox it leaves from. It has to be one of YOUR own (view_connected_mailboxes says which). Leave it out for the default one.
    attachmentsarray
    Loan document ids to attach (check_documents).
    loanstring
    The loan this email is about, as the user says it (borrower name, property address or loan number), so it shows in that loan's history even without attachments. With attachments it is implied.
    confirmboolean
    false/omitted returns the draft (always the first call); true sends it, after the user said yes to that draft.
  • set_default_mailbox
    Account
    Writes data

    Chooses which connected mailbox is the default one: every email the app sends (reminders, requests, automations, anything that does not pick a sender) leaves from it. Use it when the user has two mailboxes connected and says "send from my work email by default", "use german@… as the main one". Only the account owner can change it, and it does NOT change where replies go out from: an answer always leaves from the mailbox the original email arrived at. To see the mailboxes use view_connected_mailboxes; to send one single email from another one, pass `from` to send_email instead.

    addressstringrequired
    The connected address that becomes the default.
  • set_contacts_mailbox
    Account
    Writes data

    Chooses which connected Google account syncs the contacts, when it is not the same one email goes out from. Use it when the user says "my contacts live in the other account", "sync contacts from my personal Gmail", "use this one for the address book". Pass reset=true to go back to following the default mailbox. It only moves where contacts are read and written; email keeps leaving from the default mailbox, which is set_default_mailbox. This is the CONTACTS switch of a mailbox; to turn it off, or to change its EMAILS switch, use set_mailbox_uses.

    addressstring
    The Gmail address that holds the address book.
    resetboolean
    true = the contacts follow the default mailbox again.
  • send_milestone_email
    Communication
    Writes data

    Sends the milestone email of a loan to all its parties at once. "conditional_approval" (when the loan reaches approved with conditions) goes to title, borrowers, selling agent, broker and processor. "clear_to_close" (when the loan is clear to close) goes to title, borrowers, selling and listing agents, broker and processor, and asks title to schedule closing for the closing date. "items_needed" sends the open underwriting conditions, each party getting only the ones assigned to them, with the broker copied. Use it when the user says "send the conditional approval email for Garcia", "we are clear to close on 123 Main", "send the conditions to the title company", or right after moving a loan to approved with conditions / clear to close (offer it). Not for a one-off message to one contact (send_message). IMPORTANT: call it first with preview_only=true, show the recipients, what is missing and the email, and send only when the user approves.

    milestonestringrequired
    conditional_approval, clear_to_close or items_needed.
    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    closing_datestring
    Only for clear_to_close: the date title should schedule closing (YYYY-MM-DD). Leave it out to use the closing date on the loan.
    preview_onlyboolean
    true = only build the email and recipients, send nothing. Use it first; send (false) only after the user approves.
  • fetch_property_profile
    Pipeline
    Writes data

    Looks up the subject property on the county property appraiser record and fills the file with what it finds: property type, year built, the condo or association name (from the short legal description) and, on a refinance, the last sale date and price. Also returns the link to the county record and to the tax bill (combined property taxes). Use it when the user asks for the property profile, the property record, the taxes or the year built of a file — "pull the property info for the Garcia loan". Only works once the file has a purchase contract (or is a refinance). If the county is not clear from the address, read it from the purchase contract and pass it. Never overwrites a value the file already has.

    prestamostringrequired
    The file, as the user says it: borrower name, address, or number
    condadoanyrequired
    Florida county of the property, like "Miami-Dade" or "Broward", when it is known (it is on the purchase contract). Null to deduce it from the address.
  • view_mortgagee_clauses
    Documents
    Read-only

    Shows the account's mortgagee clause book: for each lender, the clause name (ISAOA/ATIMA), the address and when it was last updated. Use it when the user asks "what is the mortgagee clause for Rocket?", "which lenders do we have clauses for?", or before changing one. With `lender` it finds that lender by a flexible name match. Title and HOI requests take the clause from this book automatically.

    lenderstring
    A lender as the user says it ("rocket", "UWM"). Omit for the whole book.
    buscarstring
    Free text to filter the list by lender, clause or address.
  • save_mortgagee_clause
    Documents
    Writes data

    Adds or updates the mortgagee clause of one lender in the account book. Use it when the user says "the mortgagee clause for Rocket changed to…", "add UWM's clause: United Wholesale Mortgage, LLC ISAOA/ATIMA, PO Box…". The lender can be written as people say it; if it already exists it is updated (fields left out keep their value), otherwise it is created. For many clauses at once (pasting the book) use import_mortgagee_clauses.

    lenderstringrequired
    The lender, as the user says it ("Rocket Mortgage").
    nombrestring
    Clause name line, e.g. "Rocket Mortgage, LLC ISAOA/ATIMA". Required when the lender is new.
    direccionstring
    Mailing address, one or more lines ("PO Box 6577\nCarol Stream, IL 60197").
    aliasarray
    Other names the lender shows up with ("Quicken Loans"). Replaces the current list.
    nuevo_nombre_lenderstring
    Only to rename the lender itself.
  • delete_mortgagee_clause
    Documents
    Writes data

    Removes one lender's mortgagee clause from the account book. Use it when the user says "delete the clause for Flagstar", "we no longer work with that lender". The lender can be written as people say it. To change a clause instead, use save_mortgagee_clause.

    lenderstringrequired
    The lender, as the user says it.
  • import_mortgagee_clauses
    Documents
    Writes data

    Imports many mortgagee clauses at once from pasted text: a CSV or spreadsheet copy with a header row (Lender, Clause, Address, City, State, Zip), or blocks separated by a blank line where the first line is the clause ("Rocket Mortgage, LLC ISAOA/ATIMA", optionally "Lender: clause") and the next lines are the address. Use it when the user pastes the mortgagee clause book or a list of clauses. Lenders already in the book are updated. Set `preview` to check what would be imported without saving.

    textostringrequired
    The pasted text, exactly as the user gave it.
    previewboolean
    true to only show what would be imported.
  • mark_initial_request
    Documents
    Writes data

    Marks the status of one initial third-party request of a loan (HOI, title or HOA certs) WITHOUT sending any email. Use it when the user says "the broker already ordered title on the Lopez file", "HOI was requested by the broker", "I sent the HOA request myself", or wants to undo it ("title was not actually requested"). To actually send the request emails use send_initial_requests.

    loanstringrequired
    The loan, as the user says it ("the Lopez loan", "12 Oak Ave").
    requeststringrequired
    Which one: "hoi", "title" or "hoa" (HOA certs).
    statusstringrequired
    'requested_by_broker' = the broker sent it on their own; 'requested' = it went out some other way from the office; 'not_requested' = undo, nobody has requested it.
  • attach_document
    Documents
    Writes data

    Files a document the user attached in the chat into a loan's document checklist. Use it when the user uploads a file and says what it is: "this is Robert's W2", "here's the signed contract for the Garcia loan". The file_path comes from the "[Attached document: … — path: …]" note in the conversation — never invent it, and never ask the user for it. Identify the checklist entry by loan plus document type (or by document id from check_documents). The document is marked as received, ready for review.

    file_pathstringrequired
    The storage path from the "[Attached document: … — path: …]" note of the attached file in this conversation.
    file_namestring
    The original file name, from the same note.
    document_idinteger
    The checklist document id, when it is already known (e.g. from check_documents).
    loanstring
    The loan, as the user says it: borrower name, address, or number. Needed when there is no document_id.
    document_typestring
    The document type, e.g. "w2", "bank_statement_personal", "paystub". Needed when there is no document_id.
  • document_versions
    Documents
    Read-only

    Lists every version of one checklist document: each time it was sent in, who sent it, when, how it was closed out (approved, rejected, incomplete) and a link to open that exact file. Use it when the user asks about a resubmission — "what did he send the first time?", "show me the previous bank statement", "how many times have we asked for this?" Identify the document by id (from check_documents) or by loan plus document type.

    document_idinteger
    The document id, when known (e.g. from check_documents).
    loanstring
    The loan, as the user says it. Needed when there is no document_id.
    document_typestring
    The document type, e.g. "bank_statement_personal", "w2".
  • view_waived_documents
    Documents
    Read-only

    Lists the documents that were taken OFF a loan (marked not applicable / N/A). They are not deleted — they keep their history — but they no longer show on the loan file, so this is the only way to see them. Use it when the user asks what was waived or removed from a file, when a document they expected is nowhere on the checklist ("where did the survey go?", "I do not see the W-2"), or when they want something put back. To put one back, call update_document with the document_id from here and status "pending"; to remove it for good, delete_document.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
  • send_document
    Documents
    Writes data

    Sends one or more documents from a loan's file to a contact, attached to an email or as media on WhatsApp or SMS (any contact can be texted unless they replied STOP). Use it when the user wants a document that is already in the file delivered to someone: "send Maria the preapproval letter", "email the appraisal to the title company", "whatsapp him the CD", "send the Garcias their approval and the contract". Documents are named the way people say them (label, type or id from check_documents); the contact by name or by role on the loan (borrower, realtor, title company…). IMPORTANT: two-step action — call it first WITHOUT confirm to get the draft and the list of files, show it to the user, and only when they approve call it again with confirm=true. To write a message without a file use send_message; to ASK for missing documents use request_documents.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    documentstringrequired
    Which document(s), as the user says it: "the preapproval letter", "appraisal and CD", "his W-2", a document id, or "all".
    contactstringrequired
    Who receives it: a name ("Maria"), or a role on the loan ("the title company", "the borrower", "the realtor").
    channelstring
    How to send it. If omitted: email when the contact has one, otherwise sms — any contact can be texted unless they replied STOP.
    messagestring
    Optional note to go with the file(s). Without it, a short standard note is written for the user to approve.
    confirmboolean
    true = the user already saw and approved the draft: send it. Never set it on the first call.
  • send_document_to
    Documents
    Writes data

    Sends documents that ALREADY came in on a loan to the underwriter or to the processor, attached to an email (or as media on WhatsApp). Use it when the user wants to move a file forward inside the office: "send the W2 to the underwriter", "forward Maria’s paystubs to processing", "the appraisal is in, get it to the underwriter", "send everything we have to the processor". This is NOT a request: the document is already on the file and this delivers it. To ASK a borrower or a third party for something missing use request_documents; to send a document to a named person or to an outside party (the realtor, the title company) use send_document. Documents are named the way people say them ("his W-2", "the appraisal and the CD", "all"). IMPORTANT: two-step action — call it first WITHOUT confirm to get the draft and the list of files, show it to the user, and only when they approve call it again with confirm=true.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    documentstringrequired
    Which document(s) already on the file go out, as the user says it: "the W-2", "appraisal and CD", a document id, or "all".
    tostringrequired
    Who receives it inside the office: the underwriter (the one who approves), or the processor (the one who puts the file together). Say it the way the user did — "underwriting" and "the UW" are the underwriter; "processing" is the processor.
    channelstring
    How to send it. If omitted: email, which is how it goes inside the office. A text works too (anyone can be texted unless they replied STOP) but email is how the office expects files.
    messagestring
    Optional note to go with the file(s) ("this is the updated one, the first paystub was cut off"). Without it, a short standard note is written for the user to approve.
    confirmboolean
    true = the user already saw and approved the draft: send it. Never set it on the first call.
  • send_portal_link
    Documents
    Writes data

    Creates (or renews) the secure portal link for one person on one loan AND sends it to them. Use it when the user asks to send or resend the link to a specific person — "resend the portal to Maria", "text the upload link to the borrower", "send the realtor their portal link". The copy follows who they are on that loan: a realtor (realtor, listing or selling agent) gets the realtor portal message, the borrower or co-borrower gets the application link (or, once the loan is past the application, their loan portal), and anyone else (HOA, title, escrow, insurance…) gets an upload link for the documents asked of them. Email is the default; `channels` adds a text. Texts reach anyone — borrower, realtor, title… — except who replied STOP, and except when the account is in test mode, where texts go to the team's test phones. Read `envios` and the `aviso` before telling the user anything went out: each channel says whether it was queued and why not (no phone on file, channel off, replied STOP). The portal asks for a sign-in code by email, so a person with no email on file gets nothing (not even a text): ask for their email first. Calling it twice in the same minute reuses the same link and sends once. Previous links for that person keep working until they expire (30 days).

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    contactstringrequired
    The person, as the user says it ("Maria", "the realtor of...").
    channelsarray
    How it goes out: ["email"], ["sms"] or both ["email","sms"]. Omit for email only. Use it when the user says "text it", "by SMS" or asks for both. A text reaches anyone who did not reply STOP.
    channelstring
    Single-value form: 'all' is email plus text, 'email' or 'sms' one only. Ignored when `channels` is given.
    confirmboolean
    In the chat: omit it first to get the draft (who, channel, text) and show it; true only after the user said yes to that draft.
  • create_portal_link
    Documents
    Writes data

    Creates a secure portal link for one contact on one loan WITHOUT sending anything, and returns the URL. Use it when the user wants the link itself — "give me Maria's portal link", "copy the borrower portal link", "open the portal as the borrower sees it" — or will share it themselves (copy and paste). To email it to the person use send_portal_link instead; do not call both for the same request or the person may get two links. The link expires in 30 days and earlier links keep working.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    contactstringrequired
    The person, as the user says it ("Maria", "the borrower of...").
  • view_borrower_loan_summary
    Pipeline
    Read-only

    Shows what the borrower sees about their loan in the portal: loan program, amount, interest rate and rate type, term, estimated monthly payment (principal & interest, plus property taxes when on file), rate lock status and expiry, down payment, LTV, purchase price or value, closing date, loan number, and the key dates (contract, appraisal, insurance, title, contingencies, closing) with which ones the borrower can already see. Use it when the user asks "what is the monthly payment on…", "what does the borrower see", "is the rate locked", or for the key dates of a loan. To change any of it use update_loan.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
  • send_portal_message
    Communication
    Writes data

    Sends a message to the borrower in the chat of their borrower portal (it shows up in the chat bubble next time they open the portal; no email or text goes out). Use it when the user says "reply to Maria in the portal", "tell the Laventi borrower in the portal that…" or answers something read with read_portal_messages. For email or SMS use send_message instead.

    loanstringrequired
    The loan, as the user says it ("the Laventi loan", "123 Main St", a loan number).
    messagestringrequired
    The text the borrower will read, exactly as it should appear.
    confirmboolean
    In the chat: omit it first to get the draft and show it; true only after the user said yes to that draft.
  • read_portal_messages
    Communication
    Read-only

    Reads the chat between the loan officer and the borrower inside the borrower portal (the chat bubble the borrower sees). Use it when the user asks "did Maria write in the portal?", "what did the Laventi borrower ask?", "any new portal messages on loan 123?" or before answering the borrower with send_portal_message. It is NOT the email/SMS inbox (view_inbox / view_conversation). Reading marks the borrower's messages as seen unless mark_seen is false.

    loanstringrequired
    The loan, as the user says it ("the Laventi loan", "123 Main St", a loan number).
    limitinteger
    How many of the latest messages. Default 30.
    mark_seenboolean
    Mark the borrower's messages as seen. Default true.
  • archive_document
    Documents
    Writes data

    Archives one or more documents (or underwriting conditions) on a loan: they are kept with their file and history but leave the active list, stop counting as pending and no longer block a stage. Use it when the user says "archive the old W-2", "put the 2022 tax returns away", "archive everything in other documents", or wants something out of sight WITHOUT saying it does not apply. Pick them by name, id or a whole section (the union is archived). restore_document brings them back to the status they had; view_archived_documents lists them. If the document simply is not needed on this loan, use remove_from_summary (N/A) instead; to erase a line that should never have existed, delete_document.

    loanstringrequired
    The loan, as the user says it: a borrower name, a property address or a loan number.
    documentsstring
    The documents by name, as the user says them: "the 2023 W-2 and the old paystubs".
    document_idsarray
    Document ids on that loan, when known (e.g. from check_documents).
    sectionstring
    A whole section of the checklist, as the user says it: "income", "subject property", "title", "borrower", "assets", "credit", "other documents", "underwriting conditions".
  • restore_document
    Documents
    Writes data

    Brings archived documents back to the active list of a loan, each one to the status it had before it was archived (received if it has a file and nothing was saved, pending otherwise). Use it when the user says "unarchive the W-2", "bring back the archived bank statements", "restore everything archived in income". Pick them by name, id (from view_archived_documents) or section — a section here means its archived documents. Documents that are not archived are left as they are. To put back something marked N/A (removed from summary), use update_document with status "pending".

    loanstringrequired
    The loan, as the user says it: a borrower name, a property address or a loan number.
    documentsstring
    The documents by name, as the user says them: "the 2023 W-2 and the old paystubs".
    document_idsarray
    Document ids on that loan, when known (e.g. from check_documents).
    sectionstring
    A whole section of the checklist, as the user says it: "income", "subject property", "title", "borrower", "assets", "credit", "other documents", "underwriting conditions".
  • view_archived_documents
    Documents
    Read-only

    Lists the ARCHIVED documents of a loan — kept on file but out of the active list — with the status each would go back to if restored. Use it when the user asks what was archived, or looks for a document that is not on the list and was archived ("where is the old W-2?"). To bring one back use restore_document with its id. For documents removed as not applicable (N/A) use view_waived_documents.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
  • remove_from_summary
    Documents
    Writes data

    Removes one or more documents from the Loan Summary of a loan because THIS loan does not need them — they are marked not applicable (N/A), keep their history, and are not added back when the checklist re-syncs. Use it when the user says "remove the survey from the summary", "we do not need the W-2s on this one", "take the HOA docs off", or clicks Remove from summary. Pick them by name, id or section. view_waived_documents lists what was removed, and update_document with status "pending" puts one back. To only hide something without saying it does not apply, use archive_document; to erase a line that should never have existed, delete_document.

    loanstringrequired
    The loan, as the user says it: a borrower name, a property address or a loan number.
    documentsstring
    The documents by name, as the user says them: "the 2023 W-2 and the old paystubs".
    document_idsarray
    Document ids on that loan, when known (e.g. from check_documents).
    sectionstring
    A whole section of the checklist, as the user says it: "income", "subject property", "title", "borrower", "assets", "credit", "other documents", "underwriting conditions".
  • remove_from_initial_documents
    Documents
    Writes data

    Takes HOI, title and/or HOA certs OFF the Initial Documents section of one loan — the file does not need that initial request (it already has its insurance, a refi with no new title work, no HOA). Nothing is sent and the documents themselves are not touched. Use it when the user says "remove HOA from the initial documents on Lopez", "this one does not need the HOI request". With recipient it instead removes ONE person from the recipients of those requests and keeps the request ("take the processor off the title request", "don't send the HOA email to Maria"); they stay on the loan. Pass put_back: true to show them (or that recipient) again. To undo a request marked as sent (but keep it in the section) use mark_initial_request with not_requested.

    loanstringrequired
    The loan, as the user says it ("the Lopez loan", "12 Oak Ave").
    requestsarrayrequired
    Which ones: "hoi", "title", "hoa" (HOA certs).
    recipientstring
    Only to remove one recipient instead of the whole request: their name, email or role as the user says it ("the processor", "orders@title.com").
    put_backboolean
    True to put them (or the recipient) back.
  • view_portal_status
    Documents
    Read-only

    Shows what a borrower, realtor or any other party of a loan sees in their upload portal and how their invitation is going: whether a link exists and is still active, when it was created (sent), whether and when they opened it, when it expires, the last file they uploaded, and the list of documents and lender conditions they see with each status. Use it when the user asks "did Maria open her portal link?", "what does the borrower see?", "has the realtor uploaded anything?", "is the upload link still valid?" or "who has not opened their link?". Omit contact to get every party on the file. To create or resend a link use send_portal_link; to change what they see use adjust_checklist or update_document. Onboarding links are separate: view_onboarding.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    contactstring
    One person, as the user says it ("Maria", "the realtor"). Omit for every party on the file.
  • send_onboarding_link
    Documents
    Writes data

    Creates the onboarding link for the realtor of a loan — a welcome form where they fill in the OTHER parties of the file (developer, management office, listing agent, title company, insurance) — and queues the invitation by email only. Use it when the user wants the realtor to complete the contacts of a file: "send the onboarding to the realtor of the Villegas file", "ask Maria for the contacts of 412 Elm". Roles already on the file are not asked again. To check what has been filled in, use view_onboarding.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    contactstring
    Who fills the form, as the user says it ("Maria", "the realtor"). Omit to use the realtor already on the file.
    rolesarray
    Which parties to ask for, as the user says them ("developer", "title company"). Omit for the usual five: developer, management company, listing agent, title company, insurance.
    confirmboolean
    In the chat: omit it first to get the draft (who, channel, text) and show it; true only after the user said yes to that draft.
  • view_onboarding
    Documents
    Read-only

    Shows the onboarding status of a loan: the links sent to the realtor, whether they opened them, which parties they filled in (and who they picked), which they skipped, and which are still missing. Use it when the user asks how the onboarding is going, whether the realtor answered, or what contacts are still missing on a file — "did the realtor of the Villegas file fill in the contacts?".

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
  • set_doc_tracking
    Documents
    Writes data

    Changes the automatic document chasing by property type: adds or removes a document from the condo or single-family package, changes who it is requested from, sets the reminder cadence in business days, or pauses/resumes the whole chasing. Use it when the user says "also chase the flood policy on condos", "stop asking the HOA for the budget", "remind every 3 business days", or "pause the document chasing". To see the current setup first, use view_doc_tracking.

    property_kindstring
    Which package to touch. Required when adding or removing a document.
    add_documentstring
    A document to start chasing for that property kind, as the user says it ("condo questionnaire", "elevation certificate").
    remove_documentstring
    A document to stop chasing for that property kind.
    recipient_rolestring
    Who the added document is requested from, as a contact role ("hoa", "insurance company", "surveyor", "borrower"). Defaults to the document catalog default.
    cadence_daysinteger
    Business days between reminders for the same party.
    enabledboolean
    true to resume the chasing, false to pause it entirely.
  • view_doc_tracking
    Documents
    Read-only

    Shows the automatic document chasing by property type. Without a loan, it lists what gets chased for condos and for single-family properties (which documents, from whom, how often in business days, and whether the chasing is on). With a loan (a phrase like "the Villegas condo" or an address), it shows what that file is waiting on, who is being reminded and when the last reminder went out, plus whether the Closing Disclosure notice was already sent to the borrower. Use it when the user asks "what are we chasing", "did the HOA get reminded", "is the condo questionnaire being followed up", or before changing the setup with set_doc_tracking.

    loanstring
    The loan, as the user says it ("the Villegas loan", "123 Main St"). Leave empty to see the account-wide chasing catalog.
  • adjust_checklist
    Documents
    Writes data

    Adjusts the checklist of ONE loan by hand: adds documents the rules did not derive ("also ask for a divorce decree") or marks documents as not applicable ("we do not need the survey on this one"). This is how you ask ONE borrower for their personal paperwork — their ID (driver's license, passport, social security card), their immigration documents (green card, visa, work permit, asylum documents), the VA ones (certificate of eligibility, DD-214) — and how you ask for a letter of explanation, which can be asked for several times on the same file, one per subject. Use `update` to REWORD a request that is already on the file — "change the letter of explanation to say it is about the 2023 late payments, not 2022", "fix the wording on that letter" — instead of removing it and adding it again, which loses its history and confuses the borrower who already read the old one. For changing the office-wide rules use edit_checklist_rules instead.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    addarray
    Documents to add to this loan.
    removearray
    Document types to mark as not applicable on this loan.
    updatearray
    Requests already on this loan whose description changes. This replaces the old wording; it does not add a second request.
  • review_checklist
    Documents
    Writes data

    Reviews ONE loan for documents that are still on the checklist but no longer apply, and removes them once confirmed. update_loan already removes these on its own every time a loan is saved, so this is for checking or cleaning a file nobody has edited since. Use it right after something about the file changes — the property type ('this one is actually a single family, not a condo'), purchase vs refinance, the program (FHA, VA, conventional) — and whenever the user says the checklist still shows paperwork that no longer belongs, that changing the property type did not change the documents, or asks to clean up the list. Without `confirm` it only reports what would come off, with the reason for each one, so the user can decide; call it again with `confirm` to remove them, and with `only` to remove just some. It never touches documents that already came in, that have a file attached, or underwriting conditions. To remove a specific document the rules never asked for, use adjust_checklist instead.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    confirmboolean
    true removes them from the checklist (marks them not applicable). Leave it out to just show what no longer applies.
    onlyarray
    The documents to remove, by the `id` a previous call returned. Leave it out to remove everything that no longer applies.
  • view_checklist_rules
    Documents
    Read-only

    Explains the active document checklist rules of this office in plain English, including any per-account overrides (disabled types, how many bank statements or tax return years). With a loan, it also explains which rule generated each document on that checklist. Use it when the user asks why a document is being requested or how the checklist works.

    loanstring
    A loan, to also explain what generated each of its documents.
  • edit_checklist_rules
    Documents
    Writes data

    Changes the office-wide checklist rules: disable a document type so it is never requested ("we never ask for surveys"), re-enable it, or change quantities ("ask for 3 bank statements", "1 year of tax returns"). Applies to every loan the next time its checklist syncs. For one specific loan use adjust_checklist instead.

    disablearray
    Document types to stop requesting everywhere, e.g. ["survey"].
    enablearray
    Previously disabled document types to request again.
    bank_statementsinteger
    How many bank statements to request per account (default 2).
    tax_return_yearsinteger
    How many years of tax returns to request (default 2).
    w2_yearsinteger
    How many years of W-2s to request (default 2).
  • read_approval_conditions
    Documents
    Read-only

    Reads a lender approval document — the PDF the bank sends when a loan is approved with conditions, or a photo or screenshot of it — and pulls out the underwriting conditions as a clean list: bank statements, mortgage statements, rental income, liability verifications, letters of explanation. Only the section the team works comes back — Prior to Final Approval (Freedom), Prior to Doc/Approval (Cake), PTD (Jet) — not the closing, funding or lender internal ones. Use it whenever the user attaches an approval, a conditional approval or a commitment letter ("here is the approval", "pull the conditions off this", "the bank sent this back"). The file_path comes from the "[Attached document: … — path: …]" note in the conversation — never invent it. This only READS: nothing is saved. Every condition comes back with the bank wording ('texto') and a short plain-English title ('titulo', what the borrower reads). Show the user the titles, let them drop the ones that do not belong, and only then call update_conditions with accion 'add', passing the bank wording in 'condiciones' and the titles in 'titulos' (same order).

    file_pathstringrequired
    The storage path of the approval document, from the "[Attached document: … — path: …]" note of the attached file.
    file_namestring
    The original file name, from the same note.
    loanstring
    The loan the approval belongs to, as the user says it. Optional, but with it the answer says which conditions are already on the file so they do not get added twice.
  • read_document
    Documents
    Read-only

    Reads a document that is already uploaded on a loan file and checks it: what it actually is, what it says, where it disagrees with the file, and what the document itself is missing. Use it whenever someone asks whether a paper adds up ("does the appraisal match?", "is the appraised value what we have?", "check this contract against the file"), whether something is missing from a document ("are all the pages there?", "is this signed?", "what is wrong with this bank statement?"), or simply what a document that just came in says ("what does this say?", "read the insurance policy on the Garcia file"). It compares the appraised value, purchase price, loan amount, property address, borrower name, loan numbers and dates against what the file already has, and it tells you when a paper was filed under the wrong type. It does not fix differences: show them and let the user decide whether the file or the paper is the one to fix, then use update_loan or update_document. One exception: on a purchase contract it detects whether the buyer is a person or an LLC/corporation/trust and sets "title under a corporation" and the corporate name on the file accordingly (that is what asks for the corporate documents) — tell the user what was detected and changed (see comprador). For what the FILE is missing (facts nobody has entered yet) use check_missing_data instead; to pull underwriting conditions off a lender approval use read_approval_conditions.

    documentstringrequired
    Which document: its id, or the words it shows on the list — the name of the paper ("the appraisal", "Personal Bank Statement", "Hazard Insurance") or a few words of a condition text.
    loanstringnull
    The file it is on, as the user says it: borrower name, address, or number. Pass it whenever the user named a file — without it the search runs across every file and a common name comes back as "which one?".
  • suggest_documents
    Documents
    Read-only

    Reviews a whole loan file with AI and suggests the documents it is still missing to get through underwriting — based on its program (conventional, FHA, VA, DSCR, bank statement, P&L, VOE), purpose, occupancy, property type (condo, 2-4 units), whether title goes under an LLC, the borrowers and their declared income. Use it when someone asks "what else do we need on the Garcia file?", "what documents am I missing?", "anything else underwriting will ask for?". Documents already on the checklist are never suggested. It only SUGGESTS: show the list and, for the ones the user wants, call adjust_checklist (document_type when given, otherwise name). For the status of what is already on the checklist use check_documents.

    loanstringrequired
    The file, as the user says it: borrower name, address, or number.
  • send_message
    Communication
    Writes data

    Sends an email, text (SMS) or WhatsApp message to a contact, written free-form or from a template. A text can go to ANY contact — borrower, realtor, title, HOA, insurance… — with no consent or permission needed; only someone who replied STOP is never texted. IMPORTANT: draft first, one yes — call it WITHOUT confirm (also when the user orders the send): that returns the draft (who, channel, text) shown on screen; on their yes call it again with confirm=true and its borrador_id. Never ask twice. For pending conditions or missing documents of a loan use request_documents instead: it writes the real list. Use it when the user wants to message, email or text someone: "text Maria that we are waiting on her W-2", "send the Garcias the welcome email". It can attach files from the loan (attachments = document ids from check_documents); to send a document by its name ("the appraisal") use send_document instead. For reading past messages use view_conversation. LANGUAGE: write the subject and body in the RECIPIENT's language — English unless the contact prefers Spanish — never in the language the user happens to chat in: a loan officer asking in Spanish still gets an English email for an English-speaking client. Talk to the user in their language; draft for the contact in theirs.

    contactostringrequired
    Who, as the user says it: a name, email or phone number.
    canalstring
    How to send it. If omitted: email when the contact has one, otherwise sms. Any contact can be texted unless they replied STOP.
    mensajestring
    Free-form body, in the CONTACT's language (English by default), not the language of the chat. Either this or plantilla is required. Any list (items, dates, steps) goes ONE item per line starting with "- ", never in a sentence. Never use it to ask for pending conditions or missing documents: that is request_documents.
    asuntostring
    Email subject (free-form emails only), in the contact's language.
    plantillastring
    A template key ('docs_missing_reminder', 'clear_to_close'…) instead of free text. view_templates lists them.
    variablesobject
    Values for the {{variables}} of the template, when using one.
    attachmentsarray
    Document ids (from check_documents) to attach from the loan file. Email embeds them; WhatsApp/SMS send them as media.
    fromstring
    Email only: which connected mailbox it leaves from, when the user has more than one ("send it from my work email"). It has to be one of THEIR own — view_connected_mailboxes says which. Leave it out and it picks itself: the mailbox this person last wrote to (a reply goes back out the way it came in), or the default one.
    confirmboolean
    true = the user said yes to the draft you showed: send it. Never set it on the first call.
    borrador_idstring
    With confirm=true: the borrador_id the draft returned. It sends exactly that draft (same person, channel and text) even if you phrase the contact or the text differently.
  • summarize_thread
    Communication
    Read-only

    Summarizes one email/SMS/WhatsApp thread in one or two short sentences: what is being asked and what is missing. Use it when the user asks "what is this about?", "catch me up on the Coconut Palm thread", "summarize this one", or before drafting a reply to a long chain. It reuses what the inbox AI already wrote when it is enough, so asking twice about the same thread costs nothing.

    conversationstringrequired
    Which thread: the key the inbox lists (h:…), a contact (name, email, phone or id) for their latest thread, or the raw email/phone of an unknown sender.
    refreshboolean
    Write it again even if there is one saved. Rarely needed.
  • view_inbox
    Communication
    Read-only

    Shows the unified message inbox of the account: every email, text (SMS) and WhatsApp conversation grouped by EMAIL THREAD (one row per subject, like Outlook), with unread counts, what the AI flagged as urgent, and which loan file each thread belongs to — the loan file is the folder that groups threads. Use it when the user asks "what is new?", "what is urgent today?", "anything unanswered?", "show me the messages about the Oak Street file", "what came in from the lender?". Everything that arrives is shown; only PURE marketing (nothing about any property, borrower or loan) is set apart in Promotions and is NOT shown unless priority=noise is asked for. Automated notices that sell nothing (the LOS, lender portals, banks, e-signature, calendars) are a DIFFERENT thing: category=notificacion, they stay in the Inbox and the folders counter reports them as notifications. Opening a thread also says which loan file it is linked to and which files it probably belongs to (loan_suggestions). Pass conversation to read one thread. To reply use send_message; to mark things read use mark_read; to fix a wrong call use set_message_priority or set_message_loan. Only the most recent messages are swept: to go further back in history call it again with before. To say how many unread emails one loan file has, pass loan and read loan_unread (exact count).

    boxstring
    inbox (default) = threads where somebody wrote to us. sent = what went out from here, like the Sent folder of an email client. all = both, which is what a single loan's inbox shows: every email, text and portal message tied to that loan, answered or not. When loan is given and box is left out, it is all.
    filterstring
    unread = only conversations with unread incoming messages. waiting = they wrote last and nobody has replied yet. done = the Done folder: threads somebody closed with set_thread_status. Done threads are OUT of every other folder until a new message reopens them, so this is the only way to see them again.
    prioritystring
    urgent = only what needs acting on today. noise = the Promotions folder: pure marketing, normally set apart. all = everything, promotions included. Default: everything except pure marketing. For automated notices that are not selling, do not use this: ask for category=notificacion, they live inside the Inbox.
    channelstring
    Only messages of this channel.
    loanstring
    Only messages about one loan file: a property address, a borrower name or a file number, as the person says it. Use "none" for the messages that are not tied to any file.
    foldersstring
    Lists EVERY loan-file folder of one group, A to Z, with or without messages. Only OPEN files get a folder: open = exactly the loans the first view of the Loans screen shows; prequal = exactly the pre-quals the first view of the Pre-Q screen shows. Closed, on hold, archived and New Client files never get a folder — use `loan` to read the messages of one of those. Leave it out to get only the files somebody wrote about recently.
    categorystring
    Only messages the AI filed under this category. Note promocion and notificacion are NOT the same: promocion is somebody selling (Promotions, out of the Inbox), notificacion is a system reporting something that happened — the LOS, a lender portal, a bank, an e-signature — which stays in the Inbox.
    beforestring
    Only messages older than this moment (ISO timestamp), to read further back than the recent sweep — to keep going back in time: pass the next_before of the previous call. Leave it out for the newest page.
    conversationstring
    One thread: the key this action lists (h:…), or a contact (name, email, phone or id) to open their most recent thread, or the raw email/phone of an unknown sender as the inbox lists it.
    limitinteger
    How many messages of the thread (default 50, newest first).
    thread_onlyboolean
    Only with conversation. true = return ONLY that thread: conversations and loans come back empty and the folder counters are all zero (they were not counted, it does not mean the inbox is empty). Use it whenever the question is about one thread and the list of the inbox is not needed — it is much faster.
  • search_messages
    Communication
    Read-only

    Searches every message of the account — email, text (SMS) and WhatsApp, incoming and outgoing — by what the message SAYS (subject and body) and by who wrote it (name, email address or phone number). Use it when the user is looking for something specific that was said and does not remember where: "find the email where Maria mentioned the appraisal", "what did the title company write last week?", "search the messages for payoff letter", "did anyone send the paystubs?". Each result says which conversation it belongs to, so pass that key to view_inbox to open the whole thread and read it in context. Use view_inbox instead when the question is about what is new, unread or urgent — that is the inbox of today, this is the archive. Noise (marketing and automated mail) IS searched: if someone is looking for a specific message, hiding it would be lying.

    querystringrequired
    The words to look for, as the person says them: a word from the message ("appraisal", "payoff letter"), or a name, email or phone of whoever wrote it.
    channelstring
    Only messages of this channel.
    loanstring
    Only messages about one loan file: a property address, a borrower name or a file number, as the person says it. Use "none" for the messages that are not tied to any file.
    prioritystring
    Only messages the AI filed under this priority.
    limitinteger
    How many results (default 20, newest first).
  • draft_reply
    Communication
    Read-only

    Writes a suggested reply to a conversation, using the thread and the state of the loan file. Use it when the user asks "draft a reply", "what do I tell her?", "answer this one for me", or wants a starting point for an answer. It only writes text: nothing is sent, and it never invents data — what it does not know it leaves as {{a gap}} for the user to fill. To actually send it, use send_message.

    conversationstringrequired
    Which conversation: the thread key from the inbox (h:…), a contact (name, email, phone or id), or the raw email/phone of an unknown sender as the inbox lists it.
    instructionsstring
    What the reply should say, if the user asked for something specific ("tell her Friday works", "ask for the W2 again").
  • mark_read
    Communication
    Writes data

    Marks incoming messages (email, SMS, WhatsApp) as read so they stop counting as unread in the inbox. Use it after showing messages when the user says "mark those as read", "I saw Maria's texts", "clear my inbox". Pass conversation with an inbox thread key (`h:…`, the usual case: it marks just that thread), or with a contact to mark EVERYTHING from that person, or all=true for every unread message of the account. It never deletes anything.

    conversationstring
    What to mark: normally an inbox thread key as view_inbox lists it (`h:<hash>`), which marks only that thread. A contact (name, email, phone or id) marks everything from that person, and the raw email/phone of an unknown sender marks everything from it.
    allboolean
    true = mark every unread message of the account as read.
  • archive_message
    Communication
    Writes data

    Archives an inbox thread: it disappears from the inbox here AND gets archived in the connected Gmail/Outlook mailbox, without deleting anything anywhere — the messages stay searchable and in the history. Use it when the user is done with an email and wants it out of the way ("archive that one", "get this out of my inbox", "clear the Chase alerts"). Pass conversation with an inbox thread key (`h:…`, the usual case) or a contact to archive everything from that person. To bring it back, pass undo=true.

    conversationstringrequired
    What to archive: an inbox thread key as view_inbox lists it (`h:<hash>`), a contact (name, email, phone or id) to archive everything from that person, or the raw email of an unknown sender.
    undoboolean
    true = put it back in the inbox here. It does NOT move it back in the mailbox.
  • set_message_priority
    Communication
    Writes data

    Corrects how the AI triaged a message: mark it urgent, normal, or noise. Use it when the user disagrees with the inbox — "this is not urgent", "flag this one", "this is junk", "stop treating these as important". Pass message for one, or conversation to fix every unread message from that person. The correction teaches the filter: after two messages from the same domain are marked as noise by hand, the next one is filed as noise on arrival. Nothing is ever deleted.

    prioritystringrequired
    What it should have been.
    messageinteger
    The id of one message, as the inbox shows it.
    conversationstring
    Or a whole conversation: the thread key from the inbox (h:…), a contact (name, email, phone or id) for everything of theirs, or the raw email/phone of an unknown sender.
  • set_message_category
    Communication
    Writes data

    Corrects WHAT a message is about when the AI filed it under the wrong kind — which is a different question from how urgent it is (set_message_priority). Use it when the user says "this is from the lender, not marketing", "these are title company emails", "this is just a system notification", "stop filing these as promotions", or asks to move something out of Promotions and back into the Inbox. The two that get confused: promocion is somebody SELLING (it lives outside the Inbox, in Promotions), notificacion is a platform REPORTING something that happened — the LOS, a lender portal, an e-signature, a bank, a calendar — and it stays in the Inbox. Pass message for one, or conversation for the whole thread. The correction is remembered as manual, so the classifier stops overriding it. Nothing is ever deleted.

    categorystringrequired
    What it should have been, as the person says it: cliente (borrower), prestamista (lender/bank), titulo_escrow (title/escrow), avaluo_inspeccion (appraisal/inspection), seguro (insurance), agente (real estate agent), proveedor (vendor), promocion (somebody selling), notificacion (a platform reporting something), personal, otro.
    messageinteger
    The id of one message, as the inbox shows it.
    conversationstring
    Or a whole conversation: the thread key from the inbox (h:…), a contact (name, email, phone or id) for everything of theirs, or the raw email/phone of an unknown sender.
  • set_message_loan
    Communication
    Writes data

    Files a whole conversation under the right loan file, or detaches it from any file. Use it to link an email thread to its loan ("link this to the Pena file", "yes, it is that one" after view_inbox suggested files), or when the inbox put it on the wrong one: "this is about the Pine Avenue file", "move these to the other property", "this has nothing to do with that loan". It always moves the COMPLETE thread — incoming, outgoing and SMS alike — so a thread never ends up split between two files; passing one message moves the thread it belongs to. Safe to repeat: moving a thread to the file it is already in changes nothing. Pass loan="none" to UNLINK: use it when the person says an email or message is not about that loan ("unlink this email", "this has nothing to do with Pena", "remove it from that file"). Linking also brings the email's attachments (PDFs, photos) into that loan's Documents. The inbox learns from it: later messages of the same thread follow, and the sender is remembered.

    loanstringrequired
    Which file: a property address, a borrower name or a file number, as the person says it. "none" detaches the message from any file.
    messageinteger
    The id of one message, as the inbox shows it: its whole thread moves.
    conversationstring
    Or a whole conversation: the thread key from the inbox (h:…), a contact (name, email, phone or id) for everything of theirs, or the raw email/phone of an unknown sender.
  • set_thread_status
    Communication
    Writes data

    Flags an inbox thread as something to do, or marks it complete — the follow-up flag and the checkmark of an email client. Use it when the user wants to come back to an email ("flag this one", "I need to follow up on the Pena appraisal", "remind me about this by Friday"), or when they are done with it ("handled", "done with that one", "clear the flag"). Flagging it also creates the matching task in the task list, due on the date given or today, and marking it done completes that task. Pass status="none" to take the mark off without completing anything. A new message on the thread reopens it on its own.

    conversationstringrequired
    Which thread: the inbox thread key (`h:…`), or a contact (name, email, phone or id) to take their most recent thread, or the raw email/phone of an unknown sender.
    statusstringrequired
    'todo' flags it as pending and creates its task, 'done' marks it handled and completes that task, 'none' removes the mark and leaves the task alone.
    duestring
    Only with "todo": when the follow-up is due — ISO (YYYY-MM-DD) or "today"/"tomorrow". Defaults to today.
  • block_sender
    Communication
    Writes data

    Files everything from a sender as noise, now and from now on: past messages move to the Noise folder and new ones are filed there on arrival without asking the AI. Use it when the user says "block this", "I never want to see these again", "stop showing me this newsletter". Scope domain does it for the whole company (@bank.com). It never deletes anything and it refuses to block someone who is saved as a contact.

    senderstringrequired
    The email address it comes from, as the inbox shows it.
    scopestring
    address (default) = only that address. domain = everything from that company.
  • view_conversation
    Communication
    Read-only

    Shows the message history (emails, texts, WhatsApp — sent and received) with a contact, or all the messages around a loan. Use it when the user asks "what have we sent Maria?", "did the reminder go out?", "did she open my email?", "show me the thread on the Garcia file". Sent emails carry opened_at (first open, or when they replied) and opens (count); opened_at null means not opened yet — for "did X open the last email?" read ultimo_correo_enviado. Give it a contact or a loan (at least one). The contact goes as the user says it ("Federico Prueba", "la de Laventi", "the borrower on 412 Elm"); if they are on a loan's screen, pass that loan too: it settles which of two same-named contacts they mean, so do not ask.

    contactostring
    The person, as the user says it: name, email or phone.
    loanstring
    The loan, as the user says it ("the Martinez loan", "412 Elm").
    limiteinteger
    How many messages (default 20, newest first).
  • view_templates
    Communication
    Read-only

    Lists the message templates, grouped by section of the loan cycle (Pre-qual, Loan in process, Closing, Portal & documents, Condo) — the same sections and plain-English titles the Workflows screen shows ("Application received → Realtor"), with when each one goes out. Also returns each one's key, what it says by default, whether the account customized them, and which pipeline transition triggers each one automatically. Every template exists in English and Spanish, for email and for text, and asking for one key returns all four bodies — each contact receives the language their profile says (set_contact_language changes it). The "Document requests" family is what request_documents can pick from: the stock "Documents still pending" plus the account’s own docs_request_* templates (created and deleted with edit_template). Use it when the user asks what messages go out, wants to see a template before editing it, asks which request templates there are, or before send_message with a template key. When listing them for the user, group by `seccion` and name each by `titulo`, not by its key. To change one, use edit_template.

    clavestring
    One template key to see in full (with its default bodies). Omit to list them all.
    seccionstring
    Only the templates of one section: "Pre-qual", "Loan in process", "Closing", "Portal & documents", "Condo". Omit for all.
  • edit_template
    Communication
    Writes data

    Edits a message template for this account and saves it: the new wording replaces the stock one in every future send, right away (there are no drafts). Use it when the user wants to change what a message says: "make the docs reminder friendlier", "add my calendly to the welcome email". Variables go in double braces — {{borrower_name}}, {{portal_link}}… — view_templates lists each template's variables. Every template exists in English and Spanish: pass idioma='es' to change the Spanish wording, which is what Spanish-speaking borrowers receive. It is ALSO how the account gets its own document-request templates: pass `nueva: { label }` ("create a request template called Friendly reminder") and a docs_request_* template is born as a copy of the stock "Documents still pending" one, ready to pick in request_documents by that name and to edit like any other; `eliminar: true` deletes one of those (stock templates cannot be deleted, only reset with `restablecer`). It always returns a test render with sample data: show it to the user. For a text (sms) it also returns `sms`, how many carrier segments the final text takes; if it carries a warning, tell the user and offer a shorter wording.

    clavestring
    The template key ('docs_missing_reminder', 'docs_request_friendly_reminder'…). Optional only when creating one with `nueva` — then it is made from the label.
    canalstringrequired
    Which channel version to edit (and which one the test render shows). When creating or deleting, any value works.
    idiomastring
    Which language version: 'en' (default) or 'es'. Every template exists in both, and each contact gets the one their preferred language says — editing one language does not touch the other.
    cuerpostringrequired
    The new body, with {{variables}} where data should go. Leave it empty ("") when you are sending `bloques` instead, when creating with `nueva` without wording yet, or when deleting.
    bloquesanyrequired
    The formatted email, block by block, for the visual editor. Only for email: it produces both the styled HTML and the plain text (which is what goes in `cuerpo`, so leave `cuerpo` empty when you send blocks). Null for a plain-text template.
    asuntostring
    The new subject (email only).
    publishboolean
    Deprecated and ignored: saving always makes it live. Kept so older calls do not fail.
    restablecerbooleannullrequired
    true throws away the customization and goes back to the stock wording (the "reset to default" of 1.0). When true, `cuerpo` and `bloques` are ignored. Null or false to edit normally.
    nuevaany
    Create a NEW document-request template with this name. It starts as a copy of the stock "Documents still pending" wording (email and SMS versions, English and Spanish), already live. If `cuerpo` or `bloques` come too, that version is written right away.
    eliminarbooleannull
    true deletes the template (all its channels and languages). Only for the account’s own docs_request_* templates.
  • generate_preapproval_letter
    Communication
    Writes data

    Generates the official pre-approval letter (PDF) for a loan, in the format of the Letter tab of the Excel calculator: a first page of tips for the realtor and the letter itself (property, program, purchase price, down payment, loan amount, expiration and the final underwriting conditions), signed by the loan officer. It uploads the PDF to the file's documents and returns a download link that lasts 7 days. Use it when the user asks for a pre-approval letter: "generate the pre-approval for Garcia", "make me a letter for 320k for the Elm St file". Amount and expiration are optional: without them it uses the main pricing scenario of the file (purchase price, down payment, loan amount and program), or the loan amount on file when no scenario is marked as the main one, and 120 days.

    loanstringrequired
    The loan, as the user says it ("the Garcia file", "412 Elm").
    montonumber
    Approved amount in USD. Omit to use the main scenario, or the loan amount on file.
    expirastring
    Expiration date (YYYY-MM-DD). Omit for 120 days from today.
  • organize_documents
    Documents
    Writes data

    Organizes a loan file's uploaded documents into folders and tags — the Documents tab of the loan summary, which works like Google Drive. Folders: Property, Title, Borrower, Income, Assets, Credit, Other; each document starts in the folder of its section. Use it when the user wants to: move documents to another folder ("move the bank statements on the Garcia file to Assets"), tag or untag them ("tag the W-2s as verified", "remove the urgent tag from the appraisal"), or see what is in a folder or carrying a tag ("what's in the Income folder of the Smith loan?"). With only `loan` (and optionally `folder`) it just lists. Only files that were uploaded show up; archived ones do not. Documents is only what is already on file: requested documents that are still missing are not here (check_documents lists those). This does NOT change the document type, its status or where it shows on the Summary checklist — for that use update_document or adjust_checklist.

    loanstringrequired
    The loan, as the user says it: borrower name, property address or loan number.
    documentsstringnull
    Which documents, as they read on the list or as the user says them ("the W-2s and the paystub", "the appraisal"), or "all". Leave empty to just list.
    move_tostringnull
    Folder to move them to: property, title, borrower, income, assets, credit or other.
    add_tagsany
    Free-text tags to put on them ("verified", "2024").
    remove_tagsany
    Tags to take off them.
    folderstringnull
    Only list what is in this folder.
    tagstringnull
    Only list documents carrying this tag.
  • view_automations
    Communication
    Read-only

    Shows every automation of the account: which are on or off, their cadence in days, when the scheduled jobs run, and the two master switches (email and text messages) that sit above all of them. Use it when the user asks "what runs automatically", "is the document reminder on", "how often do borrowers get reminded", "why is nothing going out", "is test mode on", "who gets the test texts", or before changing one. To turn one automation on/off or change its cadence use set_automation; to turn a whole channel on or off use set_channel; to turn test mode on or off use set_test_mode.

    No parameters.

  • set_automation
    Communication
    Writes data

    Turns an automation on or off, or changes its cadence in days. Use it when the user says "stop reminding borrowers", "turn the document reminder back on", "remind every 5 days instead", or any change to what runs automatically. The automation is whatever the user calls it ("the document reminder"); view_automations lists the exact keys.

    automationstringrequired
    Which automation, as the user says it: the key ("docs_missing_reminder") or words from its name ("document reminder").
    enabledboolean
    true to turn it on, false to turn it off.
    cadence_daysinteger
    Every how many days it fires (for automations with a cadence).
  • set_channel
    Communication
    Writes data

    Turns a whole messaging channel on or off for the entire account: email, text messages (SMS and WhatsApp), or both at once. Use it when the user wants everything to stop or restart, not one automation and not one person: "stop all texts", "pause every email while I am out", "turn messaging back on". While a channel is off, nothing goes out through it — automations included — and whatever the app tries to send is held as blocked so it can be retried later with retry_message. To see how the switches are right now use view_automations; to stop just one automation use set_automation; to stop messaging one person use set_communication_preferences.

    channelstringrequired
    'email' for every email, 'sms' for every text message (SMS and WhatsApp), 'all' for both.
    enabledbooleanrequired
    true turns the channel back on, false turns it off.
  • set_test_mode
    Communication
    Writes data

    Turns test mode on or off for the whole account. While it is on, every email the app would send to a borrower, realtor or anyone else goes to the test addresses instead — one or several, all in the same email (the account email unless others are given) — exactly as the real recipient would get it, with no "test" mark. SMS go to the test phone numbers when there are any (same text the borrower would get), and are held when there are none; WhatsApp is always held. Nothing reaches the real recipients. Use it when the user says "send everything to me while I test", "I want to see what the borrower gets", "put it in test mode", "also send the tests to german@…", "send the test texts to my cell +1 305…", "remove X from the test emails", "stop sending test texts to my phone", and to end it: "stop test mode", "go live again", "send to the real people now". Turning it off does not resend by itself: held texts show in view_delivery and go out with retry_message. It is NOT for pausing messaging (that is set_channel) nor for one person (set_communication_preferences). To check whether it is on use view_automations. With enabled false plus emails/phones it saves those lists for next time without turning anything on ("keep my cell as test phone for later"); turning it off also keeps the lists in use.

    enabledbooleanrequired
    true turns test mode on, false turns it off.
    emailsarray
    The FULL list of addresses every email goes to while test mode is on (it replaces the saved list: to add one, send the current ones plus the new one — view_automations shows them). Leave it out to use the lists saved for next time, or the account email. With enabled false they are saved for next time, not used.
    emailstring
    Deprecated: a single address. Prefer `emails`.
    phonesarray
    The FULL list of phone numbers every SMS goes to while test mode is on, as the user says them ("(305) 301-1517", "305 301 1517", "+1 305…"); US numbers without +1 are fine. It replaces the saved list: send [] to stop test texts (they are then held). Leave it out to keep the saved phones. With enabled false they are saved for next time, not used.
  • set_email_signature
    Account
    Writes data

    Reads or changes the asking person's own email signature — the lines that close every email sent in their name (document requests, reminders, automatic updates). Each teammate has their own: the loan officer signs as the loan officer, an assistant as herself. Use it when the user says "change my signature", "sign my emails as…", "add my website under my name", "what is my signature?", "put my signature back to the default". Call it with no signature to read it. An empty text or null goes back to the default: full name, phone and NMLS from the profile (those change with update_profile).

    signatureany
    The new signature, as plain text: one line per line (name, title, phone, website…). Links are written as they are. Omit it to only read the current one; null or "" puts the default back.
  • view_document_templates
    Documents
    Read-only

    Lists the document templates: files (PDF, Word, Excel, images) the team downloads, fills or sends to a client, like the gift letter or the condo questionnaire. Includes the account's own templates and the shared Modellus ones (modellus: true, read-only for accounts). Use it when the user asks "what templates do we have", "send me the gift letter template", or before renaming or deleting one. Each item has a url to open the file and its folder (null when loose). Not for message templates (use view_templates).

    querystring
    Part of the template name or folder, e.g. "gift". Empty lists all.
    catalogstring
    Which library: "account" (default) is this account's own templates plus the read-only Modellus ones; "modellus" is the shared Modellus library every account sees, and only a Modellus superadmin can change it. Use "modellus" only when a superadmin is managing the shared templates.
  • rename_document_template
    Documents
    Writes data

    Renames one of the account's document templates (a file like the gift letter or the condo questionnaire). Use it when the user says "rename the gift letter template to Gift letter 2026". Modellus templates cannot be renamed from an account. Not for message templates (use edit_template).

    templatestringrequired
    The template as the user says it: its name or part of it.
    new_namestringrequired
    The new name.
    catalogstring
    Which library: "account" (default) is this account's own templates plus the read-only Modellus ones; "modellus" is the shared Modellus library every account sees, and only a Modellus superadmin can change it. Use "modellus" only when a superadmin is managing the shared templates.
  • set_document_template_folder
    Documents
    Writes data

    Puts one of the account's document templates (a file like the gift letter or the condo questionnaire) into a folder of Templates › Documents, creating the folder if it does not exist yet, or takes it out of its folder. Use it when the user says "put the gift letter in the Assets folder", "make a Condo folder with the questionnaire" or "take the W-9 out of its folder". Modellus templates cannot be moved from an account. To rename a whole folder use rename_document_template_folder.

    templatestringrequired
    The template as the user says it: its name or part of it.
    folderstringrequired
    The folder as the user says it ("assets", "the Tax forms folder"). An existing folder is reused; a new name creates it. "none" or an empty string takes the template out of its folder.
    catalogstring
    Which library: "account" (default) is this account's own templates plus the read-only Modellus ones; "modellus" is the shared Modellus library every account sees, and only a Modellus superadmin can change it. Use "modellus" only when a superadmin is managing the shared templates.
  • rename_document_template_folder
    Documents
    Writes data

    Renames a folder of document templates in Templates › Documents: every one of the account's templates in it moves to the new name (if the new name is another existing folder, the two are merged). Use it when the user says "rename the Tax folder to Tax forms". To put a single template in a folder use set_document_template_folder.

    folderstringrequired
    The folder as the user says it ("tax", "the Tax folder").
    new_namestringrequired
    The new folder name.
    catalogstring
    Which library: "account" (default) is this account's own templates plus the read-only Modellus ones; "modellus" is the shared Modellus library every account sees, and only a Modellus superadmin can change it. Use "modellus" only when a superadmin is managing the shared templates.
  • view_google_drive
    Account
    Read-only

    Shows whether Google Drive is connected and actually answering, whose account it is, whether it is switched on for documents, and the file-naming style learned from the drive. Use it when the user asks if Google Drive is connected, why Modellus cannot see their Drive, or right after they finish the Google Drive authorization. To connect use connect_google_drive, to drop it disconnect_google_drive, to switch it on or off for documents set_drive_for_documents.

    No parameters.

  • connect_google_drive
    Account
    Writes data

    Starts connecting the user's Google Drive so Modellus can READ the folders where they keep their loan files. Use it when the user asks to connect Google Drive, to let Modellus see their Drive folders, or when list_google_drive_files or scan_drive_naming says Google Drive is not connected. It returns an authorization link: show it, and tell them to open it, sign in with Google and accept. Then call view_google_drive to confirm it worked. This is separate from their Gmail connection. Modellus only ever reads; it never changes, moves or deletes anything in Google Drive. For OneDrive use connect_onedrive instead.

    No parameters.

  • disconnect_google_drive
    Account
    Writes data

    Disconnects Google Drive: Modellus stops being able to read the user's Drive files. Use it when they ask to disconnect Google Drive, revoke that access, or connect a different Google account (disconnect first, then connect_google_drive). Nothing in Google Drive is changed or deleted. To keep it connected but stop using it for documents, use set_drive_for_documents instead.

    No parameters.

  • list_google_drive_files
    archivos
    Read-only

    Lists what is inside the user's Google Drive: the top level when nothing is given, the contents of a folder, or everything whose name matches a search. Use it when the user asks what is in their Google Drive, what is in one of its folders, or where a file is. Name the folder the way they do ("Loans", "Work/Loans"), never an id. To read a file use read_google_drive_file. For OneDrive use list_onedrive_files. If it says Google Drive is not connected, use connect_google_drive.

    folderstring
    The folder to open, by path ("Work/Loans") or by name ("Loans"). Leave it out for the top level.
    searchstring
    Look for files and folders whose name contains this, anywhere in the drive. Ignores folder.
    folders_onlyboolean
  • read_google_drive_file
    archivos
    Read-only

    Reads what is inside a file in the user's Google Drive: a Google Sheet or CSV comes back as rows, a Google Doc or text file as text. PDFs and photos come back with a link and the reason they could not be read. Use it when the user asks what a file in their Google Drive says. Name the file as they do ("Smith prequal", "Loans/Smith/notes.txt"); use list_google_drive_files first when unsure it exists. Reading never changes the file. For OneDrive use read_onedrive_file.

    filestringrequired
    The file, by path or just by name, as the user says it.
  • set_drive_for_documents
    Account
    Writes data

    Turns a connected drive on or off for documents — the "Use for documents" switch in Settings → Connections. Off means the drive stays connected but Modellus stops reading and scanning it. Use it when the user says to only use OneDrive (switch Google Drive off), only Google Drive, to stop or start using one of them for documents, or when a drive tool says the drive is switched off. Nothing in the drive itself changes. To remove the connection entirely use disconnect_onedrive or disconnect_google_drive.

    drivestringrequired
    Which drive the user means.
    usebooleanrequired
    True to use it for documents, false to stop.
  • scan_drive_naming
    archivos
    Writes data

    Scans the loan folders in the user's connected drive (OneDrive or Google Drive) and learns how they name their files — the order of last name, document type and date, the separator, capitals and date format — from the real file names, then saves it so Modellus names files the same way. Use it when the user asks to scan their drive, learn or check their file naming, or "name files like I do". Takes up to a minute: it reads the most recent loan folders only. It never changes anything in the drive. Answer with the pattern and a few of the example names. To just see what was learned before, use view_onedrive or view_google_drive.

    drivestring
    Which drive to scan. Leave it out to use the one that is connected and switched on for documents (OneDrive first).
    folderstring
    The work folder that holds the loan folders. Leave it out: it is "TEAMGM WORKFOLDERS" (or the top of the drive if that does not exist). Only pass it when the user names another one.
  • delete_document_template
    Documents
    Writes data

    Deletes one of the account's document templates (a file like the gift letter or the condo questionnaire), with its file. Use it when the user says "delete the old gift letter template". Modellus templates cannot be deleted from an account. Not for message templates or condo questionnaires built in the app.

    templatestringrequired
    The template as the user says it: its name or part of it.
    catalogstring
    Which library: "account" (default) is this account's own templates plus the read-only Modellus ones; "modellus" is the shared Modellus library every account sees, and only a Modellus superadmin can change it. Use "modellus" only when a superadmin is managing the shared templates.
  • save_document_template
    Documents
    Writes data

    Saves a file the user attached in the chat as a document template (like a gift letter or a condo questionnaire), so the team can reuse it from Templates › Documents. Use it when the user uploads a file and says "save this as our gift letter template". The file_path comes from the "[Attached document: … — path: …]" note in the conversation — never invent it, and never ask the user for it. Not for filing a document into a loan's checklist (use attach_document).

    file_pathstringrequired
    The storage path from the "[Attached document: … — path: …]" note of the attached file in this conversation.
    file_namestring
    The original file name, from the same note.
    namestring
    The template name, e.g. "Gift letter". Defaults to the file name.
    folderstring
    The folder to save it in, as the user says it ("the Assets folder"). An existing folder is reused; a new name creates it.
    catalogstring
    Which library: "account" (default) is this account's own templates plus the read-only Modellus ones; "modellus" is the shared Modellus library every account sees, and only a Modellus superadmin can change it. Use "modellus" only when a superadmin is managing the shared templates.
  • view_delivery
    Communication
    Read-only

    Shows the outgoing messages that did not make it: the ones the provider rejected after every retry, and the ones held back because the account had that channel turned off. Also reports how many are waiting in the queue and how the master switches are. Use it when the user asks "did that email go out", "why has Maria not heard from me", "is anything stuck", "what failed", or when a message they expected never arrived. To send one again use retry_message; to turn a channel back on use set_channel.

    limiteinteger
    How many to list, newest first. Default 20.
  • retry_message
    Communication
    Writes data

    Sends a failed or blocked outgoing message again: it goes back into the queue and leaves within a minute. Use it after view_delivery shows something stuck and the user says "try again", "resend that", "send them all again". Pass the message id from view_delivery, or all=true to retry every stuck message at once. A message cancelled because the person opted out is never retried.

    message_idinteger
    The id view_delivery gave for that message.
    allboolean
    true = retry every stuck message of the account.
  • create_campaign
    Communication
    Writes data

    Creates a marketing campaign DRAFT: one promotional email or text to a group of contacts (Marketing tab). Use it when the user wants to send a newsletter, promo, rate update or announcement to many people at once — "email all my realtors about the new program", "text the borrowers of closed loans". It sends NOTHING: it saves the draft and returns how many people it would reach. Show that preview and ask before calling send_campaign. The body can use {{first_name}}, {{last_name}}, {{full_name}}. Opted-out contacts are skipped automatically (by SMS, anyone who replied STOP); texts go to everyone else. For a message to ONE person use send_message instead.

    nombrestringrequired
    Campaign name ("October rate update").
    canalstring
    Always email: text campaigns are off (the texting number is registered for loan updates only).
    asuntostring
    Email subject. Required to send an email.
    cuerpostring
    The message text, plain text with blank lines between paragraphs.
    audienciaobject
    Who gets it. Any mix; a contact matching several parts gets it once.
  • update_campaign
    Communication
    Writes data

    Changes a marketing campaign that has NOT been sent yet: its name, channel, subject, text or audience. Use it when the user says "change the subject of the October campaign", "also include title companies", "remove the tag", "make it a text instead". Each audience part you pass REPLACES that part (pass the full list of contact types, not only the new one); parts you omit stay. The text can use {{first_name}}, {{last_name}}, {{full_name}}. A sent campaign cannot be changed — create a new one.

    campanastringrequired
    Which campaign: its name or id.
    nuevo_nombrestring
    Only to rename it.
    canalstring
    asuntostring
    cuerpostring
    audienciaobject
  • preview_campaign
    Communication
    Read-only

    Shows who a marketing campaign would reach before sending it: how many people, the first names, how many are left out (unsubscribed, no email or phone) and how the message reads for the first person. ALWAYS call it and show the result before send_campaign, and whenever the user asks "who gets it?" or "how many?". Pass `campana` for a saved campaign, or `borrador` to preview an idea before creating it (nothing is saved). Sends nothing.

    campanastring
    Which saved campaign: its name or id.
    borradorobject
    An unsaved campaign to preview as is. Nothing is saved.
  • send_campaign
    Communication
    Writes data

    Sends a marketing campaign to its whole audience. It reaches real people and cannot be undone, so call it ONLY after you showed the preview_campaign result (how many and who) in this conversation AND the user explicitly said yes to sending it. Never call it in the same turn you created or changed the campaign. Emails leave spaced out, a few per minute, so totals grow over the next minutes; check them with view_campaigns. Sending twice never repeats a message to anyone.

    campanastringrequired
    Which campaign: its name or id.
    confirmadobooleanrequired
    true only when the user saw the preview and said to send it.
  • send_campaign_test
    Communication
    Writes data

    Sends ONE copy of a marketing campaign only to the person using the app (their own email, or their own phone for a text campaign), marked [Test], so they can see how it looks before sending it for real. It reaches nobody else, does not change the campaign and does not count in its totals. Use it when the user says "send me a test", "let me see it in my inbox" or similar. The campaign must be saved first (create_campaign). One test per campaign per minute.

    campanastringrequired
    Which campaign: its name or id.
  • view_campaigns
    Communication
    Read-only

    Lists the marketing campaigns (drafts and sent) with their totals: recipients, sent, failed, pending and opened. Use it when the user asks "how did the newsletter do?", "what campaigns do I have?", "how many opened it?". Pass a name to see only that one.

    campanastring
    Only this campaign: its name or id.
  • delete_campaign
    Communication
    Writes data

    Deletes a marketing campaign that was never sent. Use it when the user says "delete the draft", "forget the October campaign". A sent campaign stays, with its totals.

    campanastringrequired
    Which campaign: its name or id.
  • view_calendar
    Tasks
    Read-only

    Shows the calendar for a SPECIFIC period — one day, one week, one month — with the tasks, the critical loan dates and the day notes that fall in it, grouped day by day, plus the link to that same view of the calendar screen. Use it when the user names a period instead of asking what is pending: "what does the week of the 15th look like", "show me October", "what do I have on Tuesday", "open the calendar on the week view", "how does next month look". For the plain to-do list ("what is overdue", "what is pending") use view_tasks; to create or close a task use save_task; to change a loan date use update_loan; to write, rewrite or remove a note on a day use save_day_note.

    viewanyrequired
    Which view of the calendar: 'day', 'week' (Monday to Sunday), 'month', or 'agenda' (the month as a plain list of what is coming). Null means 'week'.
    datestringnullrequired
    The day to center the view on, as YYYY-MM-DD. For a week, any day inside it; for a month, any day of it. Null means today.
  • view_tasks
    Tasks
    Read-only

    Lists tasks AND the critical loan dates falling in the same window — closings, commitment dates, and rate lock, credit or pre-approval expirations. Use it when the user asks "what do I have today", "what is on my calendar this week", "what is overdue", "what is closing soon", "is any lock about to expire", or wants the to-dos of one loan, one contact, one borrower, or one team member. Filters combine: due window, loan or contact as a phrase ("the Garcia file", "Maria"), borrower ("everything for Maria Garcia": her own tasks AND the ones on her loans), assignee ("me", a name, an email). By default it shows pending tasks only; ask for done or cancelled explicitly. It also returns the sections the list is grouped into and which section each task is in. To create or change a task use save_task; to change the sections themselves use set_task_sections; to change a loan date use update_loan.

    duestring
    Due window: 'today' (due today or earlier), 'overdue' (past due), 'week' (next 7 days), 'all'. Default 'all'.
    statusstring
    Which tasks. Default 'pending'.
    loanstring
    Only tasks of this loan, as the user says it.
    contactstring
    Only tasks about this person, as the user says it.
    borrowerstring
    Only tasks of this borrower, as the user says it: the tasks tied to the person AND the ones on any of their loans. It is what the Borrower grouping of the Tasks screen shows per group.
    assigneestring
    Only tasks assigned to this member: "me", a name or email.
    sectionstring
    Only tasks in this section of the list, by name. Use "none" for the ones that are not in any section.
    loan_datesboolean
    Whether to also return the critical loan dates in the window (closing, commitment, lock / credit / pre-approval expiration). Default true. Set false when the user asks strictly for to-dos.
  • save_task
    Tasks
    Writes data

    Creates or updates a task. Use it when the user wants to remember to do something ("remind me to call Maria on Friday"), completes one ("done with the CD review"), cancels one, edits its title, due date or details, adds or checks off subtasks, ties it to a loan or contact, assigns it to a team member, moves it into or out of a section, or reorders it — to the top or bottom of its list, or right above or below another task ("put the appraisal call under the CD review"), which is what dragging a card by its grip does. To create, give a title; to change an existing one, name it by its id or by words from its title. To list tasks use view_tasks; to delete one for good use delete_task; to create, rename or reorder the sections themselves use set_task_sections.

    taskstring
    The existing task to change: its id, or words from its title. Leave empty to create a new one.
    titlestring
    The task title. Required when creating; renames when editing.
    descriptionstring
    Longer detail.
    duestring
    When it is due: ISO (YYYY-MM-DD) or "today"/"tomorrow"/"yesterday". 'none' clears it.
    statusstring
    Set to 'done' to complete, 'cancelled' to cancel, 'pending' to reopen.
    subtasksarray
    Replaces the whole subtask list. To add some, use add_subtasks.
    add_subtasksarray
    Subtasks to append, unchecked.
    check_subtaskstring
    Words from one subtask to mark as done.
    loanstring
    The loan this task is about, as the user says it — a borrower name, a property address, a loan number, or the file id. Never guess: if no file clearly matches, ask which one instead of leaving it out. Use "none" to unlink it.
    contactstring
    The person this task is about, as the user says it.
    assigneestring
    Who should do it: "me", a name, or an email. The person gets a notification in the app unless they assigned it to themselves.
    sectionstring
    Which section of the task list it belongs to, by name ("Follow-ups"). Use "none" to take it out of every section. The section is created if it does not exist yet.
    positionstring
    Where inside its section: 'top' when the user wants it first ("put it at the top"), 'bottom' otherwise. Default: bottom.
    afterstring
    Put it right BELOW this other task — its id, or words from its title. Use it for "move it under the appraisal follow-up". With no section given it lands in that task's section.
    beforestring
    Put it right ABOVE this other task — its id, or words from its title. Use it for "move it above the CD review".
    reviewedboolean
    Marks a task assigned to the caller as already seen, which clears it from their sidebar badge. Use it when they say "got it" or "I already saw that one".
  • delete_task
    Tasks
    Writes data

    Permanently deletes a task. Use it ONLY for one created by mistake or a duplicate. A task that was decided against is NOT deleted — set its status to 'cancelled' with save_task so it stays on the record. Ask the user to confirm before calling with confirmar: true.

    taskstringrequired
    Which task: its id, or words from its title.
    confirmarbooleanrequired
    Must be true to delete. Call it first with false to see which task it would be, show that to the user, and only then call with true.
  • set_task_sections
    Tasks
    Writes data

    Creates, renames, deletes or reorders the sections that group the task list ("Follow-ups", "Closings this week"). Use it when the user wants to organise their tasks by category, says "add a section", "rename that group", "get rid of that section" or "move Closings to the top". Deleting a section does NOT delete its tasks: they go back to being unsectioned. To put a task into a section use save_task with section; to see the sections use view_tasks.

    addarray
    Section names to create, in order. Existing ones are left alone.
    renamearray
    Sections to rename. "from" is the current name, as the user says it.
    removearray
    Sections to delete, by name. Their tasks survive, unsectioned. Confirm with the user first — this cannot be undone.
    orderarray
    The full list of section names in the order they should appear, top first. Anything left out keeps its current place at the end.
  • view_closing_costs
    Pricing
    Read-only

    Shows the fees and percentages this account quotes with: underwriting, processing, appraisal, title, survey, recording, Florida documentary stamps and intangible tax, prepaid interest days, escrow months, and the rates used to estimate property taxes and insurance when there is no real quote yet. Use it when asked "what do we charge for X", "what fees am I quoting", "where does that number come from", or before changing one. To change any of them use set_closing_costs.

    No parameters.

  • set_closing_costs
    Pricing
    Writes data

    Changes the fees and percentages this account quotes with, or puts any of them back to the default. Every quote — the monthly payment, the cash to close, the Loan Estimate — is built from these, so changing one changes every scenario from then on (it does not rewrite quotes already saved). Use it for "raise my underwriting fee to 2,295", "taxes in this county run 1.8%", "we collect 12 months of insurance", "the seller does not pay the deed stamps here", "put the survey back to normal". Only the account owner can change them.

    costosobject
    The fees to change, by name. Only the ones given are touched; dollar amounts in USD and rates in percent (1.5 means 1.5%).
    restablecerarray
    Names of fees to put back to their default value, for "leave it like it was" or "go back to normal".
  • fee_worksheet
    Pricing
    Writes data

    Generates the closing cost worksheet (PDF) that explains the buyer every charge in their quote: the Loan Estimate sections A-H line by line, the D / I / J totals, the monthly payment broken down, and the cash to close with its credits. It uses the main pricing scenario of the file, or the one you name. Use it when someone asks to explain the closing costs to the borrower: "send the Garcia buyer the fee sheet", "what are those 46 thousand, put it on paper", "worksheet for the FHA scenario". It uploads the PDF to the file's documents and returns a download link that lasts 7 days.

    loanstringrequired
    The loan, as the user says it ("the Garcia file", "412 Elm").
    escenariostring
    Which saved scenario to use, by name ("the FHA one", "30 year at 6.875"). Omit to use the one marked as the main scenario.
  • price_scenario
    Pricing
    Read-only

    Prices a purchase without saving anything: the monthly payment broken down (principal and interest, taxes, insurance, mortgage insurance, HOA), the cash to close, the Loan Estimate by section, the APR and — when a file is given — the housing and debt-to-income ratios against the program's caps. Use it for "price 700k at 7% with 5% down FHA", "what's the payment on 450 at 6.5", "how much would they need to close", "what does it look like with 20% down instead", "run it as conventional". Pass `loan` when the quote is about an existing file so the ratios come out; leave it out for someone who just called to ask. To keep the quote use save_scenario, to see the ones already saved view_scenarios, to compare two use compare_scenarios, and to change the fees it is built from use set_closing_costs.

    purchase_pricenumber
    Purchase price or appraised value, in USD
    down_payment_percentagenumber
    Down payment as a percent of the purchase price
    down_paymentnumber
    Down payment in USD. When both this and the percentage are given, this one wins.
    ratenumber
    Interest rate, in percent (7 means 7%)
    term_monthsinteger
    Loan term in months: 360 for a 30-year
    programstring
    Loan program
    underwritingstring
    Whether the file is approved by the automated system (aus) or underwritten manually. It changes the FHA ratio caps.
    interest_onlyboolean
    Whether the payment is interest only
    credit_scoreinteger
    Representative FICO score, used to pick the MI factor
    hoa_monthlynumber
    HOA dues per month, in USD
    property_taxes_annualnumber
    Yearly property taxes in USD. Leave it out to estimate them from the purchase price.
    hazard_annualnumber
    Yearly hazard insurance in USD. Leave it out to estimate it from the purchase price.
    flood_annualnumber
    Yearly flood insurance in USD
    mi_factornumber
    Yearly mortgage insurance factor, in percent of the loan amount. Leave it out to use the table on file.
    finance_upfront_mipboolean
    FHA only: whether the upfront MIP is rolled into the loan amount (the usual) or paid in cash at closing.
    second_liennumber
    Second lien or HELOC amount, in USD
    second_lien_paymentnumber
    Monthly payment on the second lien, in USD
    origination_pointsnumber
    Loan origination charge, in points (percent of loan amount)
    discount_pointsnumber
    Discount points paid to buy the rate down
    seller_creditnumber
    Seller's credit, in USD
    lender_creditnumber
    Lender credit, in USD
    earnest_moneynumber
    Earnest money already deposited, in USD
    appraisal_paidnumber
    Appraisal fee already paid outside closing, in USD
    hap_creditnumber
    Down payment assistance or HAP, in USD
    heloc_creditnumber
    Money coming from a HELOC, in USD
    reserves_after_closingnumber
    Cash reserves the borrower must keep after closing, in USD
    debts_paid_at_closingnumber
    Credit cards or debts being paid off at closing, in USD
    income_sheetobject
    Income and monthly debts of up to four borrowers, as typed in the Income tab of the calculator
    fee_overridesobject
    Closing-cost settings for this scenario only, on top of the account's. Same keys as set_closing_costs; what is typed here wins.
    ysp_pointsnumber
    Yield spread premium the lender pays, in points of the loan amount. Shown in section A but never charged to the borrower.
    property_addressstring
    Property address
    property_zipstring
    Property ZIP code
    loan_type_labelstring
    Free-text loan type, e.g. "CF30 Conventional 30-Year Fixed Rate"
    prepayment_penaltystring
    Prepayment penalty, e.g. "None" or "3/2/1"
    qualification_typestring
    Agency the loan is qualified under
    helocobject
    HELOC "Symmetry" block of the calculator
    mccobject
    Florida Housing MCC (mortgage credit certificate)
    vacatingobject
    The primary residence the borrower is leaving and will rent out
    loanstring
    The file this quote is about, as the user says it: a borrower name, a property address, a loan number or the file id. Leave it out when there is no file yet — everything but the ratios still comes back.
  • find_loan_programs
    Pricing
    Read-only

    Finds which lenders and programs in the account can take a scenario, and why. Give it whatever is known — credit score, loan amount and value (or the LTV), purpose, occupancy, property type, income documentation, state, DSCR — and it returns the programs that qualify with the reason each one does, the ones that miss by a hair and by how much, and what is still missing to be sure. Use it for "who takes a 590 score on an investment condo", "can anyone do a cash-out on a duplex at 75", "what does Cake need for this one", or before quoting a hard case. It answers from the lender matrices saved in this account plus the rules the book has never broken (no investment over 80 LTV, no FHA on investment, private caps at 70) — it does not price the loan: for the payment and cash to close use price_scenario. This is NOT find_loan: that one opens an existing file by borrower or number, this one matches a scenario against lender matrices and never returns a file. Programs loaded with their full matrix (Bundt Cake) also read DTI, reserves, housing lates, foreclosure/bankruptcy, first-time buyer, foreign national and interest only, and explain their maximum LTV step by step. For an existing file ("find programs for Carlos's loan", "who takes the 412 Elm file") pass `loan`: the scenario is built from that loan's data (purpose, occupancy, property, state, value, amount, FICO, DTI, income documentation), and any other parameter you pass overrides that part ("Carlos's loan but at 700 score").

    loanstring
    An existing loan to take the scenario from, as the user says it: borrower name, property address or loan number. The other parameters, when given, correct what the loan says.
    purposestring
    What the loan is for: purchase, rate & term refi or cash-out.
    credit_scorenumber
    Mid FICO of the borrower, 300 to 850.
    loan_amountnumber
    Loan amount in dollars.
    pricenumber
    Sale price, in dollars. Used with the loan amount for LTV.
    appraised_valuenumber
    Appraised value, in dollars. The LTV uses the lower of this and the price.
    ltvnumber
    LTV as a percentage (80 for 80%), when it is known directly instead of the amount and the value.
    occupancystring
    How the borrower will use the property.
    property_typestring
    What the property is.
    income_verificationstring
    How the income will be proven. Decide it the way the Loan Finder quiz does: W-2 employee → full_docs; self-employed 2+ years whose tax returns show the income → full_docs; self-employed who writes off a lot, or under 2 years → bank_statement if the deposits go into their bank accounts, p_and_l if a CPA signs a P&L; 1099 contractor → form_1099; retired or living off savings → asset_qualification; investment qualified on the rent → dscr (no_ratio if the rent does not cover the payment); nothing to show → no_income. If the user has not said enough to pick, ask.
    statestring
    Two-letter state where the property is, like FL.
    dscrnumber
    Debt service coverage ratio, when the file qualifies on rent.
    dtinumber
    Debt-to-income, as a percentage (43 for 43%).
    reserves_monthsnumber
    Months of reserves the borrower has after closing.
    housing_latesstring
    Worst housing late in the last 12 months: "ninguno" (none or one 30-day), "60" or "90".
    credit_eventstring
    Foreclosure / short sale / deed-in-lieu ("foreclosure") or bankruptcy ("bancarrota"), if any.
    credit_event_months_agonumber
    How long ago the credit event was, as a tier: 36 (3+ years), 24 (2–3), 12 (1–2), 0 (under a year).
    first_time_buyerstring
    First-time buyer: "no", "con_renta" (with rent history) or "sin_renta" (without).
    foreign_nationalboolean
    Foreign national borrower (DSCR files).
    interest_onlyboolean
    Interest-only payment.
    lenderstring
    Narrow it to one lender, as the user says it ("Cake", "the loan store"). Leave it out to look at every lender in the account.
  • view_lenders
    Pricing
    Read-only

    Shows the account's lender catalog: every lender with its programs, the qualifying parameters of each one (family, minimum FICO, maximum LTV, DSCR, loan amounts, states), the stars and latest reviews loan officers gave it, and the account executive(s) for that lender found in this account's contacts, with phone and email. Use it for "who is my AE at Cake?", "what do people say about Deephaven?", and when the user asks "which lenders do we have?", "what does Cake take?", "what are Cake's programs", "how did the team rate Windsor", or before changing a matrix — and after a search comes back empty, to check what is actually saved. With `lender` it narrows to one by a flexible name match. To add or change anything here use save_lender, save_program or rate_lender; to match a scenario against it use find_loan_programs.

    lenderstring
    One lender, as the user says it ("cake", "the loan store"). Omit for the whole catalog.
    catalogstring
    "all" (default): this account's lenders plus the shared Modellus catalog. "modellus": only the shared catalog, which is what a superadmin reviews.
    include_inactiveboolean
    Also show the lenders and programs that were turned off. Off by default: the search only looks at what is active.
  • save_lender
    Pricing
    Writes data

    Adds a lender to the account catalog, or updates one that is already there. Use it when the user says "add Cake", "we started working with The Loan Store", "Windsor's AE is Maria, 305-555-1234", "stop showing Geo Funding in the finder" (active: false) or "rename Cake to Cake Mortgage Corp" (new_name). The name is written as people say it: if the lender already exists under another spelling it is updated, not duplicated, and the fields left out keep their value. This saves WHO the lender is — its qualifying matrix (FICO, LTV, DSCR, states) is a program and goes in save_program.

    namestringrequired
    The lender, as the user says it ("Cake", "The Loan Store").
    new_namestring
    Only to rename the lender itself.
    catalogstring
    Where to write: "account" (default) is this account's own catalog; "modellus" is the shared Modellus catalog every account searches against, and only a Modellus superadmin can write it. Use "modellus" only when a superadmin is editing the public lender matrices.
    activeboolean
    Turn it off to keep it out of the finder without losing its programs, its reviews or the loans already closed with it.
    contactstring
    Account executive or contact person at the lender.
    phonestring
    Phone for that contact.
    emailstring
    Email for that contact.
    notesstring
    What the team wants on record about this lender ("slow on conditions", "great on condos").
  • save_program
    Pricing
    Writes data

    Adds a program to a lender, or updates the one already saved, with its qualifying matrix. Use it whenever the user dictates what a lender takes: "Cake's Funnel Cake goes down to 620 FICO and 85 LTV", "their DSCR program needs 1.0 and only in FL and GA", "The Loan Store caps investment at 75". This is what makes find_loan_programs able to answer at all — a lender with no program is never matched. The lender is written as people say it and is created on the spot if it is not in the catalog yet. Anything left out of the matrix keeps its saved value, so changing one number does not wipe the rest. Read what is saved first with view_lenders when you are updating rather than capturing.

    lenderstringrequired
    The lender this program belongs to, as the user says it ("Cake"). Created if it does not exist yet.
    namestringrequired
    The program, as the lender calls it ("Funnel Cake", "DSCR 30Y"). If the lender only has one, something like "Standard" works.
    new_namestring
    Only to rename the program.
    catalogstring
    Where to write: "account" (default) is this account's own catalog; "modellus" is the shared Modellus catalog every account searches against, and only a Modellus superadmin can write it. Use "modellus" only when a superadmin is editing the public lender matrices.
    activeboolean
    Turn it off to stop matching against it.
    matrixobjectrequired
    The qualifying parameters, all optional — send only what is known. familia: product family (conventional, fha, va, jumbo, non_qm, private…). propositos: purchase / refi_rate_term / refi_cash_out. ocupaciones: primary / second_home / investment. tipos_de_propiedad: single_family, condo, multi_unit… verificacion_de_ingresos: full_docs, bank_statement, dscr… fico_minimo: minimum score. ltv_maximo and ltv_maximo_inversion: LTV caps as percentages (85 for 85%). dscr_minimo: minimum coverage ratio. monto_minimo / monto_maximo: loan amount in dollars. estados: two-letter states it lends in. notas: anything the team wants on record about this program.
    cleararray
    Matrix fields to wipe, so they stop filtering and go back to "unverified": use it when the user says a limit no longer applies or was captured wrong ("drop the FICO minimum on Funnel Cake", "clear the states"). Anything named here wins over the same key in matrix.
  • admin_list_users
    Admin
    Read-only

    Modellus superadmin only. Lists every user of Modellus with the account they work in, their role, when they signed up and last signed in, whether they are suspended, and how many loans and contacts their account holds. Use it for "who signed up this week", "how many users do we have", "is Cynthia still active", "which accounts have no loans". Filter with search (email or name). Each user comes with a panel link where a superadmin can also sign in as them.

    searchstring
    Part of an email or a name, as the user says it.
  • admin_update_user
    Admin
    Writes data

    Modellus superadmin only. Changes a user's name, or their role inside the account they were invited to (assistant or loan_officer — an account owner is always owner). Use it for "rename luis+test to Luis Test", "make Cynthia a loan officer in Germán's account". The user is named as people say it: email or name.

    userstringrequired
    Email or name of the user.
    namestring
    The new display name.
    rolestring
    Their role inside the account they were invited to.
  • admin_set_user_access
    Admin
    Writes data

    Modellus superadmin only. Suspends a user (they cannot sign in; nothing is deleted), reactivates them, or emails them a link to set a new password. Use it for "suspend luis+test", "let Archana back in", "send Cynthia a password reset". Never ask for or type a password.

    userstringrequired
    Email or name of the user.
    actionstringrequired
    What to do with their access.
  • admin_list_accounts
    Admin
    Read-only

    Modellus superadmin only. Lists every client account (one per loan officer who owns an account) with its usage over the last 30 days: team size, last sign-in and last activity, active users in 7 and 30 days, chat messages, loans created by the team, imported (Arive sync, migration) and touched, emails/SMS sent, tasks done, documents received, and a usage status (heavy, light, inactive). Use it for "who is using Modellus the most", "which clients stopped using it", "how is Laventi doing", "inactive accounts this month". Rule: Heavy: active in the last 7 days and 100+ actions in 30 days. Inactive: nothing in 14+ days. Light: everything in between. Actions = tracked actions + chat messages + loans created by the team + emails/SMS sent + tasks done + documents received (loans imported by the Arive sync or the migration, and loans touched, are shown but not counted).

    statusstring
    Only accounts with this usage status.
    searchstring
    Part of the company, owner name or email, as the user says it.
    sortstring
    Order of the list. Default: usage, heaviest first.
  • admin_create_account
    Admin
    Writes data

    Modellus superadmin only. Opens a new client account for a loan officer: creates their user, sets the company name and emails them an invitation link to sign in. Use it for "create an account for Jane Doe at Laventi Mortgage, jane@laventi.com", "open Modellus for this new client". Ask for any of the four fields that is missing; never invent an email. Fails if the email already has an account.

    first_namestringrequired
    Owner first name.
    last_namestringrequired
    Owner last name.
    emailstringrequired
    Owner email; the invitation goes here.
    company_namestringrequired
    The company or team name the account works under.
  • email_lender_aes
    Communication
    Writes data

    Emails account executives (AEs) at wholesale lenders from the Loan Finder: one separate email per AE, with their first name in the greeting, sent from the user's mailbox and spaced 20-45 seconds apart so it never looks like a blast. Use it for "email all the AEs at Cake and Windsor about this scenario", "ask John at UWM if he has a DSCR program", "send this loan to every AE at The Loan Store". Pick lenders (every AE with an email at that lender) and/or AEs by name. With `loan`, the body is pre-filled with that loan's scenario (amount, LTV, FICO, state, purpose; never the borrower's name or address). IMPORTANT: two steps — call it first WITHOUT confirm to get the draft and the recipient list, show them and ask for approval, then call again with the same arguments plus confirm=true. Write {first_name} where each AE's name goes. Their replies show up per lender in the Loan Finder (view_lender_replies). Test mode applies.

    lendersarray
    Lenders whose AEs all get it, as the user says them ("cake", "uwm").
    aesarray
    Specific AEs: name, email or contact id.
    subjectstring
    Subject line. Left out, a default one.
    bodystring
    The email text. Use {first_name} for each AE's first name. Left out, a default ask (with the loan scenario when `loan` is given).
    loanstring
    The loan this is about (borrower, address or loan number), to pre-fill the scenario.
    confirmboolean
    false/omitted returns the draft; true queues the emails.
  • view_lender_replies
    Pricing
    Writes data

    Shows what account executives answered to the Loan Finder emails (email_lender_aes), newest first: who, when, what they wrote, and the guidelines the AI read from it (min FICO, max LTV, DSCR, property types, states) with whether they were already added to the Loan Finder. Use it for "did any AE answer?", "what did Cake say?", "show me the replies from UWM". Leave `lender` out for every lender. With mark_read=true the ones shown stop counting as new (the bell on each lender card). To add a reply's guidelines to the Loan Finder use apply_ae_reply.

    lenderstring
    The lender, as the user says it. Left out, all.
    mark_readboolean
    true marks the shown replies as read.
  • apply_ae_reply
    Pricing
    Writes data

    Adds what an account executive answered (their guidelines: min FICO, max LTV, DSCR, loan limits, property types, states, notes) to the Loan Finder for this account, so the lender card shows it and warns when a scenario breaks it. Use it after view_lender_replies when the user says "add that to the loan finder", "save what John from Cake said", "yes, use UWM's answer". Pick the reply by reply_id, or by lender and/or AE (the newest reply with guidelines). Any field you pass corrects what the AI read before saving. Applying the same reply twice keeps one entry. It never changes the lender's matrices or the Modellus catalog.

    reply_idinteger
    From view_lender_replies.
    lenderstring
    The lender, as the user says it.
    aestring
    The AE's name.
    min_ficointeger
    max_ltvnumber
    min_dscrnumber
    min_amountnumber
    max_amountnumber
    property_typesarray
    statesarray
    Two-letter codes.
    notesstring
  • rate_lender
    Pricing
    Writes data

    Rates a lender from 1 to 5 stars on behalf of the person speaking, with an optional comment about how it went. Use it when the user says "Cake was a nightmare, 2 stars", "give Windsor a 5, they closed in 12 days", "drop The Loan Store to 3 — they keep re-pulling conditions". The stars are per person, so this replaces that person's previous rating of the lender and does not touch anyone else's; the average is what orders the results in find_loan_programs. To see what the team has rated, use view_lenders. Needs a signed-in person: a star belongs to someone, so this one cannot be called with an API key.

    lenderstringrequired
    The lender, as the user says it ("cake", "windsor").
    starsintegerrequired
    1 to 5. 1 is "never again", 5 is "send them everything".
    commentstring
    What happened with them, in the user's words. Left out, the previous comment stays; send an empty string to clear it.
  • import_lender_book
    Pricing
    Writes data

    Loads the lender book that ships with the app into this account's catalog: 23 lenders and the product families each one has actually closed, taken from the Loan Finder sheet and from the loan book. Use it when the catalog is empty or nearly empty and the user says "load the lender book", "seed the lenders", "fill the loan finder", or when a search comes back with nothing because there are no lenders saved — check with view_lenders first. Safe to run more than once: lenders and programs already saved are left exactly as they are, and only the parameters that are still missing get written, so a matrix someone captured by hand is never overwritten. It does NOT bring FICO or LTV limits: no lender matrix was ever published in the source documents, so those stay unverified until someone dictates them with save_program.

    previewboolean
    true to only say what the book contains, without writing anything.
  • view_quiz
    equipo
    Read-only

    Shows the public pre-qual quiz of this account: the URL to share with borrowers and realtors, whether it is on, what it says, and how many pre-qualifications have come in through it. Use it when the user asks "what is my quiz link", "is my quiz on", "how many leads has the quiz brought", "does the quiz email people back", or before changing any of that with set_quiz.

    No parameters.

  • set_quiz
    equipo
    Writes data

    Turns the public pre-qual quiz on or off, changes its link name and the words on it. The quiz is the page a borrower or a realtor fills out alone — it asks about the deal in plain language, runs it against this account's lender programs and tells them how many fit, without naming any lender. Every answer lands as a new pre-qualification in the pipeline. Use it when the user says "turn on my quiz", "put my quiz under maria-garcia", "change what my quiz says", "turn off the quiz". Only the account owner. To see how it is set up and how many leads it has brought, use view_quiz. This is not the sign-up form link — that one is set_join_link, and both pages share the same link name. It also turns on or off the automatic acknowledgment email to whoever finishes the quiz — "email people back when they finish my quiz", "stop the auto-reply on the quiz". That one starts OFF; the alert to the loan officer about a new quiz lead always goes out and has no switch.

    nombrestringnullrequired
    The last part of the URL (/quiz/<name>), as the user says it — it gets cleaned up into a link-safe name. It is the SAME name the sign-up link uses, so changing it moves both pages. Null to leave it as is.
    activobooleannullrequired
    true turns the quiz on, false turns it off. Null leaves it.
    titularstringnullrequired
    Headline at the top of the quiz. Null leaves it as is.
    subtitulostringnullrequired
    The line under the headline. Null leaves it as is.
    cierrestringnullrequired
    What the person reads next to their result, at the end. Null leaves it as is.
    acusebooleannullrequired
    true emails everyone who finishes the quiz and leaves an address, with the same "I will be reaching out shortly" template that goes out when a file moves to to-be-contacted. false stops it. It starts off. Null leaves it as is.
  • save_scenario
    Pricing
    Writes data

    Saves a quote on a file, or changes one already saved, and prices it again. Use it for "save this as FHA 6.5 with seller credit", "keep that one", "update the FHA scenario to 7%", "make the conventional one the main scenario". Give `name` to create a new one and `scenario` to change an existing one; only the fields you pass change, the rest stay as they were. The main scenario is the one the file shows and the one the pre-approval letter is written from, and there is only one per file. To price without saving use price_scenario, to see what is saved view_scenarios, and to put two side by side compare_scenarios.

    purchase_pricenumber
    Purchase price or appraised value, in USD
    down_payment_percentagenumber
    Down payment as a percent of the purchase price
    down_paymentnumber
    Down payment in USD. When both this and the percentage are given, this one wins.
    ratenumber
    Interest rate, in percent (7 means 7%)
    term_monthsinteger
    Loan term in months: 360 for a 30-year
    programstring
    Loan program
    underwritingstring
    Whether the file is approved by the automated system (aus) or underwritten manually. It changes the FHA ratio caps.
    interest_onlyboolean
    Whether the payment is interest only
    credit_scoreinteger
    Representative FICO score, used to pick the MI factor
    hoa_monthlynumber
    HOA dues per month, in USD
    property_taxes_annualnumber
    Yearly property taxes in USD. Leave it out to estimate them from the purchase price.
    hazard_annualnumber
    Yearly hazard insurance in USD. Leave it out to estimate it from the purchase price.
    flood_annualnumber
    Yearly flood insurance in USD
    mi_factornumber
    Yearly mortgage insurance factor, in percent of the loan amount. Leave it out to use the table on file.
    finance_upfront_mipboolean
    FHA only: whether the upfront MIP is rolled into the loan amount (the usual) or paid in cash at closing.
    second_liennumber
    Second lien or HELOC amount, in USD
    second_lien_paymentnumber
    Monthly payment on the second lien, in USD
    origination_pointsnumber
    Loan origination charge, in points (percent of loan amount)
    discount_pointsnumber
    Discount points paid to buy the rate down
    seller_creditnumber
    Seller's credit, in USD
    lender_creditnumber
    Lender credit, in USD
    earnest_moneynumber
    Earnest money already deposited, in USD
    appraisal_paidnumber
    Appraisal fee already paid outside closing, in USD
    hap_creditnumber
    Down payment assistance or HAP, in USD
    heloc_creditnumber
    Money coming from a HELOC, in USD
    reserves_after_closingnumber
    Cash reserves the borrower must keep after closing, in USD
    debts_paid_at_closingnumber
    Credit cards or debts being paid off at closing, in USD
    income_sheetobject
    Income and monthly debts of up to four borrowers, as typed in the Income tab of the calculator
    fee_overridesobject
    Closing-cost settings for this scenario only, on top of the account's. Same keys as set_closing_costs; what is typed here wins.
    ysp_pointsnumber
    Yield spread premium the lender pays, in points of the loan amount. Shown in section A but never charged to the borrower.
    property_addressstring
    Property address
    property_zipstring
    Property ZIP code
    loan_type_labelstring
    Free-text loan type, e.g. "CF30 Conventional 30-Year Fixed Rate"
    prepayment_penaltystring
    Prepayment penalty, e.g. "None" or "3/2/1"
    qualification_typestring
    Agency the loan is qualified under
    helocobject
    HELOC "Symmetry" block of the calculator
    mccobject
    Florida Housing MCC (mortgage credit certificate)
    vacatingobject
    The primary residence the borrower is leaving and will rent out
    loanstring
    The file this quote belongs to, as the user says it: a borrower name, a property address, a loan number or the file id. Leave it out only for a quote taken before there is a file.
    scenariostring
    The saved scenario to change, by its name or its id. Leave it out to save a new one.
    namestring
    What to call it, the way it will be asked for later: "FHA 6.5 with seller credit". Required when saving a new one; renames when changing an existing one.
    principalboolean
    true makes this the main scenario of the file — the one it shows and the one the pre-approval letter uses. The one that was main before stops being it. Only works on a scenario tied to a file.
    cleararray
    Fields to remove from the scenario, by name ("seller_credit"), for "take the seller credit off" or "go back to estimating the taxes". Anything removed goes back to being estimated or to zero.
  • view_scenarios
    Pricing
    Read-only

    Lists the quotes saved on a file, each priced again right now with today's fees — payment, loan amount, cash to close and ratios — and marks which one is the main scenario (the one the file shows and the pre-approval letter uses). Use it for "what did we quote the Garcia file", "what scenarios do we have on this one", "what was the FHA option", or before changing one. Without a file it lists the quotes taken before there was a file. To price a new one use price_scenario, to save or change one save_scenario, and to put two side by side compare_scenarios.

    loanstring
    The file, as the user says it: a borrower name, a property address, a loan number or the file id. Leave it out to see the quotes that are not tied to any file yet.
  • compare_scenarios
    Pricing
    Read-only

    Puts two or three quotes side by side and says how far apart they are: each one with its payment, cash to close and DTI, plus how much more or less every other one is than the first. Use it for "compare 5% down FHA against 20% down conventional", "what if we did the same with two points", "FHA or conventional for this file", "show me 30 vs 15 year". Each scenario is either one already saved (by name) or one described on the spot: what you pass in `changes` is applied on top of the saved one, of `base`, or of the main scenario of the file, so "the same but 20% down" only needs the down payment. To price one on its own use price_scenario, and to keep one save_scenario.

    loanstring
    The file this is about, as the user says it. It brings the income and debts (so the DTI comes out) and its main scenario, which is what "the same but…" starts from.
    baseobject
    The starting point every scenario is built on, when it is not a saved one: price, rate, term, program, credits. Leave it out to start from the file's main scenario.
    scenariosarrayrequired
    The two or three scenarios to compare, in order. The first one is the one the others are measured against.
  • max_purchase_price
    Pricing
    Read-only

    Works out the most expensive house someone can buy: the highest price whose ratios still fit under the program's caps, which of the two ratios caps it, and the payment and cash to close at that price. Use it for "how much can they buy with 8,500 a month", "what is the most he qualifies for", "how much house with 3.5% down FHA", "what price works if she pays off the car". Income and debts can come from a file (`loan`) or be given directly; the rate, the program and the down payment percent are always needed — ask for them instead of guessing. To price a specific price instead, use price_scenario.

    monthly_qualifying_incomenumber
    Total qualifying monthly income of all borrowers, in USD
    monthly_liabilitiesnumber
    Monthly debt payments other than housing, in USD
    programstring
    Loan program
    ratenumber
    Interest rate, in percent (7 means 7%)
    term_monthsinteger
    Loan term in months. Defaults to 360.
    down_payment_percentagenumber
    Down payment as a percent of the purchase price
    underwritingstring
    Whether the file is approved by the automated system (aus) or underwritten manually. It changes the FHA ratio caps.
    credit_scoreinteger
    Representative FICO score, used to pick the MI factor
    hoa_monthlynumber
    HOA dues per month, in USD
    property_taxes_annualnumber
    Yearly property taxes in USD. Leave it out to estimate them from the price, which is what makes sense when the house is not picked yet.
    hazard_annualnumber
    Yearly hazard insurance in USD. Leave it out to estimate it from the price.
    loanstring
    The file to take the monthly income and debts from, as the user says it. Anything passed directly wins over what the file says.
  • calculate_buydown
    Pricing
    Read-only

    Works out a temporary buydown — 3-2-1, 2-1 or 1-0: what the borrower pays each year at the bought-down rate, how much comes out of escrow every month, and the total the seller has to fund at closing. Use it for "what does a 2-1 buydown cost on this", "how much does the seller have to put up", "what would they pay the first year with a 3-2-1", "is the buydown worth it". Pass `loan` to take the loan amount, rate and term from the scenario the file already shows, or give them directly. Remember it does not change the loan: the file still qualifies at the note payment.

    loan_amountnumber
    Loan amount the payments are based on, in USD
    ratenumber
    Note rate, in percent (5.875 means 5.875%)
    term_monthsinteger
    Loan term in months: 360 for a 30-year. Wins over term_years.
    term_yearsinteger
    Loan term in years. Defaults to 30 when neither is given.
    buydown_programstring
    Which temporary buydown: 3-2-1, 2-1 or 1-0
    loanstring
    The file to take the loan amount, rate and term from, as the user says it. Anything passed directly wins over the file.
    scenariostring
    Which saved scenario of that file to use, by name or id. Leave it out to use the main one.
  • calculate_rental_income
    Pricing
    Read-only

    Works out how much rental income can be used to qualify, the way Fannie Mae asks for it: from the Schedule E of the tax return, or from a signed lease at 75% for vacancy. Use it for "what rental income can we use from the duplex", "does the rental cover its own payment", "how much of the rent counts", "run the Schedule E on the investment property". Read the answer as two numbers: what adds to the income, and what a property running at a loss adds to the monthly debts. Pass the result into price_scenario or max_purchase_price as income and liabilities.

    propertiesarrayrequired
    The rental properties to work out, one entry each
  • business_liquidity
    Pricing
    Read-only

    Works out a business's liquidity from its balance sheet (Schedule L of a 1120S or 1065): the current ratio, the quick ratio, and which of the two to read for this kind of business. Use it for "does the business have enough liquidity", "run the current ratio", "can he take the down payment out of the company", "is the business healthy enough to pull money from". A ratio of 1 or better means the business covers what it owes within the year; below that, taking money out to close makes it worse. Say whether the business depends on selling inventory: it decides which ratio counts.

    business_namestring
    Business name, to read the result
    cashnumber
    Cash, in USD
    accounts_receivablenumber
    Trade notes and accounts receivable, in USD
    inventorynumber
    Inventories, in USD
    other_current_assetsnumber
    Other current assets, in USD
    accounts_payablenumber
    Accounts payable, in USD
    short_term_debtnumber
    Mortgages, notes and bonds payable in less than 1 year, in USD
    other_current_liabilitiesnumber
    Other current liabilities, in USD
    inventory_dependentboolean
    Whether the business depends on selling inventory to operate. True points to the quick ratio, false to the current ratio.
  • view_borrower_income
    Pricing
    Read-only

    Shows what a file qualifies with: the monthly qualifying income of each borrower broken down source by source — hourly, salary, W2s, self employed, VOE with its current year and two year averages, rental, unreimbursed expenses — and the debts, saying for each one what counts against the ratio and why (a lease counts with two payments left, an installment under ten payments drops out, a student loan follows the program's rule). Use it for "what are we qualifying them with", "how much income does this file have", "why is that student loan counting $600", "what debts are we counting", "does the co-borrower have income captured". To change any of it use set_borrower_income or set_borrower_debts; to turn it into a payment and a DTI, price_scenario.

    loanstringrequired
    The file, as the user says it: a borrower name, a property address, a loan number or the file id.
    borrowerstring
    Only this borrower, by name ("Maria") or "the co-borrower". Leave it out to see everyone who signs.
  • set_borrower_income
    Pricing
    Writes data

    Captures or corrects a borrower's qualifying income on a file: hourly jobs, fixed amounts per period (salary, Social Security, pension, retirement), two years of W2s, self employed returns, verifications of employment with base pay, overtime, commission and bonus, other monthly income, net rental income and unreimbursed employee expenses. Use it for "she makes $32 an hour, 40 hours guaranteed", "he gets $2,400 every two weeks from Amazon", "her W2s were 68k and 61k", "add $1,850 a month of Social Security", "the VOE is paid through June, base 48,000 year to date". Only the fields you pass change, the rest stay as they were. The income is what makes the DTI come out, so capture it before pricing a file. To see what is captured use view_borrower_income, for the debts use set_borrower_debts, and to price the file price_scenario.

    nombrestring
    Borrower name, shown in the breakdown
    porHoraarray
    Hourly jobs
    periodicosarray
    Fixed amounts per period: salary, Social Security, pension, retirement
    w2object
    Two years of W2s, averaged over 24 months
    selfEmployedarray
    Self employed businesses, two years averaged over 24 months
    voearray
    Verifications of employment with base, overtime, commission and bonus
    otrosarray
    Any other monthly income already stated as a monthly amount
    rentaNetanumber
    Net rental income per month, already calculated. Negative when the property does not cover its own payment.
    gastosNoReembolsadosobject
    Unreimbursed employee expenses, two years averaged over 24 months. They subtract from qualifying income.
    loanstringrequired
    The file, as the user says it: a borrower name, a property address, a loan number or the file id.
    borrowerstring
    Whose income it is, by name ("Maria") or "the co-borrower". Leave it out for the main borrower on the file.
    cleararray
    Income blocks to remove, by name ("rentaNeta", "voe"), for "take the rental income off" or "she does not have that job anymore".
    replaceboolean
    true wipes whatever was captured and leaves only what this call sends. The screen uses it because the form owns the whole block; in conversation leave it out so nothing is lost by accident.
  • set_borrower_debts
    Pricing
    Writes data

    Captures or corrects a borrower's debts on a file — the monthly payments that count against the debt-to-income ratio: credit cards, installment loans, leases, mortgages, student loans and anything else on the credit report. Use it for "she has a $420 car payment with 8 payments left", "add a Navient student loan, 42k balance, no payment showing, in deferment", "the Amex is being paid off at closing", "the truck loan is paid by the business and we have the cancelled checks". Enter the payment as it reads on the credit report: what actually counts is worked out from it — a lease counts even with two payments left, an installment under 10 payments drops out, and a student loan follows the rules of the program on the file. The answer says why each one counts what it counts. To see what is captured use view_borrower_income, for the income set_borrower_income.

    loanstringrequired
    The file, as the user says it: a borrower name, a property address, a loan number or the file id.
    borrowerstring
    Whose debts they are, by name ("Maria") or "the co-borrower". Leave it out for the main borrower on the file.
    debtsarray
    The complete list of debts, replacing whatever was captured. Use it when the whole credit report is being entered or corrected.
    addarray
    Debts to add to the ones already captured, for "she also has a $180 Best Buy card".
    removearray
    Debts to remove, by creditor name ("the Amex"). To keep a debt on file but out of the ratio because it is paid at closing, set seVaAPagarEnElCierre on it instead — that way it still shows, with the reason it does not count.
  • view_dashboard
    Insights
    Read-only

    The home dashboard in numbers: this month's closings and volume against last month, how many new pre-quals came in, how many files sit in each active stage of both pipelines, what is stalled, what closes in the next two weeks, and closings per month for the last six months. Pipeline numbers (stages, stalled, new this month, closing soon) count only OPEN files — the same as the default view of the Loans and Pre-Q tabs: active stages, not archived; "new this month" = created this month and still open. It also carries the day: what expires TODAY, what is already past due and still open, the next seven days one by one, and the notes written for today. Use it when the user asks "how am I doing", "how is business", "give me the numbers", "quick overview", "how does this month look", "what expires today", "what do I have today", "read me today's notes", or wants a general picture before getting specific. For the files in each stage use view_pipeline; to write, rewrite or remove a note for a day use save_day_note; for another day or month use view_calendar; for a different period use production_report; for the week recap use weekly_summary.

    No parameters.

  • production_report
    Insights
    Read-only

    Production report for a period: how many loans closed, total volume, and estimated commission, compared against the previous equivalent period. Use it when the user asks "how did I do this month", "what did I close in Q2", "my production last year", or any question about closings, volume, or commissions over time. For who referred the business use referral_report; for how long stages take use stage_timing_report.

    periodstring
    The period as the user says it: "this month", "last quarter", "Q2 2026", "March", "2025", "last 30 days". Defaults to this month.
  • referral_report
    Insights
    Read-only

    Referral report for a period: which sources brought the business — deals, volume, and conversion per source. Use it when the user asks "who is sending me business", "which realtor referred the most this quarter", "where are my deals coming from", or wants to know whom to thank or nurture. For totals closed use production_report.

    periodstring
    The period as the user says it: "this month", "last quarter", "Q2 2026", "2025", "last 90 days". Defaults to this month.
  • agent_report
    Insights
    Read-only

    Agents & realtors report for a period: for each listing agent, selling agent, realtor or referral source, how many loans CLOSED with them, the volume and the estimated commission — for the period and year to date. Use it when the user asks "which realtors closed the most this month", "how much business did Maria bring this year", "my top listing agents in Q2", "what did I close with Coldwell", or wants to know whom to thank. Pass `contact` to zoom into one person and list their closed files. For deals that ENTERED the pipeline and their conversion use referral_report; for the plain totals use production_report. To fix a compensation % on one of the listed loans use update_loan with datos.compensation_pct. For "my realtors by closings, most recent first" use period "all time" and sort "recent" (on screen it is the Contacts shortcut "Realtors by closings": Roles = Realtor sorted by last closing; find_contact with role "realtor" and sort "last_closing" gives the same list).

    periodstring
    The period as the user says it: "this month", "year to date", "last quarter", "Q2 2026", "March", "2025", or "all time" for everything that ever closed. Defaults to this month.
    sortstring
    How to rank: "volume" (default), "closings" (most deals first) or "recent" (whoever closed most recently first).
    rolestring
    Whom to rank: "realtors" (listing + selling agents together, the default), "listing_agent", "selling_agent" or "referral_source".
    contactstring
    One person, as the user says it ("Maria", "the Coldwell agent"), to get only her numbers and her closed files. Omit for the ranking.
  • reorder_documents
    Documents
    Writes data

    Moves one document (or underwriting condition) to another spot in the loan's checklist: up or down one place, to the top or bottom, or right before / after another document. Use it when the user wants the list in a different order ("put the W-2 first", "move the bank statements below the pay stubs", "send the appraisal to the bottom"). A document moves within its section (Borrower, Income, Subject property, Title, Credit, Assets, Other documents, or the underwriting conditions), because that is what the screen shows together. Pass `section` to move it INTO another section ("put the HOA letter under Subject property", "move that condition to Income") — alone it goes to the bottom of the new section, or combine it with before / after / direction. Name the document the way the user says it; pass document_id when you have it from check_documents.

    loanstringrequired
    The loan, as the user says it ("the Martinez loan", "123 Main St").
    documentstring
    Which document, by name as the user says it ("the W-2", "bank statements", the text of a condition). Not needed with document_id.
    document_idinteger
    The document id, when known (from check_documents).
    directionstring
    'up' / 'down' one place, 'top' / 'bottom' to the ends. Omit when passing before or after.
    beforestring
    Put it right BEFORE this other document (by name).
    afterstring
    Put it right AFTER this other document (by name).
    before_idinteger
    Same as before, by document id (what the drag-and-drop sends).
    after_idinteger
    Same as after, by document id.
    sectionstring
    The section it moves INTO, as the user says it: "income", "subject property", "title", "credit", "assets", "other documents", "borrower" or "conditions". Omit to keep it in its section.
  • adjust_conditions_view
    Documents
    Writes data

    Switches how the underwriting conditions of a loan file are shown: split into their categories (Borrower, Income, Subject property, Title, Credit, Assets, Other) or as one flat list in order. Use it when the user asks to group or ungroup the conditions ("split the conditions by section", "show the conditions as one list", "get rid of the condition sections", "group them by category again"). The choice is remembered for the whole account and applies to every loan file, so it is the same switch they would flip on screen. It does NOT change the order of the conditions — to move one use reorder_documents; to read or change the conditions themselves use view_conditions or update_conditions.

    vistastringrequired
    'sections' splits the conditions by category; 'flat' shows them as one list (the default).
  • stage_timing_report
    Insights
    Read-only

    How long each pipeline stage typically takes, averaged from this account's closed loans, and which active loans are currently taking longer than that typical time. Use it when the user asks "how long does underwriting take me", "where do my loans slow down", "which files are behind schedule", or wants process insights. For a plain list of stalled files (fixed 7-day flag) use view_pipeline.

    No parameters.

  • weekly_summary
    Insights
    Read-only

    A recap of the week, generated on demand: what moved stages this week, which documents came in, what is stalled, what closes in the next two weeks, and overdue tasks. Stalled and closing soon count only OPEN files (what the Loans/Pre-Q tabs show by default: active stages, not archived). Use it when the user asks "give me my weekly summary", "how was my week", "what happened this week", or wants a recap to forward. There is no automatic weekly email: it was removed, so do not offer to schedule or turn one on.

    No parameters.

  • view_permissions
    equipo
    Read-only

    Shows what each role in this account can do (read, edit files, send messages, delete, manage the account) and which columns each role cannot see. Use it when the user asks "what can my assistant do", "why can't I see the rate", "what is hidden from the processor", or before changing access with set_column_access.

    No parameters.

  • set_column_access
    Team
    Writes data

    Hides or shows specific columns for a role (assistant or loan officer), across the lists and the loan file. Use it when the user says "assistants should not see the rate", "hide the credit score from my processor", "let loan officers see compensation again". Only the account owner can do this. To see what is hidden today, use view_permissions.

    rolstringrequired
    Whose access changes. The owner always sees everything.
    esconderarrayrequired
    Column ids to hide from that role. Empty array if none.
    mostrararrayrequired
    Column ids to give back to that role. Empty array if none.
  • view_join_link
    equipo
    Read-only

    Shows the public sign-up link of this account: the URL to put in an email signature or an Instagram bio, whether it is on, and what the page says, how many leads came in through it, and whether those leads get an automatic acknowledgment. Use it when the user asks "what is my link", "give me my sign-up link", "is my public page on", "do my leads get a reply", or before changing it with set_join_link.

    No parameters.

  • set_join_link
    equipo
    Writes data

    Turns the public sign-up link on or off, changes its name (the last part of the URL) and the words on the page. Use it when the user says "turn on my public link", "my link should be maria-garcia", "change the headline", "turn off the sign-up page", "auto-reply to the leads that come in through my link". Only the account owner. To see the current link use view_join_link.

    nombrestringnullrequired
    The last part of the URL (/join/<name>), as the user says it — it gets cleaned up into a link-safe name. Null to leave it as is.
    activobooleannullrequired
    true turns the page on, false turns it off. Null leaves it.
    titularstringnullrequired
    Headline of the page. Null leaves it as is.
    subtitulostringnullrequired
    The line under the headline. Null leaves it as is.
    graciasstringnullrequired
    What the person sees after sending the form. Null leaves it as is.
    acusebooleannullrequired
    true makes every lead who leaves an email get an automatic "I will be reaching out shortly" reply, using the same template as the first-contact email. It is OFF until the user asks for it. Use it for "auto-reply to my leads", "send them a confirmation", "stop emailing them automatically". Null leaves it as is. The alert to the user is always on and is separate from this — this only controls what goes out to the lead.
  • view_team
    Team
    Read-only

    Lists the team of this account: the owner plus every invited assistant, with name, email, and role. Use it when the user asks "who is on my team", "who has access to my account", or before inviting, removing, or changing the role of someone, to confirm who is already in. To change what someone is, use set_teammate_role.

    No parameters.

  • rename_team
    Team
    Writes data

    Renames the team — the name everyone on this account sees at the top of the sidebar (e.g. "Garcia Mortgage Team"). Use it when the owner says "call my team...", "rename the team to...", "our office is called...", or "put back the default team name" (pass null). It does NOT change the owner's own display name — that is update_profile. Only the account owner can do it. To see the current name, use view_profile (team_name).

    nameanyrequired
    The new team name, exactly as they want it shown. null goes back to the default (the owner's name).
  • set_white_label
    Team
    Writes data

    Turns the white label of the app on or off. On: the sidebar shows the company logo instead of Modellus's, for the owner and every teammate. Off: the app shows Modellus again (the company logo stays on the borrower portal either way). Use it when the owner says "put my company logo on the app", "white label", "hide Modellus", "use our brand in the menu", or "go back to the Modellus logo". It needs a company logo first — that one is set with update_profile (company_logo_url) or uploaded in Settings > Company. Only the account owner can do it. To see whether it is on, use view_profile (white_label).

    enabledbooleanrequired
    true shows the company logo in the app; false shows Modellus.
  • invite_teammate
    Team
    Writes data

    Invites a person by email to join this account: they get full day-to-day access (contacts, pipeline, documents) but cannot manage the team or the settings. Only the account owner can do this. Use it when the user says "invite my assistant", "add maria@x.com to my team", "give my processor access", "invite John as a loan officer". The invitation is emailed to them; there is no link to hand out.

    emailstringrequired
    The email of the person to invite, e.g. "maria@gmail.com".
    rolestring
    What they are on the team: "assistant" (default — a processor or assistant helping with the book) or "loan_officer" (another originator working the same pipeline). Only set it if the user says which one.
  • invitation_link
    Team
    Writes data

    Lists the invitations that are still waiting for an answer and, for one person, RESENDS the invitation. Use it when the user says "the invitation never arrived", "resend the invite to maria", "remind my assistant to accept", or asks who has not accepted yet. There is no link to hand out: someone new gets a link inside the email, and someone who already has a modellus account sees the invitation on their own home screen and accepts it there. It also reports whether the account email channel is on: while it is off no invitation email goes out — turn it back on with set_channel. Only the account owner, signed in from their own session.

    personstring
    Who to resend the invitation to — their email or their name, as the user says it ("maria@gmail.com", "Maria"). Leave it out to just see who has not accepted yet, without resending anything.
  • set_teammate_role
    Team
    Writes data

    Changes what someone already on the team is: an assistant (a processor or assistant helping with the book) or a loan officer (another originator working the same pipeline). Only the account owner can do this. Use it when the user says "make Maria a loan officer", "John is my assistant, not an LO", "change Ana's role". The owner's own role cannot be changed.

    memberstringrequired
    The teammate, as the user says it: an email ("maria@gmail.com") or a name ("Maria").
    rolestringrequired
    What they become: "assistant" or "loan_officer". Ask the user if they did not say.
  • remove_teammate
    Team
    Writes data

    Removes an assistant from this account by email or name, revoking their access immediately. Only the account owner can do this. Use it when the user says "remove maria from my team", "revoke access for x@y.com", "my assistant left". The owner cannot be removed.

    memberstringrequired
    The teammate, as the user says it: an email ("maria@gmail.com") or a name ("Maria").
  • sync_birthdays_from_arive
    Arive
    Writes data

    Fills in the borrowers' and co-borrowers' birth dates from Arive for loans that are already in Modellus. Use it when the user asks to bring birthdays from Arive, or when view_upcoming_birthdays looks empty and the account has Arive loans. It works in batches (it pauses between Arive calls) and remembers where it stopped: if the result says remaining > 0, tell the user and run it again to continue. Never overwrites a birth date someone typed by hand. Requires Arive connected.

    limitinteger
    Loans to check in this batch (default 40).
    restartboolean
    true = start again from the first loan instead of where it stopped.
  • view_upcoming_birthdays
    Communication
    Read-only

    Lists the contacts whose birthday falls in the next days (30 by default, today included): name, the date, how many days away, and whether they can get the birthday email (has an email and did not unsubscribe; if not, sin_correo says why: "no_email" or "unsubscribed"). Use it when the user asks "whose birthday is coming up?", "any birthdays this week?" or "who turns a year today?". Birth dates come from the contact card (birth date) and from Arive (sync_birthdays_from_arive).

    daysinteger
    How many days ahead to look (default 30; 0 = only today, 7 = this week).
  • view_birthday_message
    Communication
    Read-only

    Shows the automatic birthday email: whether it is on, its subject and its message. When on, every contact with a birthday today, an email and not unsubscribed gets it once, around 9:30–10:30 am Miami time. Use it when the user asks "is the birthday email on?" or "what does the birthday message say?". Change it with set_birthday_message.

    No parameters.

  • set_birthday_message
    Communication
    Writes data

    Turns the automatic birthday email on or off, and/or changes its subject or message. Use it when the user says "turn on birthday emails", "stop the birthday message", "change the birthday email to say…". The text can use {{first_name}}, {{last_name}} and {{full_name}}. Send only what changes; the rest stays. Only the account owner can change it.

    enabledboolean
    true = on, false = off.
    subjectstring
    New subject line.
    messagestring
    New message body (plain text).
  • send_birthday_message_test
    Communication
    Writes data

    Sends ONE copy of the birthday email only to the person using the app (their own email), marked [Test] and personalized with their name, so they can see how it looks. It reaches nobody else. Use it when the user says "send me the birthday email", "let me see the birthday message". One test per minute.

    No parameters.

  • set_mailbox_uses
    Account
    Writes data

    Turns the two uses of a connected mailbox on or off: EMAILS (its mail is read into the Modellus inbox and it can be sent from) and CONTACTS (it syncs the Google address book — Gmail only, and only one mailbox at a time). Use it when the user says "use my personal Gmail only for contacts", "stop reading my work inbox", "turn emails back on for X", "sync contacts from this one". At least one use must stay on — both off means disconnect_email. Turning EMAILS off removes that mailbox's emails from Modellus (only our copies; nothing in their real mailbox is ever deleted or moved): call first with confirm=false, tell the user how many emails will be removed from Modellus, and call again with confirm=true once they agree. Check view_connected_mailboxes for the current uses.

    addressstringrequired
    The mailbox, as the user says it (its email address).
    emailsboolean
    true = read its mail and allow sending from it.
    contactsboolean
    true = this Gmail syncs the Google address book.
    confirmboolean
    Needed to turn emails off: false (or left out) only counts the emails that would be removed from Modellus.