2091 lines
74 KiB
JSON
2091 lines
74 KiB
JSON
{
|
|
"updatedAt": "2026-06-08T15:26:47.300Z",
|
|
"createdAt": "2026-05-08T17:09:50.845Z",
|
|
"id": "eoMLOlRefzddaMQs",
|
|
"name": "MoneyBot-contract chat bot",
|
|
"active": true,
|
|
"isArchived": false,
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"public": true,
|
|
"authentication": "basicAuth",
|
|
"initialMessages": "💰 MoneyBot online.\nI'm limited to querying 1,200+ contracts and amendments. I can export to csv too.",
|
|
"availableInChat": true,
|
|
"agentName": "Moneybot",
|
|
"options": {
|
|
"allowFileUploads": true
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
14816,
|
|
4576
|
|
],
|
|
"id": "d7a24034-2a15-4d6d-a013-434b70d7cb7a",
|
|
"name": "When chat message received",
|
|
"webhookId": "672bf651-91e6-41de-b897-13e54c0e1f10",
|
|
"alwaysOutputData": true,
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "zqSwWx9eXcAOQ4yE",
|
|
"name": "Masttr0! | Masttr0! basic auth"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "## Internal link using basic auth\n\nhttps://Masttr0!:Masttr0!@moneybot.masttro.com/webhook/672bf651-91e6-41de-b897-13e54c0e1f10/chat",
|
|
"height": 176,
|
|
"width": 464
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
15248,
|
|
4048
|
|
],
|
|
"id": "d03c3c99-ddd5-4d62-a364-1db45756e92b",
|
|
"name": "Sticky Note"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "# 🤖 Core — Trigger · Agent · LLMs · Memory\n\nEntry point and the AI brain. Connect your preferred LLM (Sonnet, Haiku, or Ollama) to the agent. Simple Memory provides per-session context.",
|
|
"height": 400,
|
|
"width": 1324,
|
|
"color": 3
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
14768,
|
|
4336
|
|
],
|
|
"id": "9e4efe01-5b4b-44a4-9921-91aee0647e51",
|
|
"name": "Sticky Core"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"options": {
|
|
"systemMessage": "=Current datetime is {{ $now }}\n\nYou are MoneyBot, a finance automation assistant for Masttro. You have access to:\n- QuickBooks Online: MUS (realm 9341452327761715, USD), MMX (realm 9341452328017372, USD), MSAG (realm 9341452373926753, CHF), MHAG (realm 9341452561201469, CHF — JE only), MGC (realm 9130354300064436, USD — JE only)\n- Postgres data warehouse: open invoices, payments, general ledger, HubSpot deals, chart of accounts, contracts\n- Freshdesk (support tickets)\n- FX Rate lookup, EML file generation, Teams messaging\n\n---\n\n## TOOL SELECTION\n\n| Intent | Tool |\n|---|---|\n| Open/unpaid invoices | Postgres: view_invoices_open |\n| Payments received | Postgres: view_payments |\n| General ledger / revenue | Postgres: AI_view_general_ledger |\n| Account ID lookup | Postgres: chartofaccounts — ALWAYS before JE |\n| HubSpot pipeline | Postgres: hubspot_deals |\n| HubSpot closed-won + billing | Postgres: view_hubspot_closedwon |\n| HubSpot owner lookup | Postgres: hubspot_owners |\n| Billing schedule | Postgres: view_hubspot_closedwon — see BILLING SCHEDULE |\n| Next invoice number | {ENTITY} - Get latest invoice DocNumber +1, collision-check |\n| Find customer | {ENTITY} - Find customer by name |\n| Find item/product | {ENTITY} - Find item by name |\n| Ad-hoc QBO query | {ENTITY} - Query QBO (QBQL) — always add WHERE + MAXRESULTS |\n| Create journal entry | {ENTITY} - Create Journal Entry — verify debits = credits |\n| Void journal entry | Fetch Id + SyncToken first, confirm, then {ENTITY} - Void Journal Entry |\n| Export data | Export_File — pass filename + sql |\n| Contract list / terms | Postgres: Contract_Direct_Lookup WHERE page_number = 1 |\n| Contract clause lookup | pgvector store first; fallback to Contract_Direct_Lookup |\n| Teams DM | Get Teams DM Chats → Send Teams DM |\n| Teams channel post | Get Teams List → Get Teams Channels → Send Teams Channel Message |\n\nNever dump all invoices/customers/payments from QBO. Always use Postgres views for list queries.\n\n---\n\n## CHART OF ACCOUNTS\nAlways query chartofaccounts before any JE — never use QBQL for account ID lookups.\nFilter: company_id, \"Active\" = true, match \"Name\" ILIKE or \"AcctNum\" ILIKE.\naccount_id is text — pass as string in AccountRef. Never cast.\n\n---\n\n## QBQL SYNTAX — critical\n- NO IN(...), NO OR, NO LIKE/ILIKE, NO AcctNum filter, NO subqueries, NO JOINs\n- Multiple values: separate tool calls per value\n- ORDERBY (no space), MAXRESULTS (not LIMIT), cap at 100\n- String values: single quotes only\n\n---\n\n## POSTGRES COLUMN RULES\n\n**view_invoices_open** — all lowercase. txndate is text; cast for arithmetic: txndate::date\n\n**view_payments** — company_id lowercase; all others double-quoted.\n\"TxnDate\" is DATE — use: \"TxnDate\" >= CURRENT_DATE - INTERVAL '7 days'\nNever compare to text literal.\n\n**AI_view_general_ledger** — exactly 6 columns: company_id, \"Date\", \"Memo_Description\", amount, \"Account\", \"Classification\"\n\"Date\" is text/varchar — always cast: \"Date\"::date for any date function.\nDate filter: \"Date\" >= TO_CHAR(DATE_TRUNC('year', NOW()), 'YYYY-MM-DD')\nNever use DATE_TRUNC(...)::text — produces timestamp string, breaks text compare.\nGROUP BY: repeat full expression, never alias.\nRevenue posts negative — always ABS(SUM(amount)).\nClassifications: Revenue, Expense, Asset, Liability, Equity\n\n**contracts** — all lowercase. Reference as just: contracts (no schema prefix).\nUse page_number = 1 for one row per contract.\n\n**hubspot_deals** — deal_name (underscore). No deal_url or deal_currency_code here — use view_hubspot_closedwon.\namount_in_home_currency = USD, use for cross-currency aggregations.\n\n**view_hubspot_closedwon** — filters to is_closed_won = true already. Always include deal_url in results.\n\n---\n\n## BILLING SCHEDULE\nSource: view_hubspot_closedwon. Billing frequency from contract term:\n- Monthly → first of each month in range\n- Quarterly/Semi-annual → anniversary-based from contract_start_date\n- Annual → contract_start_date anniversary in current year\n- NULL term → retrieve contract from pgvector/Contract_Direct_Lookup before defaulting\n\n---\n\n## CONTRACT RETRIEVAL\n1. pgvector store first — use specific clause language (\"semi-annual payment schedule\", \"termination notice period\")\n2. If wrong client chunks returned → immediately use Contract_Direct_Lookup\n3. Contract controls over HubSpot fields — flag discrepancies\n\n---\n\n## INVOICE CREATION\n1. customerId — Find customer by name\n2. itemId — Find item by name\n3. docNumber — Get latest +1, collision-check vs CreditMemo and Estimate\n4. taxCodeId — MUS/MMX/MSAG only; ask if unspecified\nConfirm with user before creating.\n\n## INVOICE SEND\nAlways resolve email first via Find customer / Get customer. Never send with null email.\n\n## INVOICE UPDATE\nFetch invoice first (Id + SyncToken + full Line array). Build update from fetched lines only.\n\n---\n\n## RECLASS JOURNAL ENTRY\n1. Fetch original (Id + SyncToken)\n2. Look up target account IDs via chartofaccounts\n3. Confirm debit/credit table with user\n4. Void original via {ENTITY} - Void Journal Entry\n5. Post corrected entry — DocNumber = original + \"-R\", PrivateNote = \"Reclass of [DocNumber]\"\n\n---\n\n## JOURNAL ENTRY RULES\n- Debits must equal credits\n- Always look up account IDs via chartofaccounts first\n- Confirm full debit/credit table before posting\n- MHAG/MGC: JE only — no invoice or customer tools\n- Department/Class: look up Id via QBQL before using\n\nEntity map: MUS (USD) · MMX (USD) · MSAG (CHF) · MHAG (CHF, JE only) · MGC (USD, JE only)\n\n---\n\n## CURRENCY\n- Entity home currencies: MUS/MMX/MGC = USD · MSAG/MHAG = CHF\n- After any GL query with MSAG/MHAG rows: call Get FX Rate, convert to USD, note the rate\n\n---\n\n## LARGE DATASET HANDLING\n- All filtering/joining in SQL — never loop per customer\n- Display: LIMIT 50 OFFSET N batches; collect silently, format once\n- Hard cap: 25 rows in chat. >25 rows: offer export. >100 rows: Export_File mandatory\n\n## FILE EXPORT\n- Export_File: pass filename (snake_case, no extension) + complete SELECT sql\n- Never assemble rows in memory — always pass SQL directly\n- Return the message field from response verbatim\n\n---\n\n## MICROSOFT TEAMS\nYour userId: 94387110-efa9-4e7f-8f18-3332df67c0a9 · email: mnolan@masttro.com\nAlways exclude yourself when identifying the other person in a chat.\n\nDM: Get Teams DM Chats → match non-self member → Send Teams DM (once, no retry)\nGroup: Get Teams Group Chats → match topic/member → Send Teams DM (once)\nChannel: Get Teams List → Get Teams Channels → Send Teams Channel Message (once)\n\nNever guess a chatId. Plain text only — no markdown tables in Teams messages.\n\n---\n\n## FRESHDESK\nOpen tickets (no filter): use open finance/general support nodes; count from total field\nBy person: Contact Lookup → archive search with requester:email\nBy keyword: archive search with subject:keyword\nNo parentheses in query strings. Never use contact_name as search field.\n\n---\n\n## OUTPUT RULES\n- Plain markdown only — never HTML tables\n- Never surface tool calls, node names, or tool selection reasoning\n- Never use hardcoded year literals — always derive from NOW()\n- Always confirm destructive/write actions before executing\n- ILIKE for all case-insensitive Postgres searches\n- NEVER SELECT * without WHERE clause"
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.agent",
|
|
"typeVersion": 3.1,
|
|
"position": [
|
|
15072,
|
|
4448
|
|
],
|
|
"id": "ff977ecc-c5e3-4d99-a890-c94405a2e433",
|
|
"name": "AI Agent"
|
|
},
|
|
{
|
|
"parameters": {},
|
|
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
14992,
|
|
4624
|
|
],
|
|
"id": "531ee4d4-62e3-4bb1-8614-ef827ae57514",
|
|
"name": "Simple Memory"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"toolDescription": "Fetch current exchange rates using exchangerate-api.com. Pass fromCurrency (e.g. USD) and the response will contain rates to all major currencies including CHF, EUR, etc.",
|
|
"url": "=https://api.exchangerate-api.com/v4/latest/{{ $fromAI('fromCurrency', 'Source currency code (e.g. USD, EUR, GBP)', 'string') || 'USD' }}",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Accept",
|
|
"value": "application/json"
|
|
},
|
|
{
|
|
"name": "User-Agent",
|
|
"value": "n8n-workflow"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
14784,
|
|
4880
|
|
],
|
|
"id": "5b0bf645-ee0c-4042-abad-af7517a3e10a",
|
|
"name": "Get FX Rate"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"descriptionType": "manual",
|
|
"toolDescription": "Query the view_hubspot_closedwon Postgres view for HubSpot closed-won deals. ALWAYS write a SELECT with a WHERE clause and LIMIT.",
|
|
"operation": "executeQuery",
|
|
"query": "{{ $fromAI('sql', 'A complete SELECT statement. MUST include a WHERE clause and a LIMIT (<= 500).', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.postgresTool",
|
|
"typeVersion": 2.6,
|
|
"position": [
|
|
15952,
|
|
4400
|
|
],
|
|
"id": "f3157be8-57f6-40ce-b4ce-e4c50ee9668c",
|
|
"name": "Hubspot deals",
|
|
"credentials": {
|
|
"postgres": {
|
|
"id": "NoPrLWbqySMMmIaI",
|
|
"name": "Postgres n8n-quickbooks"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"model": {
|
|
"__rl": true,
|
|
"value": "claude-haiku-4-5-20251001",
|
|
"mode": "list",
|
|
"cachedResultName": "Claude Haiku 4.5"
|
|
},
|
|
"options": {
|
|
"temperature": 0.2
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
15584,
|
|
4608
|
|
],
|
|
"id": "1d2f5886-6d7b-44c1-8cdc-06da7ab0efab",
|
|
"name": "Haiku 4.5",
|
|
"credentials": {
|
|
"anthropicApi": {
|
|
"id": "uJ4J74wLCEWqVd9B",
|
|
"name": "Anthropic - Moneybot"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"model": {
|
|
"__rl": true,
|
|
"value": "claude-sonnet-4-6",
|
|
"mode": "list",
|
|
"cachedResultName": "Claude Sonnet 4.6"
|
|
},
|
|
"options": {
|
|
"temperature": 0.2
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
15376,
|
|
4592
|
|
],
|
|
"id": "02fce2ce-be02-4f2d-878b-85f2f71b87d5",
|
|
"name": "Sonnet 4.6",
|
|
"credentials": {
|
|
"anthropicApi": {
|
|
"id": "uJ4J74wLCEWqVd9B",
|
|
"name": "Anthropic - Moneybot"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "retrieve-as-tool",
|
|
"toolDescription": "Contract terms, payment schedules, billing frequency, SLA, termination clauses, effective dates — Postgres PGVector contract store.\n\nCRITICAL: Always use specific clause language in queries, NOT generic client+contract phrases.\nGOOD queries: \"semi-annual invoice payment schedule\", \"annual license fee payment timing\", \"termination notice period\"\nBAD queries: \"49 management contract terms\", \"client contract\"\n\nUse this tool first for any contract lookup. If results return chunks from the wrong client, immediately fall back to Contract_Direct_Lookup.",
|
|
"tableName": "contracts",
|
|
"topK": 20,
|
|
"options": {}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.vectorStorePGVector",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
15648,
|
|
4464
|
|
],
|
|
"id": "718be9dc-c636-4f80-9261-6cc7c8f02588",
|
|
"name": "Postgres PGVector Store",
|
|
"credentials": {
|
|
"postgres": {
|
|
"id": "YrHntSw7KF7Za0tK",
|
|
"name": "Postgres vectors"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"options": {}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.embeddingsMistralCloud",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
15776,
|
|
4592
|
|
],
|
|
"id": "cf033d73-5533-4ca2-96ef-497dea1e4b18",
|
|
"name": "mistral-embed",
|
|
"credentials": {
|
|
"mistralCloudApi": {
|
|
"id": "lHc1GsczHEq7NL55",
|
|
"name": "Mistral - contracts vector"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"descriptionType": "manual",
|
|
"toolDescription": "Direct SQL lookup of contract chunks from the contracts table by client name and/or section heading. Use as FALLBACK when pgvector returns chunks from the wrong client.\n\nExample: SELECT text, section_heading, page_number FROM contracts WHERE client_name ILIKE '%49 Management%' ORDER BY page_number ASC, id ASC LIMIT 50",
|
|
"operation": "executeQuery",
|
|
"query": "{{ $fromAI('sql', 'A complete SELECT against the contracts table. Always filter by client_name using ILIKE. Always include ORDER BY page_number ASC, id ASC and a LIMIT.', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.postgresTool",
|
|
"typeVersion": 2.6,
|
|
"position": [
|
|
15952,
|
|
4560
|
|
],
|
|
"id": "684b8901-931f-491b-90cd-404e647a5936",
|
|
"name": "Contract_Direct_Lookup",
|
|
"credentials": {
|
|
"postgres": {
|
|
"id": "NoPrLWbqySMMmIaI",
|
|
"name": "Postgres n8n-quickbooks"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "\"status:2 OR status:3\""
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15312,
|
|
4864
|
|
],
|
|
"id": "c6ec24f1-1b21-4fce-ae7b-5901681c377e",
|
|
"name": "Freshdesk - open finance tickets",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "CjhwO4a2iGx7J4v0",
|
|
"name": "Freshdesk - Finance"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro-assist.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "\"status:2 OR status:3\""
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15120,
|
|
4864
|
|
],
|
|
"id": "61c96080-1240-46f4-a474-8feb2c0c7c1d",
|
|
"name": "Freshdesk - open general support tickets",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "eU5oyV62tEJdY6dV",
|
|
"name": "Freshdesk - general support"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "={{ $fromAI('search_query', 'Freshdesk search query string. Examples: \"requester:email@domain.com\", \"subject:invoice\". Always wrap in double quotes.', 'string') }}"
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15520,
|
|
4848
|
|
],
|
|
"id": "d0015e34-fe26-4915-b11f-f9eccd92a000",
|
|
"name": "Freshdesk archive - finance",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "CjhwO4a2iGx7J4v0",
|
|
"name": "Freshdesk - Finance"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro-assist.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "={{ $fromAI('search_query', 'Freshdesk search query string. Examples: \"requester:email@domain.com\", \"subject:invoice\". Always wrap in double quotes.', 'string') }}"
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15712,
|
|
4848
|
|
],
|
|
"id": "d81d88b1-d9ec-4494-8c17-04562a7022fa",
|
|
"name": "Freshdesk archive - general support",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "eU5oyV62tEJdY6dV",
|
|
"name": "Freshdesk - general support"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro.freshdesk.com/api/v2/contacts/autocomplete",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "term",
|
|
"value": "={{ $fromAI('contact_name', 'The name or partial name of the contact to search for.', 'string') }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15904,
|
|
4848
|
|
],
|
|
"id": "464ce97a-b552-4283-8524-73094ce05f5c",
|
|
"name": "Freshdesk Contact Lookup - Finance",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "IKEtEPEGfb3MGzuf",
|
|
"name": "Freshdesk - Finance"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro-assist.freshdesk.com/api/v2/contacts/autocomplete",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "term",
|
|
"value": "={{ $fromAI('contact_name', 'The name or partial name of the contact to search for.', 'string') }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
16112,
|
|
4832
|
|
],
|
|
"id": "35869ee7-d81e-4d14-b476-e273c2a591fc",
|
|
"name": "Freshdesk Contact Lookup - General Support",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "nTAuFBMj691S2ltO",
|
|
"name": "Freshdesk - general support"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"toolDescription": "Exports query results to a CSV file and returns a download URL. Pass a complete SELECT SQL query and a filename.",
|
|
"method": "POST",
|
|
"url": "https://moneybot.masttro.com/webhook/export-insert",
|
|
"sendBody": true,
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "filename",
|
|
"value": "={{ $fromAI('filename', 'CSV filename without extension, snake_case, e.g. contracts_renewal_2026-05-14') }}"
|
|
},
|
|
{
|
|
"name": "sql",
|
|
"value": "={{ $fromAI('sql', 'Complete SELECT SQL query to execute against the Postgres data warehouse') }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
14944,
|
|
4880
|
|
],
|
|
"id": "e3402386-a250-40c0-85af-43565fd8e04d",
|
|
"name": "Export_File"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "contractbot",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
14384,
|
|
4160
|
|
],
|
|
"id": "ea3b9e9a-0b4f-4c4c-ae3c-9f0bac57f118",
|
|
"name": "Webhook",
|
|
"webhookId": "8d835ff1-ebd9-471f-87e8-fbcb3eb3c6ef"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"assignments": {
|
|
"assignments": [
|
|
{
|
|
"id": "map-message",
|
|
"name": "chatInput",
|
|
"value": "={{ $json.body.message }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-sender",
|
|
"name": "sender",
|
|
"value": "={{ $json.body.sender }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-senderid",
|
|
"name": "senderId",
|
|
"value": "={{ $json.body.senderId }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-messageid",
|
|
"name": "messageId",
|
|
"value": "={{ $json.body.messageId }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-channelid",
|
|
"name": "channelId",
|
|
"value": "={{ $json.body.channelId }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-teamid",
|
|
"name": "teamId",
|
|
"value": "={{ $json.body.teamId }}",
|
|
"type": "string"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.set",
|
|
"typeVersion": 3.4,
|
|
"position": [
|
|
14640,
|
|
4144
|
|
],
|
|
"id": "a00987de-5146-4b26-883b-8ebc97f48ca9",
|
|
"name": "Map Teams Payload"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ JSON.stringify({ reply: $json.output }) }}",
|
|
"options": {
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.1,
|
|
"position": [
|
|
15472,
|
|
4432
|
|
],
|
|
"id": "5b755b0a-597f-460e-b475-a69e60e05512",
|
|
"name": "Respond to Teams"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://graph.microsoft.com/v1.0/me/chats?$filter=chatType eq 'oneOnOne'&$expand=members&$select=id,chatType&$top=50",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16224,
|
|
4416
|
|
],
|
|
"id": "eed2ede6-f2ee-40df-98a3-31eaed798c7c",
|
|
"name": "Get Teams DM Chats — returns all 1:1 chats with id and members. Search members for displayName or email matching the target person. Use chatId with Send Teams DM.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://graph.microsoft.com/v1.0/me/chats?$filter=chatType eq 'group'&$expand=members&$select=id,chatType,topic&$top=50",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16496,
|
|
4576
|
|
],
|
|
"id": "daf510e2-a1a0-4660-9e4e-f2d39adfaf63",
|
|
"name": "Get Teams Group Chats — returns all group chats with id, topic, and members. Match by topic name or member displayName. Use chatId with Send Teams DM.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://graph.microsoft.com/v1.0/me/joinedTeams?$select=id,displayName",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16224,
|
|
4576
|
|
],
|
|
"id": "97b32ae3-68d4-44a0-ab23-7ca45daa250b",
|
|
"name": "Get Teams List — returns all joined teams with id and displayName. Call this first to resolve a team name to a teamId before calling Get Teams Channels.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://graph.microsoft.com/v1.0/teams/{{ $fromAI('teamId', 'The team GUID from Get Teams List matching the target team displayName', 'string') }}/channels?$select=id,displayName",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16400,
|
|
4416
|
|
],
|
|
"id": "eb3a53df-8ace-4702-af98-20abca1c226a",
|
|
"name": "Get Teams Channels — given a teamId from Get Teams List, returns all channels with id and displayName. Use channelId and teamId together with Send Teams Channel Message.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"resource": "chatMessage",
|
|
"chatId": {
|
|
"__rl": true,
|
|
"value": "={{ $fromAI('chatId', 'The Teams chat GUID resolved from Get Teams DM Chats or Get Teams Group Chats. Never guess — always resolve first.', 'string') }}",
|
|
"mode": "id"
|
|
},
|
|
"message": "={{ $fromAI('message', 'Plain text message to send. No markdown tables. Use line breaks for structure. Summarize large datasets and offer export links rather than pasting rows.', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.microsoftTeamsTool",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
16560,
|
|
4368
|
|
],
|
|
"id": "068406e6-73c8-4aef-848b-540aedd534ba",
|
|
"name": "Send Teams DM",
|
|
"webhookId": "d0bf3351-3696-4ea0-adbd-ddec03926981",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"resource": "channelMessage",
|
|
"teamId": {
|
|
"__rl": true,
|
|
"value": "={{ $fromAI('teamId', 'The team GUID from Get Teams List matching the target team displayName', 'string') }}",
|
|
"mode": "id"
|
|
},
|
|
"channelId": {
|
|
"__rl": true,
|
|
"value": "={{ $fromAI('channelId', 'The channel GUID from Get Teams Channels matching the target channel displayName', 'string') }}",
|
|
"mode": "id"
|
|
},
|
|
"message": "={{ $fromAI('message', 'Plain text message to post. No markdown tables. Use line breaks for structure.', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.microsoftTeamsTool",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
16688,
|
|
4560
|
|
],
|
|
"id": "3fd0e16b-f259-47e5-abe5-76635d40b7b2",
|
|
"name": "Send Teams Channel Message",
|
|
"webhookId": "fb75f216-5c71-4ea0-867b-90abb819a51c",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "# Microsoft Teams",
|
|
"height": 400,
|
|
"width": 768
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
16144,
|
|
4320
|
|
],
|
|
"id": "4c2841ea-0be5-4485-9886-f974393c2d8b",
|
|
"name": "Sticky Note1"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "## Teams Webhook Path\n\nPower Automate POSTs to:\nhttps://moneybot.masttro.com/webhook/contractbot\n\nPayload: { message, sender, senderId, messageId, channelId, teamId }\n\nReply is returned as JSON: { reply: '...' }\nPower Automate reads body.reply and posts back to Teams.",
|
|
"height": 344,
|
|
"width": 500
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
14320,
|
|
3952
|
|
],
|
|
"id": "e7e6b1b9-61dc-4a19-b348-4e86dc645579",
|
|
"name": "Teams Webhook Note"
|
|
}
|
|
],
|
|
"connections": {
|
|
"When chat message received": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Webhook": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Map Teams Payload",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Map Teams Payload": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AI Agent": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Respond to Teams",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Simple Memory": {
|
|
"ai_memory": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_memory",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get FX Rate": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Hubspot deals": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Sonnet 4.6": {
|
|
"ai_languageModel": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_languageModel",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Postgres PGVector Store": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"mistral-embed": {
|
|
"ai_embedding": [
|
|
[
|
|
{
|
|
"node": "Postgres PGVector Store",
|
|
"type": "ai_embedding",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Contract_Direct_Lookup": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk - open finance tickets": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk - open general support tickets": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk archive - finance": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk archive - general support": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk Contact Lookup - Finance": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk Contact Lookup - General Support": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Export_File": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams DM Chats — returns all 1:1 chats with id and members. Search members for displayName or email matching the target person. Use chatId with Send Teams DM.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams Group Chats — returns all group chats with id, topic, and members. Match by topic name or member displayName. Use chatId with Send Teams DM.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams List — returns all joined teams with id and displayName. Call this first to resolve a team name to a teamId before calling Get Teams Channels.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams Channels — given a teamId from Get Teams List, returns all channels with id and displayName. Use channelId and teamId together with Send Teams Channel Message.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Send Teams DM": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Send Teams Channel Message": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"settings": {
|
|
"binaryMode": "separate",
|
|
"errorWorkflow": "tJSgL4iy63ys2NCA",
|
|
"availableInMCP": false,
|
|
"executionOrder": "v1"
|
|
},
|
|
"staticData": null,
|
|
"meta": {
|
|
"templateCredsSetupCompleted": true
|
|
},
|
|
"pinData": {},
|
|
"versionId": "679315e7-61ef-4b87-9b1e-5d6fe1b80544",
|
|
"activeVersionId": "679315e7-61ef-4b87-9b1e-5d6fe1b80544",
|
|
"triggerCount": 2,
|
|
"shared": [
|
|
{
|
|
"updatedAt": "2026-05-08T17:09:50.845Z",
|
|
"createdAt": "2026-05-08T17:09:50.845Z",
|
|
"role": "workflow:owner",
|
|
"workflowId": "eoMLOlRefzddaMQs",
|
|
"projectId": "X4TTvIwW8wN0Iirz"
|
|
}
|
|
],
|
|
"activeVersion": {
|
|
"updatedAt": "2026-05-22T15:22:04.438Z",
|
|
"createdAt": "2026-05-22T15:22:02.573Z",
|
|
"versionId": "679315e7-61ef-4b87-9b1e-5d6fe1b80544",
|
|
"workflowId": "eoMLOlRefzddaMQs",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"public": true,
|
|
"authentication": "basicAuth",
|
|
"initialMessages": "💰 MoneyBot online.\nI'm limited to querying 1,200+ contracts and amendments. I can export to csv too.",
|
|
"availableInChat": true,
|
|
"agentName": "Moneybot",
|
|
"options": {
|
|
"allowFileUploads": true
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
|
|
"typeVersion": 1.4,
|
|
"position": [
|
|
14816,
|
|
4576
|
|
],
|
|
"id": "d7a24034-2a15-4d6d-a013-434b70d7cb7a",
|
|
"name": "When chat message received",
|
|
"webhookId": "672bf651-91e6-41de-b897-13e54c0e1f10",
|
|
"alwaysOutputData": true,
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "zqSwWx9eXcAOQ4yE",
|
|
"name": "Masttr0! | Masttr0! basic auth"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "## Internal link using basic auth\n\nhttps://Masttr0!:Masttr0!@moneybot.masttro.com/webhook/672bf651-91e6-41de-b897-13e54c0e1f10/chat",
|
|
"height": 176,
|
|
"width": 464
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
15248,
|
|
4048
|
|
],
|
|
"id": "d03c3c99-ddd5-4d62-a364-1db45756e92b",
|
|
"name": "Sticky Note"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "# 🤖 Core — Trigger · Agent · LLMs · Memory\n\nEntry point and the AI brain. Connect your preferred LLM (Sonnet, Haiku, or Ollama) to the agent. Simple Memory provides per-session context.",
|
|
"height": 400,
|
|
"width": 1324,
|
|
"color": 3
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
14768,
|
|
4336
|
|
],
|
|
"id": "9e4efe01-5b4b-44a4-9921-91aee0647e51",
|
|
"name": "Sticky Core"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"options": {
|
|
"systemMessage": "=Current datetime is {{ $now }}\n\nYou are MoneyBot, a finance automation assistant for Masttro. You have access to:\n- QuickBooks Online: MUS (realm 9341452327761715, USD), MMX (realm 9341452328017372, USD), MSAG (realm 9341452373926753, CHF), MHAG (realm 9341452561201469, CHF — JE only), MGC (realm 9130354300064436, USD — JE only)\n- Postgres data warehouse: open invoices, payments, general ledger, HubSpot deals, chart of accounts, contracts\n- Freshdesk (support tickets)\n- FX Rate lookup, EML file generation, Teams messaging\n\n---\n\n## TOOL SELECTION\n\n| Intent | Tool |\n|---|---|\n| Open/unpaid invoices | Postgres: view_invoices_open |\n| Payments received | Postgres: view_payments |\n| General ledger / revenue | Postgres: AI_view_general_ledger |\n| Account ID lookup | Postgres: chartofaccounts — ALWAYS before JE |\n| HubSpot pipeline | Postgres: hubspot_deals |\n| HubSpot closed-won + billing | Postgres: view_hubspot_closedwon |\n| HubSpot owner lookup | Postgres: hubspot_owners |\n| Billing schedule | Postgres: view_hubspot_closedwon — see BILLING SCHEDULE |\n| Next invoice number | {ENTITY} - Get latest invoice DocNumber +1, collision-check |\n| Find customer | {ENTITY} - Find customer by name |\n| Find item/product | {ENTITY} - Find item by name |\n| Ad-hoc QBO query | {ENTITY} - Query QBO (QBQL) — always add WHERE + MAXRESULTS |\n| Create journal entry | {ENTITY} - Create Journal Entry — verify debits = credits |\n| Void journal entry | Fetch Id + SyncToken first, confirm, then {ENTITY} - Void Journal Entry |\n| Export data | Export_File — pass filename + sql |\n| Contract list / terms | Postgres: Contract_Direct_Lookup WHERE page_number = 1 |\n| Contract clause lookup | pgvector store first; fallback to Contract_Direct_Lookup |\n| Teams DM | Get Teams DM Chats → Send Teams DM |\n| Teams channel post | Get Teams List → Get Teams Channels → Send Teams Channel Message |\n\nNever dump all invoices/customers/payments from QBO. Always use Postgres views for list queries.\n\n---\n\n## CHART OF ACCOUNTS\nAlways query chartofaccounts before any JE — never use QBQL for account ID lookups.\nFilter: company_id, \"Active\" = true, match \"Name\" ILIKE or \"AcctNum\" ILIKE.\naccount_id is text — pass as string in AccountRef. Never cast.\n\n---\n\n## QBQL SYNTAX — critical\n- NO IN(...), NO OR, NO LIKE/ILIKE, NO AcctNum filter, NO subqueries, NO JOINs\n- Multiple values: separate tool calls per value\n- ORDERBY (no space), MAXRESULTS (not LIMIT), cap at 100\n- String values: single quotes only\n\n---\n\n## POSTGRES COLUMN RULES\n\n**view_invoices_open** — all lowercase. txndate is text; cast for arithmetic: txndate::date\n\n**view_payments** — company_id lowercase; all others double-quoted.\n\"TxnDate\" is DATE — use: \"TxnDate\" >= CURRENT_DATE - INTERVAL '7 days'\nNever compare to text literal.\n\n**AI_view_general_ledger** — exactly 6 columns: company_id, \"Date\", \"Memo_Description\", amount, \"Account\", \"Classification\"\n\"Date\" is text/varchar — always cast: \"Date\"::date for any date function.\nDate filter: \"Date\" >= TO_CHAR(DATE_TRUNC('year', NOW()), 'YYYY-MM-DD')\nNever use DATE_TRUNC(...)::text — produces timestamp string, breaks text compare.\nGROUP BY: repeat full expression, never alias.\nRevenue posts negative — always ABS(SUM(amount)).\nClassifications: Revenue, Expense, Asset, Liability, Equity\n\n**contracts** — all lowercase. Reference as just: contracts (no schema prefix).\nUse page_number = 1 for one row per contract.\n\n**hubspot_deals** — deal_name (underscore). No deal_url or deal_currency_code here — use view_hubspot_closedwon.\namount_in_home_currency = USD, use for cross-currency aggregations.\n\n**view_hubspot_closedwon** — filters to is_closed_won = true already. Always include deal_url in results.\n\n---\n\n## BILLING SCHEDULE\nSource: view_hubspot_closedwon. Billing frequency from contract term:\n- Monthly → first of each month in range\n- Quarterly/Semi-annual → anniversary-based from contract_start_date\n- Annual → contract_start_date anniversary in current year\n- NULL term → retrieve contract from pgvector/Contract_Direct_Lookup before defaulting\n\n---\n\n## CONTRACT RETRIEVAL\n1. pgvector store first — use specific clause language (\"semi-annual payment schedule\", \"termination notice period\")\n2. If wrong client chunks returned → immediately use Contract_Direct_Lookup\n3. Contract controls over HubSpot fields — flag discrepancies\n\n---\n\n## INVOICE CREATION\n1. customerId — Find customer by name\n2. itemId — Find item by name\n3. docNumber — Get latest +1, collision-check vs CreditMemo and Estimate\n4. taxCodeId — MUS/MMX/MSAG only; ask if unspecified\nConfirm with user before creating.\n\n## INVOICE SEND\nAlways resolve email first via Find customer / Get customer. Never send with null email.\n\n## INVOICE UPDATE\nFetch invoice first (Id + SyncToken + full Line array). Build update from fetched lines only.\n\n---\n\n## RECLASS JOURNAL ENTRY\n1. Fetch original (Id + SyncToken)\n2. Look up target account IDs via chartofaccounts\n3. Confirm debit/credit table with user\n4. Void original via {ENTITY} - Void Journal Entry\n5. Post corrected entry — DocNumber = original + \"-R\", PrivateNote = \"Reclass of [DocNumber]\"\n\n---\n\n## JOURNAL ENTRY RULES\n- Debits must equal credits\n- Always look up account IDs via chartofaccounts first\n- Confirm full debit/credit table before posting\n- MHAG/MGC: JE only — no invoice or customer tools\n- Department/Class: look up Id via QBQL before using\n\nEntity map: MUS (USD) · MMX (USD) · MSAG (CHF) · MHAG (CHF, JE only) · MGC (USD, JE only)\n\n---\n\n## CURRENCY\n- Entity home currencies: MUS/MMX/MGC = USD · MSAG/MHAG = CHF\n- After any GL query with MSAG/MHAG rows: call Get FX Rate, convert to USD, note the rate\n\n---\n\n## LARGE DATASET HANDLING\n- All filtering/joining in SQL — never loop per customer\n- Display: LIMIT 50 OFFSET N batches; collect silently, format once\n- Hard cap: 25 rows in chat. >25 rows: offer export. >100 rows: Export_File mandatory\n\n## FILE EXPORT\n- Export_File: pass filename (snake_case, no extension) + complete SELECT sql\n- Never assemble rows in memory — always pass SQL directly\n- Return the message field from response verbatim\n\n---\n\n## MICROSOFT TEAMS\nYour userId: 94387110-efa9-4e7f-8f18-3332df67c0a9 · email: mnolan@masttro.com\nAlways exclude yourself when identifying the other person in a chat.\n\nDM: Get Teams DM Chats → match non-self member → Send Teams DM (once, no retry)\nGroup: Get Teams Group Chats → match topic/member → Send Teams DM (once)\nChannel: Get Teams List → Get Teams Channels → Send Teams Channel Message (once)\n\nNever guess a chatId. Plain text only — no markdown tables in Teams messages.\n\n---\n\n## FRESHDESK\nOpen tickets (no filter): use open finance/general support nodes; count from total field\nBy person: Contact Lookup → archive search with requester:email\nBy keyword: archive search with subject:keyword\nNo parentheses in query strings. Never use contact_name as search field.\n\n---\n\n## OUTPUT RULES\n- Plain markdown only — never HTML tables\n- Never surface tool calls, node names, or tool selection reasoning\n- Never use hardcoded year literals — always derive from NOW()\n- Always confirm destructive/write actions before executing\n- ILIKE for all case-insensitive Postgres searches\n- NEVER SELECT * without WHERE clause"
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.agent",
|
|
"typeVersion": 3.1,
|
|
"position": [
|
|
15072,
|
|
4448
|
|
],
|
|
"id": "ff977ecc-c5e3-4d99-a890-c94405a2e433",
|
|
"name": "AI Agent"
|
|
},
|
|
{
|
|
"parameters": {},
|
|
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
14992,
|
|
4624
|
|
],
|
|
"id": "531ee4d4-62e3-4bb1-8614-ef827ae57514",
|
|
"name": "Simple Memory"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"toolDescription": "Fetch current exchange rates using exchangerate-api.com. Pass fromCurrency (e.g. USD) and the response will contain rates to all major currencies including CHF, EUR, etc.",
|
|
"url": "=https://api.exchangerate-api.com/v4/latest/{{ $fromAI('fromCurrency', 'Source currency code (e.g. USD, EUR, GBP)', 'string') || 'USD' }}",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Accept",
|
|
"value": "application/json"
|
|
},
|
|
{
|
|
"name": "User-Agent",
|
|
"value": "n8n-workflow"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
14784,
|
|
4880
|
|
],
|
|
"id": "5b0bf645-ee0c-4042-abad-af7517a3e10a",
|
|
"name": "Get FX Rate"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"descriptionType": "manual",
|
|
"toolDescription": "Query the view_hubspot_closedwon Postgres view for HubSpot closed-won deals. ALWAYS write a SELECT with a WHERE clause and LIMIT.",
|
|
"operation": "executeQuery",
|
|
"query": "{{ $fromAI('sql', 'A complete SELECT statement. MUST include a WHERE clause and a LIMIT (<= 500).', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.postgresTool",
|
|
"typeVersion": 2.6,
|
|
"position": [
|
|
15952,
|
|
4400
|
|
],
|
|
"id": "f3157be8-57f6-40ce-b4ce-e4c50ee9668c",
|
|
"name": "Hubspot deals",
|
|
"credentials": {
|
|
"postgres": {
|
|
"id": "NoPrLWbqySMMmIaI",
|
|
"name": "Postgres n8n-quickbooks"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"model": {
|
|
"__rl": true,
|
|
"value": "claude-haiku-4-5-20251001",
|
|
"mode": "list",
|
|
"cachedResultName": "Claude Haiku 4.5"
|
|
},
|
|
"options": {
|
|
"temperature": 0.2
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
15584,
|
|
4608
|
|
],
|
|
"id": "1d2f5886-6d7b-44c1-8cdc-06da7ab0efab",
|
|
"name": "Haiku 4.5",
|
|
"credentials": {
|
|
"anthropicApi": {
|
|
"id": "uJ4J74wLCEWqVd9B",
|
|
"name": "Anthropic - Moneybot"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"model": {
|
|
"__rl": true,
|
|
"value": "claude-sonnet-4-6",
|
|
"mode": "list",
|
|
"cachedResultName": "Claude Sonnet 4.6"
|
|
},
|
|
"options": {
|
|
"temperature": 0.2
|
|
}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
15376,
|
|
4592
|
|
],
|
|
"id": "02fce2ce-be02-4f2d-878b-85f2f71b87d5",
|
|
"name": "Sonnet 4.6",
|
|
"credentials": {
|
|
"anthropicApi": {
|
|
"id": "uJ4J74wLCEWqVd9B",
|
|
"name": "Anthropic - Moneybot"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "retrieve-as-tool",
|
|
"toolDescription": "Contract terms, payment schedules, billing frequency, SLA, termination clauses, effective dates — Postgres PGVector contract store.\n\nCRITICAL: Always use specific clause language in queries, NOT generic client+contract phrases.\nGOOD queries: \"semi-annual invoice payment schedule\", \"annual license fee payment timing\", \"termination notice period\"\nBAD queries: \"49 management contract terms\", \"client contract\"\n\nUse this tool first for any contract lookup. If results return chunks from the wrong client, immediately fall back to Contract_Direct_Lookup.",
|
|
"tableName": "contracts",
|
|
"topK": 20,
|
|
"options": {}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.vectorStorePGVector",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
15648,
|
|
4464
|
|
],
|
|
"id": "718be9dc-c636-4f80-9261-6cc7c8f02588",
|
|
"name": "Postgres PGVector Store",
|
|
"credentials": {
|
|
"postgres": {
|
|
"id": "YrHntSw7KF7Za0tK",
|
|
"name": "Postgres vectors"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"options": {}
|
|
},
|
|
"type": "@n8n/n8n-nodes-langchain.embeddingsMistralCloud",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
15776,
|
|
4592
|
|
],
|
|
"id": "cf033d73-5533-4ca2-96ef-497dea1e4b18",
|
|
"name": "mistral-embed",
|
|
"credentials": {
|
|
"mistralCloudApi": {
|
|
"id": "lHc1GsczHEq7NL55",
|
|
"name": "Mistral - contracts vector"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"descriptionType": "manual",
|
|
"toolDescription": "Direct SQL lookup of contract chunks from the contracts table by client name and/or section heading. Use as FALLBACK when pgvector returns chunks from the wrong client.\n\nExample: SELECT text, section_heading, page_number FROM contracts WHERE client_name ILIKE '%49 Management%' ORDER BY page_number ASC, id ASC LIMIT 50",
|
|
"operation": "executeQuery",
|
|
"query": "{{ $fromAI('sql', 'A complete SELECT against the contracts table. Always filter by client_name using ILIKE. Always include ORDER BY page_number ASC, id ASC and a LIMIT.', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.postgresTool",
|
|
"typeVersion": 2.6,
|
|
"position": [
|
|
15952,
|
|
4560
|
|
],
|
|
"id": "684b8901-931f-491b-90cd-404e647a5936",
|
|
"name": "Contract_Direct_Lookup",
|
|
"credentials": {
|
|
"postgres": {
|
|
"id": "NoPrLWbqySMMmIaI",
|
|
"name": "Postgres n8n-quickbooks"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "\"status:2 OR status:3\""
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15312,
|
|
4864
|
|
],
|
|
"id": "c6ec24f1-1b21-4fce-ae7b-5901681c377e",
|
|
"name": "Freshdesk - open finance tickets",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "CjhwO4a2iGx7J4v0",
|
|
"name": "Freshdesk - Finance"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro-assist.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "\"status:2 OR status:3\""
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15120,
|
|
4864
|
|
],
|
|
"id": "61c96080-1240-46f4-a474-8feb2c0c7c1d",
|
|
"name": "Freshdesk - open general support tickets",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "eU5oyV62tEJdY6dV",
|
|
"name": "Freshdesk - general support"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "={{ $fromAI('search_query', 'Freshdesk search query string. Examples: \"requester:email@domain.com\", \"subject:invoice\". Always wrap in double quotes.', 'string') }}"
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15520,
|
|
4848
|
|
],
|
|
"id": "d0015e34-fe26-4915-b11f-f9eccd92a000",
|
|
"name": "Freshdesk archive - finance",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "CjhwO4a2iGx7J4v0",
|
|
"name": "Freshdesk - Finance"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro-assist.freshdesk.com/api/v2/search/tickets",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "freshdeskApi",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "query",
|
|
"value": "={{ $fromAI('search_query', 'Freshdesk search query string. Examples: \"requester:email@domain.com\", \"subject:invoice\". Always wrap in double quotes.', 'string') }}"
|
|
},
|
|
{
|
|
"name": "page",
|
|
"value": "1"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15712,
|
|
4848
|
|
],
|
|
"id": "d81d88b1-d9ec-4494-8c17-04562a7022fa",
|
|
"name": "Freshdesk archive - general support",
|
|
"credentials": {
|
|
"freshdeskApi": {
|
|
"id": "eU5oyV62tEJdY6dV",
|
|
"name": "Freshdesk - general support"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro.freshdesk.com/api/v2/contacts/autocomplete",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "term",
|
|
"value": "={{ $fromAI('contact_name', 'The name or partial name of the contact to search for.', 'string') }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
15904,
|
|
4848
|
|
],
|
|
"id": "464ce97a-b552-4283-8524-73094ce05f5c",
|
|
"name": "Freshdesk Contact Lookup - Finance",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "IKEtEPEGfb3MGzuf",
|
|
"name": "Freshdesk - Finance"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://masttro-assist.freshdesk.com/api/v2/contacts/autocomplete",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBasicAuth",
|
|
"sendQuery": true,
|
|
"queryParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "term",
|
|
"value": "={{ $fromAI('contact_name', 'The name or partial name of the contact to search for.', 'string') }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
16112,
|
|
4832
|
|
],
|
|
"id": "35869ee7-d81e-4d14-b476-e273c2a591fc",
|
|
"name": "Freshdesk Contact Lookup - General Support",
|
|
"credentials": {
|
|
"httpBasicAuth": {
|
|
"id": "nTAuFBMj691S2ltO",
|
|
"name": "Freshdesk - general support"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"toolDescription": "Exports query results to a CSV file and returns a download URL. Pass a complete SELECT SQL query and a filename.",
|
|
"method": "POST",
|
|
"url": "https://moneybot.masttro.com/webhook/export-insert",
|
|
"sendBody": true,
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "filename",
|
|
"value": "={{ $fromAI('filename', 'CSV filename without extension, snake_case, e.g. contracts_renewal_2026-05-14') }}"
|
|
},
|
|
{
|
|
"name": "sql",
|
|
"value": "={{ $fromAI('sql', 'Complete SELECT SQL query to execute against the Postgres data warehouse') }}"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
14944,
|
|
4880
|
|
],
|
|
"id": "e3402386-a250-40c0-85af-43565fd8e04d",
|
|
"name": "Export_File"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "contractbot",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
14384,
|
|
4160
|
|
],
|
|
"id": "ea3b9e9a-0b4f-4c4c-ae3c-9f0bac57f118",
|
|
"name": "Webhook",
|
|
"webhookId": "8d835ff1-ebd9-471f-87e8-fbcb3eb3c6ef"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"assignments": {
|
|
"assignments": [
|
|
{
|
|
"id": "map-message",
|
|
"name": "chatInput",
|
|
"value": "={{ $json.body.message }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-sender",
|
|
"name": "sender",
|
|
"value": "={{ $json.body.sender }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-senderid",
|
|
"name": "senderId",
|
|
"value": "={{ $json.body.senderId }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-messageid",
|
|
"name": "messageId",
|
|
"value": "={{ $json.body.messageId }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-channelid",
|
|
"name": "channelId",
|
|
"value": "={{ $json.body.channelId }}",
|
|
"type": "string"
|
|
},
|
|
{
|
|
"id": "map-teamid",
|
|
"name": "teamId",
|
|
"value": "={{ $json.body.teamId }}",
|
|
"type": "string"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.set",
|
|
"typeVersion": 3.4,
|
|
"position": [
|
|
14640,
|
|
4144
|
|
],
|
|
"id": "a00987de-5146-4b26-883b-8ebc97f48ca9",
|
|
"name": "Map Teams Payload"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"respondWith": "json",
|
|
"responseBody": "={{ JSON.stringify({ reply: $json.output }) }}",
|
|
"options": {
|
|
"responseHeaders": {
|
|
"entries": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"type": "n8n-nodes-base.respondToWebhook",
|
|
"typeVersion": 1.1,
|
|
"position": [
|
|
15472,
|
|
4432
|
|
],
|
|
"id": "5b755b0a-597f-460e-b475-a69e60e05512",
|
|
"name": "Respond to Teams"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://graph.microsoft.com/v1.0/me/chats?$filter=chatType eq 'oneOnOne'&$expand=members&$select=id,chatType&$top=50",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16224,
|
|
4416
|
|
],
|
|
"id": "eed2ede6-f2ee-40df-98a3-31eaed798c7c",
|
|
"name": "Get Teams DM Chats — returns all 1:1 chats with id and members. Search members for displayName or email matching the target person. Use chatId with Send Teams DM.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://graph.microsoft.com/v1.0/me/chats?$filter=chatType eq 'group'&$expand=members&$select=id,chatType,topic&$top=50",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16496,
|
|
4576
|
|
],
|
|
"id": "daf510e2-a1a0-4660-9e4e-f2d39adfaf63",
|
|
"name": "Get Teams Group Chats — returns all group chats with id, topic, and members. Match by topic name or member displayName. Use chatId with Send Teams DM.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "https://graph.microsoft.com/v1.0/me/joinedTeams?$select=id,displayName",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16224,
|
|
4576
|
|
],
|
|
"id": "97b32ae3-68d4-44a0-ab23-7ca45daa250b",
|
|
"name": "Get Teams List — returns all joined teams with id and displayName. Call this first to resolve a team name to a teamId before calling Get Teams Channels.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "=https://graph.microsoft.com/v1.0/teams/{{ $fromAI('teamId', 'The team GUID from Get Teams List matching the target team displayName', 'string') }}/channels?$select=id,displayName",
|
|
"authentication": "predefinedCredentialType",
|
|
"nodeCredentialType": "microsoftTeamsOAuth2Api",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.httpRequestTool",
|
|
"typeVersion": 4.2,
|
|
"position": [
|
|
16400,
|
|
4416
|
|
],
|
|
"id": "eb3a53df-8ace-4702-af98-20abca1c226a",
|
|
"name": "Get Teams Channels — given a teamId from Get Teams List, returns all channels with id and displayName. Use channelId and teamId together with Send Teams Channel Message.",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"resource": "chatMessage",
|
|
"chatId": {
|
|
"__rl": true,
|
|
"value": "={{ $fromAI('chatId', 'The Teams chat GUID resolved from Get Teams DM Chats or Get Teams Group Chats. Never guess — always resolve first.', 'string') }}",
|
|
"mode": "id"
|
|
},
|
|
"message": "={{ $fromAI('message', 'Plain text message to send. No markdown tables. Use line breaks for structure. Summarize large datasets and offer export links rather than pasting rows.', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.microsoftTeamsTool",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
16560,
|
|
4368
|
|
],
|
|
"id": "068406e6-73c8-4aef-848b-540aedd534ba",
|
|
"name": "Send Teams DM",
|
|
"webhookId": "d0bf3351-3696-4ea0-adbd-ddec03926981",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"resource": "channelMessage",
|
|
"teamId": {
|
|
"__rl": true,
|
|
"value": "={{ $fromAI('teamId', 'The team GUID from Get Teams List matching the target team displayName', 'string') }}",
|
|
"mode": "id"
|
|
},
|
|
"channelId": {
|
|
"__rl": true,
|
|
"value": "={{ $fromAI('channelId', 'The channel GUID from Get Teams Channels matching the target channel displayName', 'string') }}",
|
|
"mode": "id"
|
|
},
|
|
"message": "={{ $fromAI('message', 'Plain text message to post. No markdown tables. Use line breaks for structure.', 'string') }}",
|
|
"options": {}
|
|
},
|
|
"type": "n8n-nodes-base.microsoftTeamsTool",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
16688,
|
|
4560
|
|
],
|
|
"id": "3fd0e16b-f259-47e5-abe5-76635d40b7b2",
|
|
"name": "Send Teams Channel Message",
|
|
"webhookId": "fb75f216-5c71-4ea0-867b-90abb819a51c",
|
|
"credentials": {
|
|
"microsoftTeamsOAuth2Api": {
|
|
"id": "VGkMYU2FoGJszbIJ",
|
|
"name": "Microsoft Teams account"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "# Microsoft Teams",
|
|
"height": 400,
|
|
"width": 768
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
16144,
|
|
4320
|
|
],
|
|
"id": "4c2841ea-0be5-4485-9886-f974393c2d8b",
|
|
"name": "Sticky Note1"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"content": "## Teams Webhook Path\n\nPower Automate POSTs to:\nhttps://moneybot.masttro.com/webhook/contractbot\n\nPayload: { message, sender, senderId, messageId, channelId, teamId }\n\nReply is returned as JSON: { reply: '...' }\nPower Automate reads body.reply and posts back to Teams.",
|
|
"height": 344,
|
|
"width": 500
|
|
},
|
|
"type": "n8n-nodes-base.stickyNote",
|
|
"typeVersion": 1,
|
|
"position": [
|
|
14320,
|
|
3952
|
|
],
|
|
"id": "e7e6b1b9-61dc-4a19-b348-4e86dc645579",
|
|
"name": "Teams Webhook Note"
|
|
}
|
|
],
|
|
"connections": {
|
|
"When chat message received": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Webhook": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Map Teams Payload",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Map Teams Payload": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"AI Agent": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Respond to Teams",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Simple Memory": {
|
|
"ai_memory": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_memory",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get FX Rate": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Hubspot deals": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Sonnet 4.6": {
|
|
"ai_languageModel": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_languageModel",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Postgres PGVector Store": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"mistral-embed": {
|
|
"ai_embedding": [
|
|
[
|
|
{
|
|
"node": "Postgres PGVector Store",
|
|
"type": "ai_embedding",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Contract_Direct_Lookup": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk - open finance tickets": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk - open general support tickets": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk archive - finance": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk archive - general support": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk Contact Lookup - Finance": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Freshdesk Contact Lookup - General Support": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Export_File": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams DM Chats — returns all 1:1 chats with id and members. Search members for displayName or email matching the target person. Use chatId with Send Teams DM.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams Group Chats — returns all group chats with id, topic, and members. Match by topic name or member displayName. Use chatId with Send Teams DM.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams List — returns all joined teams with id and displayName. Call this first to resolve a team name to a teamId before calling Get Teams Channels.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get Teams Channels — given a teamId from Get Teams List, returns all channels with id and displayName. Use channelId and teamId together with Send Teams Channel Message.": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Send Teams DM": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Send Teams Channel Message": {
|
|
"ai_tool": [
|
|
[
|
|
{
|
|
"node": "AI Agent",
|
|
"type": "ai_tool",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"nodeGroups": [],
|
|
"authors": "Michael Nolan",
|
|
"name": "Version 679315e7",
|
|
"description": "",
|
|
"autosaved": false
|
|
},
|
|
"tags": []
|
|
} |