API & MCP

Everything modellus can do is available through code. The same actions the app uses internally can be called from your program or from another AI.

Authentication

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

curl https://modellus-app.vercel.app/api/v1/resumen_cuenta \
  -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-app.vercel.app/api/mcp

Specification

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

Available actions (101)

  • 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.
  • 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, or the contacts list. 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 (file, loan, rate, contacts, property, title, dates, docs — "expand the property columns"; Loan, Rate, Property and Title exist only on the loan pipeline, since a pre-qual has no property or rate yet), 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 and the grid of cards ("show the loans as cards", "back to the table view") — each list remembers its own, and on a phone it is always cards — changes row density (compact/standard/comfortable), SORTS the list by a column ("sort the loans by amount, biggest first") 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, or contacts.
    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
    How to lay the list out on a desktop screen: 'tabla' is the row table with all the columns, 'tarjetas' is the grid of cards. This is the pair of icons above the list, and it sticks per list. 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
  • view_profile
    Account
    Read-only

    Returns the profile of the person asking: their display name, email, phone, photo, NMLS number, 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", "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, NMLS number, or profile photo. Use it when the user says "change my name to...", "my phone is...", "update my NMLS", "remove my profile picture". 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.
    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.
  • 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 what this account has connected — Arive (the loan origination system) and the user's own email account (Gmail/Outlook) — and whether each one is actually working: its status, when it last worked, and what the last failure said. Use it when the user asks what is connected, where their messages are sent from, why their emails are not going out from their own address, or right after they finish an email authorization to confirm it worked. To test a connection right now use check_integration; to change any of it, use connect_arive, connect_email or disconnect_email. 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.

  • check_integration
    Account
    Writes data

    Tests a connection right now and reports whether it works: Arive (it authenticates and reads a loan) or the connected email account. Use it when the user suspects something is down ("is Arive working?", "my emails are not going out from my address", "check the connection"), or after fixing credentials. If it comes back expired or denied, the fix is connecting it again with connect_arive or connect_email — retrying will not help.

    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. 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.

    providerstringrequired
    Which email provider the user wants to connect.
  • disconnect_email
    Account
    Writes data

    Disconnects the user's own email account, so messages go back out through the generic Modellus sender and their address book is no longer reachable. Use it when the user asks to disconnect, unlink or remove their Gmail/Outlook connection. Messages already in the queue are not affected — they will simply leave from the generic sender.

    No parameters.

  • view_google_contacts
    Account
    Read-only

    Shows the Google Contacts connection: which Google account is linked (name and email), whether it is working, 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 whether Google is connected, why their contacts are not syncing, how the sync is going, or right after they finish the Google authorization. To change any of it: connect_google to connect or reconnect, sync_google_contacts to run a sync now, preview_google_push / push_contacts_to_google to put Modellus contacts into Google, disconnect_google to stop syncing.

    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 permission to manage their contacts; then call view_google_contacts to confirm it worked and to start the first import. This is NOT connect_email: that one is for sending mail from their own address and only reads the address book.

    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 — only if the user already allowed it with push_contacts_to_google — sends changes the other way too. 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

    Says how many Modellus contacts would be CREATED in the user's Google address book, without creating anything. Use it BEFORE push_contacts_to_google, and whenever the user asks how many of their contacts are missing from Google or what would happen if they turned the sync both ways. Always show the number to the user and let them decide — this writes into their personal address book, so it is their call, not a side effect of connecting.

    No parameters.

  • push_contacts_to_google
    Contacts
    Writes data

    Creates the Modellus contacts that are missing from the user's Google address book and keeps changes flowing that way from then on, writing the Modellus contact id into a Google custom field so nothing is ever duplicated. Call preview_google_push FIRST and only call this once the user has SEEN how many contacts would be created and said yes — it writes into their personal address book. 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 when the user asks to stop writing to Google (what is already there stays).

    stopbooleanrequired
    True to STOP pushing Modellus contacts into Google from now on. Nothing already in Google is removed. False to start or continue.
  • 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 and key data; when few match, it includes their latest activity.

    querystring
    Free text: name, email, phone or fragment. Omit to browse by role or tag.
    rolestring
    Only contacts with this role, e.g. "realtor" or "past_client".
    tagstring
    Only contacts carrying this tag.
    limitinteger
    Max results, default 10.
  • 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, and send an empty list to clear them all. Any other field takes an empty string to clear it ("he has no company"). What you do not send stays as it was. 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, text or WhatsApp sent to that contact is copied to their assistant.

    idinteger
    The contact id, when updating someone find_contact already returned.
    namestring
    Full name. Required when creating.
    emailstring
    phonestring
    Any format; stored as E.164, US +1 assumed for 10 digits.
    rolesarray
    Business roles, e.g. ["realtor", "referral_source"]. Replaces the list.
    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
    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 text and WhatsApp sent to the contact. Same format as phone; stored as E.164.
    create_anywayboolean
    Set true ONLY after the user confirmed the probable duplicate is a different person.
  • 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. The second contact is 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, 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).

    batch_idstringrequired
    The batch id the review step returned.
    treat_duplicates_asstring
    Override for rows flagged as probable duplicates. Default: each row's suggestion.
  • 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.
  • 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.

    contactostringrequired
    Who, as the user says it: name, email or phone fragment.
    emailboolean
    true = they accept email, false = do not email them.
    smsboolean
    true = they accept texts, false = do not text them.
  • 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, who they belong to, how many days each has been in its current stage, and which ones are stalled (more than 7 days in an active stage). Use it when asked "how does my pipeline look", "what do I have going on", "what is stuck", or for any overview of current files. For one specific file use find_loan instead.

    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'). Leave out for the whole pipeline.
  • 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.

    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
    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 name, if the user already said it. 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
    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 name, if the user already said it. 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 name, if already said. Null otherwise.
    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, 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", "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). 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, purpose, 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. Null if unchanged.
    fechasanyrequired
    Milestone dates to set by name, like {"appraisal_received": "2026-09-01"}. 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.
  • 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). 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. 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
    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
    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 marks one as received/approved/rejected/waived. Use it when the loan comes back approved with conditions ("UW wants 2023 tax returns and a gift letter"), when a condition clears ("the gift letter came in", "VOE approved"), or when asked what conditions are still open on a file. 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.

    prestamostringrequired
    The loan, as the user says it: borrower name, address, or number
    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. Null otherwise.
    condicionstringnullrequired
    For 'resolve': which condition, by a few words of its text. Null otherwise.
    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.
    estadoanyrequired
    For 'resolve': the new status. Defaults to 'aprobado' (cleared) when null.
    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.
  • 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". 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.
  • 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 (deduplicated against existing contacts), 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), 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.
  • 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 pending documents and how many days they have been waiting. Use it whenever the user asks what is missing, what came in, or what is stuck.

    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), creates a secure upload portal link for each party, and queues a reminder message (email and text, whichever the contact has) with the link and the list of missing documents. Use it when the user wants to chase, collect or request the missing documents of a loan. The messages go out within a minute; the response says exactly what was queued to whom.

    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.
    modostring
    'request' is the first ask; 'reminder' is the nudge for what was already asked. Default is request.
    confirmarboolean
    false (or omitted) previews what WOULD go out to whom, without sending anything. true sends it. Show the preview first.
  • review_document
    Documents
    Writes data

    Closes out a document that came in: approve it, reject it, or flag it as incomplete. Identify it by document id, or by loan plus document type ("reject the bank statement on the Martinez loan"). Use 'missing_information' 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 'reject' when it is the wrong or unusable document. Both need a reason: it is what the borrower reads to fix it. Approving takes optional notes for the file. Use it when the user reviews paperwork from the chat instead of the review queue.

    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
    Accepted, sent back to be redone, or received but incomplete.
    reasonstring
    Why it is sent back, or exactly what is missing — written for the person who has to fix it. Required for both reject and missing_information.
    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: still pending, already requested and waiting on them (follow_up), already received by other means, or not applicable to 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. Use it when the user says "the statements should be Jan through Mar", "I already have the W-2, mark it in", "I just chased him for the paystub" (follow_up), "we do not need the survey here", 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. To approve or reject a file that came in, use review_document. 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.
    request_fromstring
    Who this document is asked from, 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. The same document goes to different people on different files — never assume from the document type.
    statusstring
    'follow_up' means it was already requested and you are waiting on them — use it after chasing someone; 'received' is for paperwork that arrived outside the portal; 'not_applicable' takes it off the list without erasing its history.
    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.
  • 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. 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", "HOA docs came back today", "payoff received", "did we order HOI on the Miller file?", or "what is still not ordered". 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 six 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". Leave it out to just see the board.
    statusstring
    'ordered' means it went out and we are waiting; 'received' means it came in; 'not_ordered' undoes both — use it when they say they had not actually ordered it. Leave it out to only read.
    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.
  • 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".
  • send_portal_link
    Documents
    Writes data

    Creates (or renews) the secure upload portal link for one contact on one loan and returns the URL. Use it when the user asks for the link of a specific person — "resend the portal to Maria", "give me the upload link for the title company". 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...").
  • 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. 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.
  • 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. 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. Show the user the list, let them drop the ones that do not belong, and only then call update_conditions with accion 'add' to put them on the file.

    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.
  • send_message
    Communication
    Writes data

    Sends an email, text (SMS) or WhatsApp message to a contact, written free-form or from a template. IMPORTANT: it is a two-step action — call it first WITHOUT confirm to get the rendered draft, show that draft to the user and ask for their approval, and only when they approve call it again with confirm=true to actually send. 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". For reading past messages use view_conversation.

    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.
    mensajestring
    Free-form body. Either this or plantilla is required.
    asuntostring
    Email subject (free-form emails only).
    plantillastring
    A template key ('docs_missing_reminder', 'weekly_summary'…) instead of free text. view_templates lists them.
    variablesobject
    Values for the {{variables}} of the template, when using one.
    confirmboolean
    true = the user already saw and approved the draft: send it. Never set it on the first call.
  • 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?", "show me the thread on the Garcia file". Give it a contact or a loan (at least one).

    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: their key, what each one 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). Use it when the user asks what messages go out, wants to see a template before editing it, or before send_message with a template key. To change one, use edit_template.

    clavestring
    One template key to see in full (with its default bodies). Omit to list them all.
  • edit_template
    Communication
    Writes data

    Edits a message template for this account: saves a draft (default) or publishes it (publish=true) so it replaces the stock wording in every future send. 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 always returns a test render with sample data: show it to the user.

    clavestringrequired
    The template key ('docs_missing_reminder'…).
    canalstringrequired
    Which channel version to edit.
    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 ("") only when you are sending `bloques` instead.
    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
    true = make it live for every future send. Default: save as draft only.
    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.
  • generate_preapproval_letter
    Communication
    Writes data

    Generates the official pre-approval letter (PDF) for a loan: amount, program, expiration and the standard disclaimers, 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 loan amount on file and 60 days.

    loanstringrequired
    The loan, as the user says it ("the Garcia file", "412 Elm").
    montonumber
    Approved amount in USD. Omit to use the loan amount on file.
    expirastring
    Expiration date (YYYY-MM-DD). Omit for 60 days from today.
    tasanumber
    Interest rate to show, if the user wants it on the letter.
  • 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", 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.

    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.
  • 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.
  • view_calendar
    Tasks
    Read-only

    Shows the calendar for a SPECIFIC period — one day, one week, one month — with the tasks and the critical loan dates 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.

    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, or one team member. Filters combine: due window, loan or contact as a phrase ("the Garcia file", "Maria"), 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.
    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 full timestamp). '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.
    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.
  • 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.
  • 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

    The weekly summary email, 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 — as ready-to-send text. 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. The same summary goes out automatically by email every week.

    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. Use it when the user asks "what is my link", "give me my sign-up link", "is my public page on", 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". 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.
  • 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.

  • 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". Returns the invitation link too, in case the email does not arrive.

    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, issues a fresh invitation link to share by hand. Use it when the user says "the invitation email never arrived", "resend the invite to maria", "give me the link for my assistant", or asks who has not accepted yet. It also reports whether the account email channel is on: while it is off no invitation email goes out at all, and the link is the only way in — turn it back on with set_channel. Issuing a new link invalidates the previous one for that person. Only the account owner, signed in from their own session.

    personstring
    Who to issue the link for — 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 issuing 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").