{"openapi":"3.1.0","info":{"title":"modellus","version":"1.0.0","description":"Chases documents, keeps borrowers posted in English or Spanish, and re-checks every condition while you originate.\n\nThe same actions are available through four doors: this API, the in-app\nchat, an MCP server at `/api/mcp` to connect Claude or ChatGPT,\nand the screens.\n\nAuthentication: send your key in the `Authorization: Bearer mll_...` header.\nKeys are created from the app."},"servers":[{"url":"https://modellus.ai"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"modellus API key (starts with `mll_`)."}}},"tags":[{"name":"cuenta","description":"Account"},{"name":"contacts","description":"Contacts"},{"name":"pipeline","description":"Pipeline"},{"name":"documents","description":"Documents"},{"name":"communication","description":"Communication"},{"name":"tasks","description":"Tasks"},{"name":"insights","description":"Insights"},{"name":"team","description":"Team"}],"paths":{"/api/v1/resumen_cuenta":{"post":{"operationId":"resumen_cuenta","summary":"Returns the asking account's own data: display name and when it was created","description":"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?\".","tags":["cuenta"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string"},"correo":{"type":["string","null"]},"creada":{"type":["string","null"]}},"required":["nombre","correo","creada"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/adjust_pipeline_view":{"post":{"operationId":"adjust_pipeline_view","summary":"Shows or hides columns in the pipeline screen (stage, amount, address, days in stage, loan number, created)","description":"Shows or hides columns in the pipeline screen (stage, amount, address, days in stage, loan number, created). Use it when asked to add, remove, show or hide a pipeline column — \"show the loan number in the pipeline\", \"hide the address column\". To read the pipeline itself use view_pipeline.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mostrar":{"type":"array","items":{"type":"string","enum":["stage","amount","address","days_in_stage","loan_number","created"]},"description":"Columns to turn on, if any"},"ocultar":{"type":"array","items":{"type":"string","enum":["stage","amount","address","days_in_stage","loan_number","created"]},"description":"Columns to turn off, if any"}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"columnas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"visible":{"type":"boolean"}},"required":["id","label","visible"],"additionalProperties":false}}},"required":["columnas"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/cambiar_nombre":{"post":{"operationId":"cambiar_nombre","summary":"Changes the account's display name","description":"Changes the account's display name. Use it only when explicitly asked to change or correct how the user is called.","tags":["cuenta"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string","minLength":2,"maxLength":80,"description":"The new name, exactly as they want it displayed"}},"required":["nombre"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"nombre":{"type":"string"}},"required":["nombre"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/find_contact":{"post":{"operationId":"find_contact","summary":"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\"","description":"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.","tags":["contacts"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Free text: name, email, phone or fragment. Omit to browse by role or tag."},"role":{"type":"string","enum":["borrower","co_borrower","realtor","listing_agent","selling_agent","seller","title_company","escrow_officer","insurance_company","building_master_insurance","appraiser","appraisal_management_company","processor","underwriter","closer","lender","account_executive","account_manager","mortgage_broker","hard_money_lender","attorney","cpa","financial_advisor","home_inspector","contractor","hoa","surveyor","notary","referral_source","past_client","builder","property_manager","other"],"description":"Only contacts with this role, e.g. \"realtor\" or \"past_client\"."},"tag":{"type":"string","description":"Only contacts carrying this tag."},"limit":{"type":"integer","minimum":1,"maximum":25,"description":"Max results, default 10."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"number"},"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"},"description":"Role labels, e.g. \"Listing Agent\"."},"tags":{"type":"array","items":{"type":"string"}},"sms_opt_out":{"type":"boolean"},"company":{"type":["string","null"]},"preferred_language":{"type":"string"},"recent_events":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"detail":{"type":"string"},"when":{"type":"string"}},"required":["action","detail","when"],"additionalProperties":false}}},"required":["id","name","email","phone","roles","tags","sms_opt_out","company","preferred_language","recent_events"],"additionalProperties":false}}},"required":["total","contacts"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/save_contact":{"post":{"operationId":"save_contact","summary":"Create a new contact or update an existing one","description":"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 — include the ones to keep.","tags":["contacts"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer","description":"The contact id, when updating someone find_contact already returned."},"name":{"type":"string","maxLength":160,"description":"Full name. Required when creating."},"email":{"type":"string"},"phone":{"type":"string","description":"Any format; stored as E.164, US +1 assumed for 10 digits."},"roles":{"type":"array","items":{"type":"string","enum":["borrower","co_borrower","realtor","listing_agent","selling_agent","seller","title_company","escrow_officer","insurance_company","building_master_insurance","appraiser","appraisal_management_company","processor","underwriter","closer","lender","account_executive","account_manager","mortgage_broker","hard_money_lender","attorney","cpa","financial_advisor","home_inspector","contractor","hoa","surveyor","notary","referral_source","past_client","builder","property_manager","other"]},"description":"Business roles, e.g. [\"realtor\", \"referral_source\"]. Replaces the list."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"description":"Replaces the list."},"address":{"type":"string","maxLength":240},"company":{"type":"string","maxLength":120},"nmls_license":{"type":"string","maxLength":40},"preferred_language":{"type":"string","enum":["en","es"]},"referral_source":{"type":"string","maxLength":160,"description":"Who or what referred them."},"notes":{"type":"string","maxLength":4000,"description":"Free-form background notes."},"create_anyway":{"type":"boolean","description":"Set true ONLY after the user confirmed the probable duplicate is a different person."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["created","updated","duplicate_found"]},"contact":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}}},"required":["id","name","email","phone","roles","tags"],"additionalProperties":false},"duplicates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"score":{"type":"number"},"reason":{"type":"string"}},"required":["id","name","email","phone","score","reason"],"additionalProperties":false},"description":"Present when status is duplicate_found: confirm with the user before retrying."}},"required":["status"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/merge_contacts":{"post":{"operationId":"merge_contacts","summary":"Merge two contacts that are the same person into one","description":"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.","tags":["contacts"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"keep_id":{"type":"integer","description":"The contact that survives and wins on conflicts."},"merge_id":{"type":"integer","description":"The duplicate that gets absorbed and deleted."}},"required":["keep_id","merge_id"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"object","properties":{"id":{"type":"number"},"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}}},"required":["id","name","email","phone","roles","tags"],"additionalProperties":false},"absorbed":{"type":"string","description":"Name of the contact that was merged in."}},"required":["contact","absorbed"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/review_contact_import":{"post":{"operationId":"review_contact_import","summary":"FIRST step of importing contacts from a CSV (from another CRM, a phone export, a spreadsheet)","description":"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.","tags":["contacts"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"csv_text":{"type":"string","minLength":1,"description":"The raw CSV content, headers in the first row."},"mapping":{"type":"object","additionalProperties":{"type":"string"},"description":"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."}},"required":["csv_text"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"batch_id":{"type":"string","description":"Pass this to import_contacts to execute the import."},"total_rows":{"type":"number"},"valid":{"type":"number"},"invalid":{"type":"number","description":"Rows without even a name, email or phone. Not staged."},"probable_duplicates":{"type":"number"},"mapping_used":{"type":"object","additionalProperties":{"type":"string"}},"unmapped_columns":{"type":"array","items":{"type":"string"}},"sample":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"duplicate_of":{"type":["string","null"]}},"required":["name","email","phone","duplicate_of"],"additionalProperties":false}}},"required":["batch_id","total_rows","valid","invalid","probable_duplicates","mapping_used","unmapped_columns","sample"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/import_contacts":{"post":{"operationId":"import_contacts","summary":"SECOND step of a CSV import: executes a batch that review_contact_import staged, after the user confirmed the summary","description":"SECOND step of a CSV import: executes a batch that review_contact_import 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).","tags":["contacts"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"batch_id":{"type":"string","minLength":1,"description":"The batch id review_contact_import returned."},"treat_duplicates_as":{"type":"string","enum":["merge","create","skip"],"description":"Override for rows flagged as probable duplicates. Default: each row's suggestion."}},"required":["batch_id"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"created":{"type":"number"},"merged":{"type":"number"},"discarded":{"type":"number"},"batch_id":{"type":"string"}},"required":["created","merged","discarded","batch_id"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/log_note":{"post":{"operationId":"log_note","summary":"Write a dated note on a contact's timeline","description":"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.","tags":["contacts"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"string","minLength":1,"description":"Who, as the user says it: name, email or phone fragment."},"note":{"type":"string","minLength":1,"maxLength":4000,"description":"The note text."},"date":{"type":"string","description":"When it happened (ISO date), only if different from today."}},"required":["contact","note"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"contact":{"type":"string"},"note":{"type":"string"},"logged_at":{"type":"string"}},"required":["contact","note","logged_at"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_pipeline":{"post":{"operationId":"view_pipeline","summary":"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)","description":"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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tipo":{"type":"string","enum":["prequal","loan","both"],"description":"Which pipeline to show. Use 'both' unless the user asks only about pre-quals or only about loans."},"estado":{"type":"string","description":"Only files in this stage, by its name as people say it ('clear to close', 'docs received'). Leave out for the whole pipeline."}},"required":["tipo"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"pipelines":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string","enum":["prequal","loan"]},"total":{"type":"number"},"grupos":{"type":"array","items":{"type":"object","properties":{"estado":{"type":"string"},"label":{"type":"string"},"total":{"type":"number"},"prestamos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"borrower":{"type":["string","null"]},"direccion":{"type":["string","null"]},"monto":{"type":["number","null"]},"dias_en_etapa":{"type":["number","null"]},"estancado":{"type":"boolean"}},"required":["id","borrower","direccion","monto","dias_en_etapa","estancado"],"additionalProperties":false}}},"required":["estado","label","total","prestamos"],"additionalProperties":false}}},"required":["tipo","total","grupos"],"additionalProperties":false}},"estancados":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"borrower":{"type":["string","null"]},"direccion":{"type":["string","null"]},"monto":{"type":["number","null"]},"dias_en_etapa":{"type":["number","null"]},"estancado":{"type":"boolean"},"estado":{"type":"string"}},"required":["id","borrower","direccion","monto","dias_en_etapa","estancado","estado"],"additionalProperties":false}}},"required":["pipelines","estancados"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/find_loan":{"post":{"operationId":"find_loan","summary":"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","description":"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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The file, as the user says it: borrower name, property address, or loan number"}},"required":["prestamo"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"nombre":{"type":"string"},"tipo":{"type":"string","enum":["prequal","loan"]},"estado":{"type":"string"},"estado_label":{"type":"string"},"monto":{"type":["number","null"]},"fecha_cierre":{"type":["string","null"]},"etiquetas":{"type":"array","items":{"type":"string"}},"datos":{"type":"object","additionalProperties":{}},"calculados":{"type":"object","additionalProperties":{"type":"number"}},"borrowers":{"type":"array","items":{"type":"object","properties":{"orden":{"type":"number"},"rol":{"type":"string"},"nombre":{"type":"string"},"email":{"type":["string","null"]},"telefono":{"type":["string","null"]}},"required":["orden","rol","nombre","email","telefono"],"additionalProperties":false}},"participantes":{"type":"array","items":{"type":"object","properties":{"rol":{"type":"string"},"nombre":{"type":"string"},"email":{"type":["string","null"]},"telefono":{"type":["string","null"]}},"required":["rol","nombre","email","telefono"],"additionalProperties":false}},"items":{"type":"array","items":{"type":"object","properties":{"grupo":{"type":"string"},"tipo":{"type":"string"},"label":{"type":"string"},"datos":{"type":"object","additionalProperties":{}}},"required":["grupo","tipo","label","datos"],"additionalProperties":false}},"hitos":{"type":"array","items":{"type":"object","properties":{"hito":{"type":"string"},"label":{"type":"string"},"fecha":{"type":"string"}},"required":["hito","label","fecha"],"additionalProperties":false}}},"required":["id","nombre","tipo","estado","estado_label","monto","fecha_cierre","etiquetas","datos","calculados","borrowers","participantes","items","hitos"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/create_prequal":{"post":{"operationId":"create_prequal","summary":"Creates a new pre-qualification for a borrower and puts it in the pipeline at \"To Be Contacted\"","description":"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. To move an existing file forward use move_stage, not this.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"borrower":{"type":"string","minLength":2,"description":"The borrower, as the user says it: a name, an email, or a phone"},"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"description":"Email for a NEW contact. Null if the borrower already exists or no email was given."},"telefono":{"type":["string","null"],"description":"Phone for a NEW contact. Null if the borrower already exists or no phone was given."}},"required":["borrower","email","telefono"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"borrower":{"type":"string"},"estado":{"type":"string"},"contacto_creado":{"type":"boolean"}},"required":["id","borrower","estado","contacto_creado"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/move_stage":{"post":{"operationId":"move_stage","summary":"Moves a loan or pre-qual to another pipeline stage and stamps the milestone date","description":"Moves a loan or pre-qual 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\". 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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The file, as the user says it: borrower name, property address, or loan number"},"estado":{"type":"string","minLength":1,"description":"The target stage, in snake_case: 'docs_received', 'clear_to_close'…"},"preview":{"type":"boolean","description":"true = do NOT move; only report which notifications the move would send. For \"what would happen if…\" questions."},"skip_notifications":{"type":"boolean","description":"true = move without notifying anyone. For silent corrections."},"force":{"type":"boolean","description":"true = advance EVEN IF documents or UW conditions are still owed. Only when the user explicitly says to move it anyway."}},"required":["prestamo","estado"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"nombre":{"type":"string"},"de":{"type":"string"},"a":{"type":"string"},"a_label":{"type":"string"},"solo_preview":{"type":"boolean"},"notificaciones_previstas":{"type":"array","items":{"type":"string"}}},"required":["id","nombre","de","a","a_label","solo_preview","notificaciones_previstas"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/convert_to_loan":{"post":{"operationId":"convert_to_loan","summary":"Converts a pre-qualification into an active loan, starting it at \"Contract Received\"","description":"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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The pre-qual, as the user says it: borrower name, address, or number"}},"required":["prestamo"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"nombre":{"type":"string"},"estado":{"type":"string"}},"required":["id","nombre","estado"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/update_loan":{"post":{"operationId":"update_loan","summary":"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)","description":"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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The file, as the user says it: borrower name, address, or number"},"monto":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"description":"New loan amount in USD. Null if unchanged."},"fecha_cierre":{"anyOf":[{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}],"description":"New closing date (ISO). Null if unchanged."},"etiquetas":{"anyOf":[{"type":"array","items":{"type":"string","minLength":1}},{"type":"null"}],"description":"The FULL new list of tags (replaces). Null if unchanged."},"datos":{"anyOf":[{"type":"object","properties":{"property_address":{"type":"string","maxLength":300,"description":"Street address of the subject property"},"property_type":{"type":"string","enum":["single_family","condo","townhouse","multi_family","manufactured","duplex","triplex","fourplex","pud","condotel","commercial","land"],"description":"What kind of property it is"},"property_usage":{"type":"string","enum":["primary_residence","second_home","investment"],"description":"How the borrower will use the property"},"property_value":{"type":"number","minimum":0,"description":"Appraised or estimated value in USD"},"structure_type":{"type":"string","enum":["attached","detached"],"description":"Whether the structure is attached or detached"},"appraisal_status":{"type":"string","enum":["not_ordered","ordered","scheduled","inspected","received","received_for_value","received_under_value","received_subject_to","waived"],"description":"Where the appraisal stands, from not ordered to received or waived"},"appraisal_value":{"type":"number","minimum":0,"description":"Appraised value of the property in USD, once the report is in"},"title_under_a_corporation":{"type":"boolean","description":"Whether the property title is held under a corporation or LLC"},"corporate_name":{"type":"string","maxLength":200,"description":"Name of the corporation or LLC holding title, if any"},"number_of_units":{"type":"integer","minimum":1,"maximum":100,"description":"Number of units in the property (1 for single family)"},"loan_number":{"type":"string","maxLength":60,"description":"Loan number assigned by the broker"},"loan_number_lender":{"type":"string","maxLength":60,"description":"Loan number assigned by the lender (loan_number is the broker one)"},"program":{"type":"string","enum":["conventional","fha","va","usda","jumbo","non_qm","heloc","heloan","reverse","private","foreign_national"],"description":"Loan program"},"purpose":{"type":"string","enum":["purchase","refinance","cash_out","rate_term_refinance","limited_cash_out"],"description":"Purchase, refinance, cash-out, rate/term refinance, or limited cash-out"},"fico_score":{"type":"integer","minimum":300,"maximum":850,"description":"Qualifying FICO credit score of the borrower"},"loan_amount_2":{"type":"number","minimum":0,"description":"Second mortgage amount in USD, for combo/piggyback loans"},"purchase_price":{"type":"number","minimum":0,"description":"Price paid to purchase the property in USD"},"down_payment":{"type":"number","minimum":0,"description":"Down payment in USD"},"down_payment_percentage":{"type":"number","minimum":0,"maximum":100,"description":"Down payment as a percent of the purchase price"},"loan_to_value":{"type":"number","minimum":0,"maximum":200,"description":"Loan-to-value ratio, in percent"},"combined_loan_to_value":{"type":"number","minimum":0,"maximum":200,"description":"Combined loan-to-value ratio (all liens), in percent"},"dti":{"type":"string","maxLength":20,"description":"Debt-to-income ratio, like \"43\" or \"31/43\" (front/back)"},"amortization_type":{"type":"string","enum":["fixed","adjustable"],"description":"Fixed or adjustable rate amortization"},"amortization_term_months":{"type":"number","enum":[360,240,180],"description":"Amortization term in months: 360, 240, or 180"},"interest_only":{"type":"boolean","description":"Whether the loan has an interest-only period"},"income_verification":{"type":"string","enum":["full_docs","form_1099","bank_statement","dscr","no_ratio","no_income","profit_and_loss","voe","asset_depletion"],"description":"How income is verified: full docs, 1099, bank statements, DSCR, no ratio, no income, P&L, VOE, or asset depletion"},"waive_escrows":{"type":"boolean","description":"Whether the borrower waives the escrow account"},"lender_program":{"type":"string","maxLength":120,"description":"The lender's own program or product name"},"prepayment_penalty_term":{"type":"string","maxLength":60,"description":"Prepayment penalty term, like \"3 years\""},"prepayment_penalty_type":{"type":"string","maxLength":120,"description":"Prepayment penalty structure, like \"5/4/3/2/1\" or \"fixed 5%\""},"rate":{"type":"number","minimum":0,"maximum":30,"description":"Interest rate, in percent"},"note_rate":{"type":"number","minimum":0,"maximum":30,"description":"The note rate on the mortgage, in percent"},"interest_rate_locked":{"type":"boolean","description":"Whether the interest rate is locked"},"interest_rate_disclosed":{"type":"number","minimum":0,"maximum":30,"description":"Interest rate disclosed to the borrower, in percent"},"interest_rate_buydown":{"type":"number","description":"Rate buydown, in percent"},"interest_rate_cost":{"type":"number","description":"Cost of the interest rate, in points (percent of loan amount)"},"lock_cost":{"type":"number","description":"Cost of the rate lock in USD"},"rate_cost_credit":{"type":"number","description":"Rate cost or credit amount in USD (negative means a credit)"},"credit_to_borrower":{"type":"number","description":"Credit applied to the borrower in USD"},"interest_rate_cost_credit_percent":{"type":"number","description":"Rate cost or credit, as a percent of the loan amount"},"rate_lock_extension_cost":{"type":"number","description":"Cost of extending the rate lock, in percent"},"rate_locked_type":{"type":"string","enum":["borrower_paid","lender_paid"],"description":"Whether the locked rate compensation is borrower-paid or lender-paid"},"lock_expires":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"When the rate lock expires (ISO date)"},"compensation_pct":{"type":"number","minimum":0,"maximum":10,"description":"Broker compensation, in percent of the loan amount"},"priority":{"type":"string","enum":["low","medium","high"],"description":"How hot the file is, to sort the pipeline"},"notes":{"type":"string","maxLength":4000,"description":"Free-form notes about the file"}},"additionalProperties":false},{"type":"null"}],"description":"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."},"fechas":{"anyOf":[{"type":"object","additionalProperties":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"type":"null"}],"description":"Milestone dates to set by name, like {\"appraisal_received\": \"2026-09-01\"}. Valid names are pipeline stages (contract_received, clear_to_close, loan_funded…) 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; 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. Null if unchanged."}},"required":["prestamo","monto","fecha_cierre","etiquetas","datos","fechas"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"nombre":{"type":"string"},"cambios":{"type":"object","additionalProperties":{}}},"required":["id","nombre","cambios"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/update_loan_items":{"post":{"operationId":"update_loan_items","summary":"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","description":"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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The file, as the user says it: borrower name, address, or number"},"agregar":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string","enum":["w2","form_1099","paystub","tax_return_personal","tax_return_business","social_security","pension","alimony","rental_income","voe","irs_transcripts","profit_and_loss_income","child_support","bank_statement_personal","bank_statement_business","retirement_401k","brokerage","cd","gift_funds","sale_proceeds","heloc","crypto","asset_depletion","sale_of_assets","mortgage","heloc_balance","auto_loan","student_loan","credit_card","alimony_owed","child_support_payments","irs_payment_plan","third_party_payments","retirement_draw_payment","government_payment_plan","other_liability","primary_residence","second_home","investment_property","current_residence","pending_sale"],"description":"Item type from the catalog, like w2, form_1099, paystub, voe, irs_transcripts, profit_and_loss_income, child_support, bank_statement_personal, retirement_401k, gift_funds, asset_depletion, sale_of_assets, child_support_payments, irs_payment_plan, third_party_payments, retirement_draw_payment, government_payment_plan, primary_residence, investment_property…"},"participante":{"type":["string","null"],"description":"Whose item it is, by name. Null = the main borrower."},"datos":{"anyOf":[{"type":"object","properties":{"amount":{"type":"number","description":"Monthly amount, balance, or value in USD"},"institution":{"type":"string","maxLength":200,"description":"Bank, employer, or servicer"},"address":{"type":"string","maxLength":300,"description":"Property address, for property items"},"proposed_status":{"type":"string","enum":["retained","pending_sale","sold"],"description":"For property items only: what happens to the property with this loan — kept (retained), listed (pending_sale), or sold"},"description":{"type":"string","maxLength":1000,"description":"Anything else worth noting"}},"additionalProperties":false},{"type":"null"}],"description":"Details: employer, bank, balance, annual_income, address, and for properties proposed_status (retained, pending_sale, sold). Null if none were given."}},"required":["tipo","participante","datos"],"additionalProperties":false}},{"type":"null"}],"description":"Items to add. Null if only removing."},"quitar":{"anyOf":[{"type":"array","items":{"type":"integer","exclusiveMinimum":0}},{"type":"null"}],"description":"Item ids to remove (find_loan lists them). Null if only adding."}},"required":["prestamo","agregar","quitar"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string"},"agregados":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"item":{"type":"string"}},"required":["id","item"],"additionalProperties":false}},"quitados":{"type":"number"},"checklist":{"type":"object","properties":{"nuevos_documentos":{"type":"number"},"ya_no_aplican":{"type":"number"}},"required":["nuevos_documentos","ya_no_aplican"],"additionalProperties":false}},"required":["prestamo","agregados","quitados","checklist"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/assign_loan_contact":{"post":{"operationId":"assign_loan_contact","summary":"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 agent… 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\", \"remove the appraiser from 412 Elm\"","description":"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 agent… 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\", \"remove the appraiser from 412 Elm\". The person must already be a contact.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The file, as the user says it: borrower name, address, or number"},"contacto":{"type":"string","minLength":1,"description":"The person, as the user says it: name, email, or phone"},"rol":{"type":"string","minLength":1,"description":"Their role on this file, in snake_case: 'borrower', 'co_borrower', 'realtor', 'title_company', 'appraiser'…"},"accion":{"type":"string","enum":["add","remove"],"description":"'add' to attach the person, 'remove' to detach them"}},"required":["prestamo","contacto","rol","accion"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string"},"contacto":{"type":"string"},"rol":{"type":"string"},"accion":{"type":"string","enum":["add","remove"]},"orden":{"type":["number","null"]}},"required":["prestamo","contacto","rol","accion","orden"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/update_conditions":{"post":{"operationId":"update_conditions","summary":"Manages the underwriting conditions of a loan: lists them, adds new ones, or marks one as received/approved/rejected/waived","description":"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.","tags":["pipeline"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string","minLength":1,"description":"The loan, as the user says it: borrower name, address, or number"},"accion":{"type":"string","enum":["list","add","resolve"],"description":"'list' to see the conditions, 'add' to create new ones, 'resolve' to change the status of one"},"condiciones":{"anyOf":[{"type":"array","items":{"type":"string","minLength":1}},{"type":"null"}],"description":"For 'add': the text of each new condition. Null otherwise."},"condicion":{"type":["string","null"],"description":"For 'resolve': which condition, by a few words of its text. Null otherwise."},"estado":{"anyOf":[{"type":"string","enum":["pendiente","recibido","aprobado","rechazado","no_aplica"]},{"type":"null"}],"description":"For 'resolve': the new status. Defaults to 'aprobado' (cleared) when null."}},"required":["prestamo","accion","condiciones","condicion","estado"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string"},"condiciones":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"texto":{"type":"string"},"estado":{"type":"string"}},"required":["id","texto","estado"],"additionalProperties":false}},"pendientes":{"type":"number"}},"required":["prestamo","condiciones","pendientes"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/check_documents":{"post":{"operationId":"check_documents","summary":"Shows the document checklist","description":"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.","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loan":{"type":"string","description":"The loan, as the user says it (\"the Martinez loan\", \"123 Main St\"). Leave empty for the cross-pipeline report."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"resumen":{"type":"string"},"prestamos":{"type":"array","items":{"type":"object","properties":{"prestamo_id":{"type":"number"},"prestamo":{"type":"string"},"pendientes":{"type":"number"},"recibidos":{"type":"number"},"aprobados":{"type":"number"},"rechazados":{"type":"number"},"dias_esperando":{"type":["number","null"]},"por_parte":{"type":"array","items":{"type":"object","properties":{"parte":{"type":"string"},"documentos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"documento":{"type":"string"},"estado":{"type":"string"},"motivo_rechazo":{"type":["string","null"]}},"required":["id","documento","estado","motivo_rechazo"],"additionalProperties":false}}},"required":["parte","documentos"],"additionalProperties":false}}},"required":["prestamo_id","prestamo","pendientes","recibidos","aprobados","rechazados","dias_esperando","por_parte"],"additionalProperties":false}}},"required":["resumen","prestamos"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/request_documents":{"post":{"operationId":"request_documents","summary":"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","description":"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.","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loan":{"type":"string","minLength":1,"description":"The loan, as the user says it (\"the Martinez loan\", \"123 Main St\")."}},"required":["loan"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"aviso":{"type":"string"},"partes":{"type":"array","items":{"type":"object","properties":{"parte":{"type":"string"},"rol":{"type":["string","null"]},"docs_faltantes":{"type":"array","items":{"type":"string"}},"enlace":{"type":["string","null"]},"mensajes_encolados":{"type":"array","items":{"type":"string"}}},"required":["parte","rol","docs_faltantes","enlace","mensajes_encolados"],"additionalProperties":false}}},"required":["aviso","partes"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/review_document":{"post":{"operationId":"review_document","summary":"Approves or rejects a received document","description":"Approves or rejects a received document. Identify it by document id, or by loan plus document type (\"reject the bank statement on the Martinez loan\"). Rejecting requires a reason — it is what the borrower reads to fix the resubmission. Use it when the user reviews paperwork from the chat instead of the review queue.","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"document_id":{"type":"integer","description":"The document id, when it is already known (e.g. from check_documents)."},"loan":{"type":"string","description":"The loan, as the user says it. Needed when there is no document_id."},"document_type":{"type":"string","description":"The document type, e.g. \"w2\", \"bank_statement_personal\", \"paystub\"."},"decision":{"type":"string","enum":["approve","reject"],"description":"Whether the document is accepted or sent back."},"reason":{"type":"string","description":"Why it is rejected, written for the person who must resubmit it."}},"required":["decision"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"documento":{"type":"string"},"estado":{"type":"string"},"motivo":{"type":["string","null"]}},"required":["documento","estado","motivo"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/send_portal_link":{"post":{"operationId":"send_portal_link","summary":"Creates (or renews) the secure upload portal link for one contact on one loan and returns the URL","description":"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).","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loan":{"type":"string","minLength":1,"description":"The loan, as the user says it (\"the Martinez loan\", \"123 Main St\")."},"contact":{"type":"string","minLength":1,"description":"The person, as the user says it (\"Maria\", \"the realtor of...\")."}},"required":["loan","contact"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"contacto":{"type":"string"},"enlace":{"type":"string"},"expira_el":{"type":"string"},"aviso":{"type":"string"}},"required":["contacto","enlace","expira_el","aviso"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/adjust_checklist":{"post":{"operationId":"adjust_checklist","summary":"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\")","description":"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\"). For changing the office-wide rules use edit_checklist_rules instead.","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loan":{"type":"string","minLength":1,"description":"The loan, as the user says it (\"the Martinez loan\", \"123 Main St\")."},"add":{"type":"array","items":{"type":"object","properties":{"document_type":{"type":"string","description":"The document type, e.g. \"divorce_decree\", \"credit_explanation_letter\"."},"from":{"type":"string","description":"Who provides it, as the user says it (\"Maria\", \"the realtor\"). Defaults to the borrower."},"note":{"type":"string","description":"Why it is being asked (e.g. the underwriting condition text)."}},"required":["document_type"],"additionalProperties":false},"description":"Documents to add to this loan."},"remove":{"type":"array","items":{"type":"string"},"description":"Document types to mark as not applicable on this loan."}},"required":["loan"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"agregados":{"type":"array","items":{"type":"string"}},"retirados":{"type":"array","items":{"type":"string"}}},"required":["agregados","retirados"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_checklist_rules":{"post":{"operationId":"view_checklist_rules","summary":"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)","description":"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.","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loan":{"type":"string","description":"A loan, to also explain what generated each of its documents."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"reglas":{"type":"array","items":{"type":"string"}},"overrides":{"type":"object","additionalProperties":{}},"documentos_del_prestamo":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"documento":{"type":"string"},"origen":{"type":"string"},"razon":{"type":"string"}},"required":["documento","origen","razon"],"additionalProperties":false}},{"type":"null"}]}},"required":["reglas","overrides","documentos_del_prestamo"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/edit_checklist_rules":{"post":{"operationId":"edit_checklist_rules","summary":"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\")","description":"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.","tags":["documents"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"disable":{"type":"array","items":{"type":"string"},"description":"Document types to stop requesting everywhere, e.g. [\"survey\"]."},"enable":{"type":"array","items":{"type":"string"},"description":"Previously disabled document types to request again."},"bank_statements":{"type":"integer","minimum":1,"maximum":12,"description":"How many bank statements to request per account (default 2)."},"tax_return_years":{"type":"integer","minimum":1,"maximum":5,"description":"How many years of tax returns to request (default 2)."},"w2_years":{"type":"integer","minimum":1,"maximum":5,"description":"How many years of W-2s to request (default 2)."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"overrides":{"type":"object","additionalProperties":{}},"resumen":{"type":"string"}},"required":["overrides","resumen"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/send_message":{"post":{"operationId":"send_message","summary":"Sends an email, text (SMS) or WhatsApp message to a contact, written free-form or from a template","description":"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.","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contacto":{"type":"string","minLength":1,"description":"Who, as the user says it: a name, email or phone number."},"canal":{"type":"string","enum":["email","sms","whatsapp"],"description":"How to send it. If omitted: email when the contact has one, otherwise sms."},"mensaje":{"type":"string","description":"Free-form body. Either this or plantilla is required."},"asunto":{"type":"string","description":"Email subject (free-form emails only)."},"plantilla":{"type":"string","description":"A template key ('docs_missing_reminder', 'weekly_summary'…) instead of free text. view_templates lists them."},"variables":{"type":"object","additionalProperties":{"type":"string"},"description":"Values for the {{variables}} of the template, when using one."},"confirm":{"type":"boolean","description":"true = the user already saw and approved the draft: send it. Never set it on the first call."}},"required":["contacto"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"enviado":{"type":"boolean"},"contacto":{"type":"string"},"canal":{"type":"string"},"destinatario":{"type":"string"},"borrador":{"type":"object","properties":{"asunto":{"type":["string","null"]},"cuerpo":{"type":"string"}},"required":["asunto","cuerpo"],"additionalProperties":false},"aviso":{"type":"string"}},"required":["enviado","contacto","canal","destinatario","borrador","aviso"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_conversation":{"post":{"operationId":"view_conversation","summary":"Shows the message history (emails, texts, WhatsApp — sent and received) with a contact, or all the messages around a loan","description":"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).","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contacto":{"type":"string","description":"The person, as the user says it: name, email or phone."},"loan":{"type":"string","description":"The loan, as the user says it (\"the Martinez loan\", \"412 Elm\")."},"limite":{"type":"integer","minimum":1,"maximum":50,"description":"How many messages (default 20, newest first)."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"hilo":{"type":"string"},"mensajes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"canal":{"type":"string"},"direccion":{"type":"string"},"estado":{"type":"string"},"destinatario":{"type":"string"},"asunto":{"type":["string","null"]},"texto":{"type":"string"},"cuando":{"type":"string"}},"required":["id","canal","direccion","estado","destinatario","asunto","texto","cuando"],"additionalProperties":false}}},"required":["hilo","mensajes"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_templates":{"post":{"operationId":"view_templates","summary":"Lists the message templates: their key, what each one says by default, which channels and languages exist, whether the account customized them, and which pipeline transition triggers each one automatically","description":"Lists the message templates: their key, what each one says by default, which channels and languages exist, whether the account customized them, and which pipeline transition triggers each one automatically. 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.","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string","description":"One template key to see in full (with its default bodies). Omit to list them all."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"plantillas":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"label":{"type":"string"},"variables":{"type":"array","items":{"type":"string"}},"disparadores":{"type":"array","items":{"type":"string"}},"personalizaciones":{"type":"array","items":{"type":"string"}},"cuerpos":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"canal":{"type":"string"},"idioma":{"type":"string"},"asunto":{"type":["string","null"]},"cuerpo":{"type":"string"}},"required":["canal","idioma","asunto","cuerpo"],"additionalProperties":false}},{"type":"null"}]}},"required":["clave","label","variables","disparadores","personalizaciones","cuerpos"],"additionalProperties":false}}},"required":["plantillas"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/edit_template":{"post":{"operationId":"edit_template","summary":"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","description":"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. It always returns a test render with sample data: show it to the user.","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string","minLength":1,"description":"The template key ('docs_missing_reminder'…)."},"canal":{"type":"string","enum":["email","sms","whatsapp"],"description":"Which channel version to edit."},"idioma":{"type":"string","enum":["en"],"description":"Which language version (default 'en')."},"cuerpo":{"type":"string","minLength":1,"description":"The new body, with {{variables}} where data should go."},"asunto":{"type":"string","description":"The new subject (email only)."},"publish":{"type":"boolean","description":"true = make it live for every future send. Default: save as draft only."}},"required":["clave","canal","cuerpo"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string"},"canal":{"type":"string"},"idioma":{"type":"string"},"estado":{"type":"string"},"render_de_prueba":{"type":"object","properties":{"asunto":{"type":["string","null"]},"cuerpo":{"type":"string"}},"required":["asunto","cuerpo"],"additionalProperties":false},"aviso":{"type":"string"}},"required":["clave","canal","idioma","estado","render_de_prueba","aviso"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/generate_preapproval_letter":{"post":{"operationId":"generate_preapproval_letter","summary":"Generates the official pre-approval letter (PDF) for a loan: amount, program, expiration and the standard disclaimers, signed by the loan officer","description":"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.","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loan":{"type":"string","minLength":1,"description":"The loan, as the user says it (\"the Garcia file\", \"412 Elm\")."},"monto":{"type":"number","exclusiveMinimum":0,"description":"Approved amount in USD. Omit to use the loan amount on file."},"expira":{"type":"string","description":"Expiration date (YYYY-MM-DD). Omit for 60 days from today."},"tasa":{"type":"number","exclusiveMinimum":0,"description":"Interest rate to show, if the user wants it on the letter."}},"required":["loan"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"prestamo":{"type":"string"},"borrower":{"type":"string"},"monto":{"type":"number"},"vence":{"type":"string"},"enlace":{"type":"string"},"aviso":{"type":"string"}},"required":["prestamo","borrower","monto","vence","enlace","aviso"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_automations":{"post":{"operationId":"view_automations","summary":"Shows every automation of the account: which are on or off, their cadence in days, and when the scheduled jobs run","description":"Shows every automation of the account: which are on or off, their cadence in days, and when the scheduled jobs run. Use it when the user asks \"what runs automatically\", \"is the document reminder on\", \"how often do borrowers get reminded\", or before changing one. To turn one on/off or change its cadence use set_automation.","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"automatizaciones":{"type":"array","items":{"type":"object","properties":{"clave":{"type":"string"},"nombre":{"type":"string"},"activa":{"type":"boolean"},"cadencia_dias":{"type":["number","null"]}},"required":["clave","nombre","activa","cadencia_dias"],"additionalProperties":false}},"programacion":{"type":"array","items":{"type":"object","properties":{"trabajo":{"type":"string"},"cuando":{"type":"string"}},"required":["trabajo","cuando"],"additionalProperties":false}}},"required":["automatizaciones","programacion"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/set_automation":{"post":{"operationId":"set_automation","summary":"Turns an automation on or off, or changes its cadence in days","description":"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.","tags":["communication"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"automation":{"type":"string","minLength":1,"description":"Which automation, as the user says it: the key (\"docs_missing_reminder\") or words from its name (\"document reminder\")."},"enabled":{"type":"boolean","description":"true to turn it on, false to turn it off."},"cadence_days":{"type":"integer","minimum":1,"maximum":30,"description":"Every how many days it fires (for automations with a cadence)."}},"required":["automation"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"clave":{"type":"string"},"activa":{"type":"boolean"},"cadencia_dias":{"type":["number","null"]},"resumen":{"type":"string"}},"required":["clave","activa","cadencia_dias","resumen"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_tasks":{"post":{"operationId":"view_tasks","summary":"Lists tasks","description":"Lists tasks. Use it when the user asks \"what do I have today\", \"what is overdue\", \"my tasks for the week\", 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. To create or change a task use save_task.","tags":["tasks"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"due":{"type":"string","enum":["today","overdue","week","all"],"description":"Due window: 'today' (due today or earlier), 'overdue' (past due), 'week' (next 7 days), 'all'. Default 'all'."},"status":{"type":"string","enum":["pending","done","cancelled","all"],"description":"Which tasks. Default 'pending'."},"loan":{"type":"string","description":"Only tasks of this loan, as the user says it."},"contact":{"type":"string","description":"Only tasks about this person, as the user says it."},"assignee":{"type":"string","description":"Only tasks assigned to this member: \"me\", a name or email."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"resumen":{"type":"string"},"tareas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"titulo":{"type":"string"},"estado":{"type":"string"},"vence_el":{"type":["string","null"]},"vencida":{"type":"boolean"},"descripcion":{"type":["string","null"]},"subtareas":{"type":"array","items":{"type":"object","properties":{"texto":{"type":"string"},"hecha":{"type":"boolean"}},"required":["texto","hecha"],"additionalProperties":false}},"prestamo":{"type":["string","null"]},"contacto":{"type":["string","null"]},"asignado_a":{"type":["string","null"]}},"required":["id","titulo","estado","vence_el","vencida","descripcion","subtareas","prestamo","contacto","asignado_a"],"additionalProperties":false}}},"required":["resumen","tareas"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/save_task":{"post":{"operationId":"save_task","summary":"Creates or updates a task","description":"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 due date, adds or checks off subtasks, ties it to a loan or contact, or assigns it to a team member. 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.","tags":["tasks"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"task":{"type":"string","description":"The existing task to change: its id, or words from its title. Leave empty to create a new one."},"title":{"type":"string","maxLength":200,"description":"The task title. Required when creating; renames when editing."},"description":{"type":"string","maxLength":4000,"description":"Longer detail."},"due":{"type":"string","description":"When it is due, ISO (YYYY-MM-DD or full timestamp). 'none' clears it."},"status":{"type":"string","enum":["pending","done","cancelled"],"description":"Set to 'done' to complete, 'cancelled' to cancel, 'pending' to reopen."},"subtasks":{"type":"array","items":{"type":"object","properties":{"text":{"type":"string"},"done":{"type":"boolean"}},"required":["text","done"],"additionalProperties":false},"description":"Replaces the whole subtask list. To add some, use add_subtasks."},"add_subtasks":{"type":"array","items":{"type":"string"},"description":"Subtasks to append, unchecked."},"check_subtask":{"type":"string","description":"Words from one subtask to mark as done."},"loan":{"type":"string","description":"The loan this task is about, as the user says it."},"contact":{"type":"string","description":"The person this task is about, as the user says it."},"assignee":{"type":"string","description":"Who should do it: \"me\", a name, or an email."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"number"},"titulo":{"type":"string"},"estado":{"type":"string"},"vence_el":{"type":["string","null"]},"resumen":{"type":"string"}},"required":["id","titulo","estado","vence_el","resumen"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/production_report":{"post":{"operationId":"production_report","summary":"Production report for a period: how many loans closed, total volume, and estimated commission, compared against the previous equivalent period","description":"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.","tags":["insights"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"string","description":"The period as the user says it: \"this month\", \"last quarter\", \"Q2 2026\", \"March\", \"2025\", \"last 30 days\". Defaults to this month."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"label":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"}},"required":["label","from","to"],"additionalProperties":false},"closings":{"type":"number"},"volume":{"type":"number"},"estimated_commission":{"type":"number"},"closings_without_commission_data":{"type":"number"},"loans":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"borrower":{"type":["string","null"]},"address":{"type":["string","null"]},"amount":{"type":["number","null"]},"closed_on":{"type":"string"},"estimated_commission":{"type":["number","null"]}},"required":["id","borrower","address","amount","closed_on","estimated_commission"],"additionalProperties":false}},"previous":{"type":"object","properties":{"label":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"},"closings":{"type":"number"},"volume":{"type":"number"},"estimated_commission":{"type":"number"}},"required":["label","from","to","closings","volume","estimated_commission"],"additionalProperties":false},"change":{"type":"object","properties":{"closings":{"type":"number"},"volume":{"type":"number"},"volume_pct":{"type":["number","null"]}},"required":["closings","volume","volume_pct"],"additionalProperties":false}},"required":["period","closings","volume","estimated_commission","closings_without_commission_data","loans","previous","change"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/referral_report":{"post":{"operationId":"referral_report","summary":"Referral report for a period: which sources brought the business — deals, volume, and conversion per source","description":"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.","tags":["insights"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"string","description":"The period as the user says it: \"this month\", \"last quarter\", \"Q2 2026\", \"2025\", \"last 90 days\". Defaults to this month."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"object","properties":{"label":{"type":"string"},"from":{"type":"string"},"to":{"type":"string"}},"required":["label","from","to"],"additionalProperties":false},"sources":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string"},"contact_id":{"type":["number","null"]},"deals":{"type":"number"},"volume":{"type":"number"},"won":{"type":"number"},"conversion_pct":{"type":["number","null"]}},"required":["source","contact_id","deals","volume","won","conversion_pct"],"additionalProperties":false}},"total_deals":{"type":"number"},"deals_without_source":{"type":"number"}},"required":["period","sources","total_deals","deals_without_source"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/stage_timing_report":{"post":{"operationId":"stage_timing_report","summary":"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","description":"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.","tags":["insights"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"stages":{"type":"array","items":{"type":"object","properties":{"stage":{"type":"string"},"label":{"type":"string"},"average_days":{"type":"number"},"samples":{"type":"number"}},"required":["stage","label","average_days","samples"],"additionalProperties":false}},"outliers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"number"},"borrower":{"type":["string","null"]},"address":{"type":["string","null"]},"stage":{"type":"string"},"label":{"type":"string"},"days_in_stage":{"type":"number"},"average_days":{"type":"number"}},"required":["id","borrower","address","stage","label","days_in_stage","average_days"],"additionalProperties":false}},"closed_loans_measured":{"type":"number"},"note":{"type":["string","null"]}},"required":["stages","outliers","closed_loans_measured","note"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/weekly_summary":{"post":{"operationId":"weekly_summary","summary":"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","description":"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.","tags":["insights"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"summary":{"type":"string"},"data":{"type":"object","additionalProperties":{}}},"required":["summary","data"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/view_team":{"post":{"operationId":"view_team","summary":"Lists the team of this account: the owner plus every invited assistant, with name, email, and role","description":"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 or removing someone to confirm who is already in.","tags":["team"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"team":{"type":"array","items":{"type":"object","properties":{"name":{"type":["string","null"]},"email":{"type":["string","null"]},"role":{"type":"string","enum":["owner","assistant","loan_officer"]},"since":{"type":["string","null"]}},"required":["name","email","role","since"],"additionalProperties":false}}},"required":["team"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/invite_teammate":{"post":{"operationId":"invite_teammate","summary":"Invites a person by email to join this account as an assistant: they get full day-to-day access (contacts, pipeline, documents) but cannot manage the team","description":"Invites a person by email to join this account as an assistant: they get full day-to-day access (contacts, pipeline, documents) but cannot manage the team. 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\". Returns the invitation link too, in case the email does not arrive.","tags":["team"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"The email of the person to invite, e.g. \"maria@gmail.com\"."}},"required":["email"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"role":{"type":"string"},"invite_link":{"type":"string"},"email_queued":{"type":"boolean"},"note":{"type":"string"}},"required":["email","role","invite_link","email_queued","note"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}},"/api/v1/remove_teammate":{"post":{"operationId":"remove_teammate","summary":"Removes an assistant from this account by email or name, revoking their access immediately","description":"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.","tags":["team"],"security":[{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"member":{"type":"string","minLength":1,"description":"The teammate, as the user says it: an email (\"maria@gmail.com\") or a name (\"Maria\")."}},"required":["member"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"type":"object","properties":{"removed":{"type":"string"},"email":{"type":["string","null"]}},"required":["removed","email"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}}},"400":{"description":"The parameters are not valid"},"401":{"description":"Missing or invalid API key"},"404":{"description":"What you asked for was not found"},"500":{"description":"Server or provider error"}}}}}}