MCP App Store
Finance
Voder icon

Voder

by Windy Road Technology Pty Ltd

Overview

Ask your AI about your Xero numbers. Has a customer paid you. Who owes you money. Your cash position. What's outstanding. All in plain language, without opening Xero. Read-only: Voder looks, never touches.

Tools

voder_get_revenue_by_period

ChatGPT
Returns monthly revenue from Xero's profit-and-loss report for the requested month plus N prior monthly comparatives, alongside a per-account breakdown so you can see which revenue-classified accounts contribute. Server-side composition: fetches the chart of accounts to resolve accountType, calls Xero's profit-and-loss report for the requested single calendar month with periods=N for the comparatives, filters to revenue-classified accounts (accountType ∈ REVENUE / OTHERINCOME), and returns {periods: [{period, revenue, accounts: [{accountId, accountName, accountType, amount}]}], coverage: {startingMonth, periodsRequested, periodsReturned}}. Date-range constraints (invalid inputs are rejected before any Xero call): - fromDate and toDate MUST describe ONE single calendar month — same year-month, with fromDate on the 1st of the month and toDate on the last day (the 31st). Multi-month or full-year spans are rejected at the schema boundary. - The starting month MUST be one of January, March, May, July, August, October, or December — months that end on the 31st. February, April, June, September, and November cannot be the starting month. To report a February / April / June / September / November month, anchor on the next 31-day month (e.g. for February, anchor on March) and read that month's value from the comparatives column. - periods (1-24) — number of prior monthly comparative columns to return alongside the starting month. Use this for "show me monthly revenue", "how is revenue tracking month-on-month", "what's the trend on revenue over the last N months". Always present the per-account breakdown alongside the aggregate so you can spot a classification surprise — an account named in a revenue-suggesting way classified non-revenue, or one account contributing far more than expected.

voder_get_revenue_by_period

ChatGPT
Returns monthly revenue from Xero's profit-and-loss report for the requested month plus N prior monthly comparatives, alongside a per-account breakdown so you can see which revenue-classified accounts contribute. Server-side composition: fetches the chart of accounts to resolve accountType, calls Xero's profit-and-loss report for the requested single calendar month with periods=N for the comparatives, filters to revenue-classified accounts (accountType ∈ REVENUE / OTHERINCOME), and returns {periods: [{period, revenue, accounts: [{accountId, accountName, accountType, amount}]}], coverage: {startingMonth, periodsRequested, periodsReturned}}. Date-range constraints (invalid inputs are rejected before any Xero call): - fromDate and toDate MUST describe ONE single calendar month — same year-month, with fromDate on the 1st of the month and toDate on the last day (the 31st). Multi-month or full-year spans are rejected at the schema boundary. - The starting month MUST be one of January, March, May, July, August, October, or December — months that end on the 31st. February, April, June, September, and November cannot be the starting month. To report a February / April / June / September / November month, anchor on the next 31-day month (e.g. for February, anchor on March) and read that month's value from the comparatives column. - periods (1-24) — number of prior monthly comparative columns to return alongside the starting month. Use this for "show me monthly revenue", "how is revenue tracking month-on-month", "what's the trend on revenue over the last N months". Always present the per-account breakdown alongside the aggregate so you can spot a classification surprise — an account named in a revenue-suggesting way classified non-revenue, or one account contributing far more than expected.

voder_list_organisations

ChatGPT
List the organisations you can ask about, each with a human-readable name and an id. Use this when you need to know which organisations are available, or when a question could apply to more than one of them: show the names, let the user pick, then pass the chosen organisation's id as the organisationId argument to the data tools. If only one organisation is available, the data tools already use it by default and you do not need to call this first. Returns { organisations: [{ id, name }] }name is what to show the user; id is the value to pass as organisationId. Only the organisations you have access to are listed.

voder_list_organisations

ChatGPT
List the organisations you can ask about, each with a human-readable name and an id. Use this when you need to know which organisations are available, or when a question could apply to more than one of them: show the names, let the user pick, then pass the chosen organisation's id as the organisationId argument to the data tools. If only one organisation is available, the data tools already use it by default and you do not need to call this first. Returns { organisations: [{ id, name }] }name is what to show the user; id is the value to pass as organisationId. Only the organisations you have access to are listed.

voder_record_feedback

ChatGPT
Record an observation of user-facing friction, error, or annoyance for the Voder team's research loop — the co-discovery experiment depends on this signal. Invoke ONLY when ONE of these specific in-session friction signals occurred: (a) a Xero or bank-data tool returned an unexpected error or empty-result shape; (b) the user expressed confusion, repeated themselves, or asked for something the toolset cannot do; (c) you noticed a mismatch between what was asked and what the available tools can answer; (d) the user expressed a suggestion or wish for a capability that doesn't exist yet. Openness mandate: when you invoke this tool, you MUST tell the user openly in the same chat reply — e.g. "I'm noting this for the Voder team so they can improve the tool." Do NOT invoke this tool silently or describe its result without telling the user. If the user objects ("don't log that", "stop", "I don't want feedback recorded"), STOP invoking the tool for the remainder of the session and acknowledge the objection openly. Boundary: do NOT invoke at session-initiation or when nothing notable happened — this is a friction-response surface, not a session-opening or session-closing nudge. Data hygiene: summary and toolContext MUST NOT contain real Xero IDs, real bank-line UUIDs, customer revenue figures, organisation identifiers, or any payload data. Describe the OBSERVATION (e.g. "user asked for monthly recurring revenue but no tool surfaces it") not the PAYLOAD ("INV-1234 returned $5,874.00 from contact ABC-789"). Field shape: category (one of error/annoyance/friction/suggestion), summary (one-line observation, 1-2000 chars), toolContext (optional context string describing what the user was trying to do, 0-2000 chars).

voder_record_feedback

ChatGPT
Record an observation of user-facing friction, error, or annoyance for the Voder team's research loop — the co-discovery experiment depends on this signal. Invoke ONLY when ONE of these specific in-session friction signals occurred: (a) a Xero or bank-data tool returned an unexpected error or empty-result shape; (b) the user expressed confusion, repeated themselves, or asked for something the toolset cannot do; (c) you noticed a mismatch between what was asked and what the available tools can answer; (d) the user expressed a suggestion or wish for a capability that doesn't exist yet. Openness mandate: when you invoke this tool, you MUST tell the user openly in the same chat reply — e.g. "I'm noting this for the Voder team so they can improve the tool." Do NOT invoke this tool silently or describe its result without telling the user. If the user objects ("don't log that", "stop", "I don't want feedback recorded"), STOP invoking the tool for the remainder of the session and acknowledge the objection openly. Boundary: do NOT invoke at session-initiation or when nothing notable happened — this is a friction-response surface, not a session-opening or session-closing nudge. Data hygiene: summary and toolContext MUST NOT contain real Xero IDs, real bank-line UUIDs, customer revenue figures, organisation identifiers, or any payload data. Describe the OBSERVATION (e.g. "user asked for monthly recurring revenue but no tool surfaces it") not the PAYLOAD ("INV-1234 returned $5,874.00 from contact ABC-789"). Field shape: category (one of error/annoyance/friction/suggestion), summary (one-line observation, 1-2000 chars), toolContext (optional context string describing what the user was trying to do, 0-2000 chars).

xero_aged_payables_by_contact

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool to answer any payables question): this tool is the question-shaped surface for payables DRILL-DOWN to a single named supplier — "how much do we owe <named supplier>?", "is the Acme bill overdue?", "give me the aged payables breakdown for <supplier>". For the cross-supplier headline ("What do I owe suppliers?", "How much is outstanding in payables?", "What bills are about to be paid vs awaiting approval?"), prefer xero_list_invoices — its apBreakdown carrier already pre-aggregates the answer across all suppliers, splitting approved (AUTHORISED — about to leave the bank) from pendingApproval (SUBMITTED — awaiting your approval). Use THIS tool ONLY when the question names a specific supplier OR when the caller has already identified a ContactID and wants the aged-bucket breakdown for that one supplier. Aged payables report for a specific contact. Shows what we owe them and how overdue.

xero_aged_payables_by_contact

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool to answer any payables question): this tool is the question-shaped surface for payables DRILL-DOWN to a single named supplier — "how much do we owe <named supplier>?", "is the Acme bill overdue?", "give me the aged payables breakdown for <supplier>". For the cross-supplier headline ("What do I owe suppliers?", "How much is outstanding in payables?", "What bills are about to be paid vs awaiting approval?"), prefer xero_list_invoices — its apBreakdown carrier already pre-aggregates the answer across all suppliers, splitting approved (AUTHORISED — about to leave the bank) from pendingApproval (SUBMITTED — awaiting your approval). Use THIS tool ONLY when the question names a specific supplier OR when the caller has already identified a ContactID and wants the aged-bucket breakdown for that one supplier. Aged payables report for a specific contact. Shows what we owe them and how overdue.

xero_aged_receivables_by_contact

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool to answer any receivables question): this tool is the question-shaped surface for receivables DRILL-DOWN to a single named contact — "how much does <named customer> owe me?", "how overdue is Acme's invoice?", "give me the aged receivables breakdown for <customer>". For the cross-customer headline ("Who owes us money?", "How much do customers owe me, and how much is overdue?", "What's outstanding in receivables?"), prefer xero_list_invoices — its arBreakdown carrier already pre-aggregates the answer across all customers, including a byContact rollup that names the biggest owers; you do NOT need to walk per-contact aged-receivables calls to assemble it. Use THIS tool ONLY when the question names a specific contact OR when the caller has already identified a ContactID and wants the aged-bucket breakdown for that one contact. Aged receivables report for a specific contact. Shows what they owe and how overdue.

xero_aged_receivables_by_contact

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool to answer any receivables question): this tool is the question-shaped surface for receivables DRILL-DOWN to a single named contact — "how much does <named customer> owe me?", "how overdue is Acme's invoice?", "give me the aged receivables breakdown for <customer>". For the cross-customer headline ("Who owes us money?", "How much do customers owe me, and how much is overdue?", "What's outstanding in receivables?"), prefer xero_list_invoices — its arBreakdown carrier already pre-aggregates the answer across all customers, including a byContact rollup that names the biggest owers; you do NOT need to walk per-contact aged-receivables calls to assemble it. Use THIS tool ONLY when the question names a specific contact OR when the caller has already identified a ContactID and wants the aged-bucket breakdown for that one contact. Aged receivables report for a specific contact. Shows what they owe and how overdue.

xero_list_accounts

ChatGPT
Returns the chart of accounts. Each account carries an accountType (REVENUE, OTHERINCOME, EXPENSE, DIRECTCOSTS, OVERHEADS, CURRENT, FIXED, EQUITY, etc.) — use this to resolve which accounts are revenue-classified, expense-classified, or balance-sheet-classified rather than guessing from the account name. Account names alone are unreliable signals — the same account name can be classified differently across organisations. Always cross-check the accountType before treating a row in a Xero report as revenue, expense, or anything else. Filter to a single accountType to narrow the result set. Default status: 'active' excludes ARCHIVED accounts; pass status: 'all' to include them.

xero_list_accounts

ChatGPT
Returns the chart of accounts. Each account carries an accountType (REVENUE, OTHERINCOME, EXPENSE, DIRECTCOSTS, OVERHEADS, CURRENT, FIXED, EQUITY, etc.) — use this to resolve which accounts are revenue-classified, expense-classified, or balance-sheet-classified rather than guessing from the account name. Account names alone are unreliable signals — the same account name can be classified differently across organisations. Always cross-check the accountType before treating a row in a Xero report as revenue, expense, or anything else. Filter to a single accountType to narrow the result set. Default status: 'active' excludes ARCHIVED accounts; pass status: 'all' to include them.

xero_list_bank_transactions

ChatGPT
List Xero BankTransactions — Xero's RECONCILED view of bank-account activity. Returns ONLY reconciled (matched + categorised) entries — a recent payment that has landed in the bank but not yet been reconciled (typically the last 1-3 days) is NOT visible via this tool, because Xero sees only the reconciled subset of bank-account transactions. Use this tool for: confirming a known payment has been reconciled in Xero, listing categorised bank activity across accounts, or cross-referencing Xero's matched view. Most-recent first. The isReconciled filter operates on Xero's category-match axis (isReconciled: false mostly returns DELETED historical entries — NOT recent payments). Default returns AUTHORISED (live) lines; status: 'all' includes DELETED for audit. PAYMENT-STATUS ANSWER POLICY (read before answering any 'has X paid / did X pay / has the invoice been paid?' question): Xero shows ONLY reconciled bank activity, so an invoice that is AUTHORISED or has no payments recorded is NOT evidence of non-payment — a payment may have landed in the bank and simply not been matched yet. There are only TWO valid answers to a payment-status question: (1) PAID — when the invoice status is PAID or a reconciled payment exists; or (2) UNKNOWN — when Xero shows AUTHORISED / unpaid / no payments recorded. You MUST NOT answer 'No', 'not paid', 'still unpaid', 'no payment received', or otherwise state the invoice is unpaid — Xero cannot distinguish 'unpaid' from 'paid-but-not-yet-reconciled'. Do NOT lead with 'No'. Instead lead with the UNKNOWN framing, e.g.: "I can't confirm from Xero — the invoice shows AUTHORISED (Xero only sees reconciled payments), so a payment may have arrived but not been matched yet. Check the bank or chase the customer to be sure." Recent payments (last 1-3 days especially) are the common unreconciled case. Each invoice row carries an explicit paymentStatus field (paid or unknown) — use it as the authoritative answer token. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_bank_transactions

ChatGPT
List Xero BankTransactions — Xero's RECONCILED view of bank-account activity. Returns ONLY reconciled (matched + categorised) entries — a recent payment that has landed in the bank but not yet been reconciled (typically the last 1-3 days) is NOT visible via this tool, because Xero sees only the reconciled subset of bank-account transactions. Use this tool for: confirming a known payment has been reconciled in Xero, listing categorised bank activity across accounts, or cross-referencing Xero's matched view. Most-recent first. The isReconciled filter operates on Xero's category-match axis (isReconciled: false mostly returns DELETED historical entries — NOT recent payments). Default returns AUTHORISED (live) lines; status: 'all' includes DELETED for audit. PAYMENT-STATUS ANSWER POLICY (read before answering any 'has X paid / did X pay / has the invoice been paid?' question): Xero shows ONLY reconciled bank activity, so an invoice that is AUTHORISED or has no payments recorded is NOT evidence of non-payment — a payment may have landed in the bank and simply not been matched yet. There are only TWO valid answers to a payment-status question: (1) PAID — when the invoice status is PAID or a reconciled payment exists; or (2) UNKNOWN — when Xero shows AUTHORISED / unpaid / no payments recorded. You MUST NOT answer 'No', 'not paid', 'still unpaid', 'no payment received', or otherwise state the invoice is unpaid — Xero cannot distinguish 'unpaid' from 'paid-but-not-yet-reconciled'. Do NOT lead with 'No'. Instead lead with the UNKNOWN framing, e.g.: "I can't confirm from Xero — the invoice shows AUTHORISED (Xero only sees reconciled payments), so a payment may have arrived but not been matched yet. Check the bank or chase the customer to be sure." Recent payments (last 1-3 days especially) are the common unreconciled case. Each invoice row carries an explicit paymentStatus field (paid or unknown) — use it as the authoritative answer token. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_contacts

ChatGPT
Search and list Xero contacts (customers and suppliers). The entry point for payment-status questions: start here to resolve a contact name to a ContactID, then call xero_list_invoices(contactId, status: 'paid') to confirm payment status. searchTerm performs a case-insensitive substring match across the contact's display name, first name, last name, contact number, company number, email, and account number — so a partial token, an email fragment, or a customer reference all work. Do not retry case variations on a zero result; the match is already case-insensitive — try a different word or check the spelling against the Xero UI. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_contacts

ChatGPT
Search and list Xero contacts (customers and suppliers). The entry point for payment-status questions: start here to resolve a contact name to a ContactID, then call xero_list_invoices(contactId, status: 'paid') to confirm payment status. searchTerm performs a case-insensitive substring match across the contact's display name, first name, last name, contact number, company number, email, and account number — so a partial token, an email fragment, or a customer reference all work. Do not retry case variations on a zero result; the match is already case-insensitive — try a different word or check the spelling against the Xero UI. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_credit_notes

ChatGPT
List Xero credit notes, most-recent first, optionally filtered by contact. Supplementary surface for aged-ledger questions — credit notes adjust outstanding balances and refunds. By default returns only LIVE credit notes (DRAFT, SUBMITTED, AUTHORISED, PAID) — excludes DELETED and VOIDED so aged-ledger answers reflect live entries. Pass status: 'all' to include DELETED + VOIDED for audit queries. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_credit_notes

ChatGPT
List Xero credit notes, most-recent first, optionally filtered by contact. Supplementary surface for aged-ledger questions — credit notes adjust outstanding balances and refunds. By default returns only LIVE credit notes (DRAFT, SUBMITTED, AUTHORISED, PAID) — excludes DELETED and VOIDED so aged-ledger answers reflect live entries. Pass status: 'all' to include DELETED + VOIDED for audit queries. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_invoices

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool): this is the question-shaped surface for THREE invoice-related question classes — pick this tool first when the user is asking any of them: (A) "Has invoice <NN> been paid?" / "Did <customer> pay invoice <NN>?" → call with the invoiceNumber filter; read the invoiceLookupResult carrier as the structural answer. (B) "Who owes us money?" / "How much do customers owe me?" / "What's outstanding in receivables?" / "How much is overdue?" → call WITHOUT invoiceNumber; read the arBreakdown carrier (it pre-aggregates customer-by-customer with a byContact rollup naming the biggest owers and an overdue split). (C) "What do I owe suppliers?" / "How much is outstanding in bills?" / "What's about to leave the bank account?" / "What's awaiting my approval?" → call WITHOUT invoiceNumber; read the apBreakdown carrier (it splits approved / pendingApproval / combined so the answer distinguishes "about to be paid" from "awaiting your decision"). DO NOT pick this tool when the user names a SPECIFIC customer/supplier and asks for that one party's drill-down — for "how much does Acme owe me?" or "is the Acme bill overdue?", prefer xero_aged_receivables_by_contact / xero_aged_payables_by_contact (cheaper, single Xero call). Use this tool when the answer needs the headline aggregate or per-row detail. List Xero invoices, optionally filtered by contact, invoice number, and status. Most-recent first. Xero invoice status (AUTHORISED, PAID, etc.) reflects what Xero has RECONCILED — for 'did <contact> pay?' an AUTHORISED (unpaid) invoice does not prove non-payment, because a recent payment may have landed but not yet been reconciled in Xero. By default returns only LIVE invoices (DRAFT, SUBMITTED, AUTHORISED, PAID) — excludes DELETED and VOIDED so payment-status answers are not polluted by historical voided entries. Pass status: 'all' to include DELETED + VOIDED for audit queries, or a specific status to narrow further. PAYMENT-STATUS ANSWER POLICY (read before answering any 'has X paid / did X pay / has the invoice been paid?' question): Xero shows ONLY reconciled bank activity, so an invoice that is AUTHORISED or has no payments recorded is NOT evidence of non-payment — a payment may have landed in the bank and simply not been matched yet. There are only TWO valid answers to a payment-status question: (1) PAID — when the invoice status is PAID or a reconciled payment exists; or (2) UNKNOWN — when Xero shows AUTHORISED / unpaid / no payments recorded. You MUST NOT answer 'No', 'not paid', 'still unpaid', 'no payment received', or otherwise state the invoice is unpaid — Xero cannot distinguish 'unpaid' from 'paid-but-not-yet-reconciled'. Do NOT lead with 'No'. Instead lead with the UNKNOWN framing, e.g.: "I can't confirm from Xero — the invoice shows AUTHORISED (Xero only sees reconciled payments), so a payment may have arrived but not been matched yet. Check the bank or chase the customer to be sure." Recent payments (last 1-3 days especially) are the common unreconciled case. Each invoice row carries an explicit paymentStatus field (paid or unknown) — use it as the authoritative answer token. INVOICE-LOOKUP ANSWER POLICY (read before answering any "does invoice <NN> exist / has invoice <NN> been paid?" question): when the caller passes an invoiceNumber filter, the response carries a structural invoiceLookupResult: { invoiceNumber, status: 'not_found' | 'found_paid' | 'found_unpaid' } carrier. Read the carrier as the load-bearing answer token. When invoiceLookupResult.status === 'not_found', the answer is simply "invoice <NN> doesn't exist in this Xero org" — full stop. You MUST NOT hedge with phrases like "the invoice number may be different in Xero", "may belong to another organisation", "the payment hasn't been reconciled yet", or any other plausible-but-wrong explanation that would erode the customer's trust in the answer. The not-found token means the requested invoice number is genuinely absent from this Xero organisation; each question is already s…

xero_list_invoices

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool): this is the question-shaped surface for THREE invoice-related question classes — pick this tool first when the user is asking any of them: (A) "Has invoice <NN> been paid?" / "Did <customer> pay invoice <NN>?" → call with the invoiceNumber filter; read the invoiceLookupResult carrier as the structural answer. (B) "Who owes us money?" / "How much do customers owe me?" / "What's outstanding in receivables?" / "How much is overdue?" → call WITHOUT invoiceNumber; read the arBreakdown carrier (it pre-aggregates customer-by-customer with a byContact rollup naming the biggest owers and an overdue split). (C) "What do I owe suppliers?" / "How much is outstanding in bills?" / "What's about to leave the bank account?" / "What's awaiting my approval?" → call WITHOUT invoiceNumber; read the apBreakdown carrier (it splits approved / pendingApproval / combined so the answer distinguishes "about to be paid" from "awaiting your decision"). DO NOT pick this tool when the user names a SPECIFIC customer/supplier and asks for that one party's drill-down — for "how much does Acme owe me?" or "is the Acme bill overdue?", prefer xero_aged_receivables_by_contact / xero_aged_payables_by_contact (cheaper, single Xero call). Use this tool when the answer needs the headline aggregate or per-row detail. List Xero invoices, optionally filtered by contact, invoice number, and status. Most-recent first. Xero invoice status (AUTHORISED, PAID, etc.) reflects what Xero has RECONCILED — for 'did <contact> pay?' an AUTHORISED (unpaid) invoice does not prove non-payment, because a recent payment may have landed but not yet been reconciled in Xero. By default returns only LIVE invoices (DRAFT, SUBMITTED, AUTHORISED, PAID) — excludes DELETED and VOIDED so payment-status answers are not polluted by historical voided entries. Pass status: 'all' to include DELETED + VOIDED for audit queries, or a specific status to narrow further. PAYMENT-STATUS ANSWER POLICY (read before answering any 'has X paid / did X pay / has the invoice been paid?' question): Xero shows ONLY reconciled bank activity, so an invoice that is AUTHORISED or has no payments recorded is NOT evidence of non-payment — a payment may have landed in the bank and simply not been matched yet. There are only TWO valid answers to a payment-status question: (1) PAID — when the invoice status is PAID or a reconciled payment exists; or (2) UNKNOWN — when Xero shows AUTHORISED / unpaid / no payments recorded. You MUST NOT answer 'No', 'not paid', 'still unpaid', 'no payment received', or otherwise state the invoice is unpaid — Xero cannot distinguish 'unpaid' from 'paid-but-not-yet-reconciled'. Do NOT lead with 'No'. Instead lead with the UNKNOWN framing, e.g.: "I can't confirm from Xero — the invoice shows AUTHORISED (Xero only sees reconciled payments), so a payment may have arrived but not been matched yet. Check the bank or chase the customer to be sure." Recent payments (last 1-3 days especially) are the common unreconciled case. Each invoice row carries an explicit paymentStatus field (paid or unknown) — use it as the authoritative answer token. INVOICE-LOOKUP ANSWER POLICY (read before answering any "does invoice <NN> exist / has invoice <NN> been paid?" question): when the caller passes an invoiceNumber filter, the response carries a structural invoiceLookupResult: { invoiceNumber, status: 'not_found' | 'found_paid' | 'found_unpaid' } carrier. Read the carrier as the load-bearing answer token. When invoiceLookupResult.status === 'not_found', the answer is simply "invoice <NN> doesn't exist in this Xero org" — full stop. You MUST NOT hedge with phrases like "the invoice number may be different in Xero", "may belong to another organisation", "the payment hasn't been reconciled yet", or any other plausible-but-wrong explanation that would erode the customer's trust in the answer. The not-found token means the requested invoice number is genuinely absent from this Xero organisation; each question is already s…

xero_list_payments

ChatGPT
List Xero payment records, optionally filtered by invoice or reference. Most-recent first. Each payment object links to one invoice — use as a secondary lookup AFTER xero_list_invoices has identified the invoice, e.g. "how was INV-1234 paid?" or "which payments came in this week?". By default returns only AUTHORISED (live) payments — excludes DELETED so payment-status answers are not polluted by reversed payment entries. Pass status: 'all' to include DELETED for audit queries. PAYMENT-STATUS ANSWER POLICY (read before answering any 'has X paid / did X pay / has the invoice been paid?' question): Xero shows ONLY reconciled bank activity, so an invoice that is AUTHORISED or has no payments recorded is NOT evidence of non-payment — a payment may have landed in the bank and simply not been matched yet. There are only TWO valid answers to a payment-status question: (1) PAID — when the invoice status is PAID or a reconciled payment exists; or (2) UNKNOWN — when Xero shows AUTHORISED / unpaid / no payments recorded. You MUST NOT answer 'No', 'not paid', 'still unpaid', 'no payment received', or otherwise state the invoice is unpaid — Xero cannot distinguish 'unpaid' from 'paid-but-not-yet-reconciled'. Do NOT lead with 'No'. Instead lead with the UNKNOWN framing, e.g.: "I can't confirm from Xero — the invoice shows AUTHORISED (Xero only sees reconciled payments), so a payment may have arrived but not been matched yet. Check the bank or chase the customer to be sure." Recent payments (last 1-3 days especially) are the common unreconciled case. Each invoice row carries an explicit paymentStatus field (paid or unknown) — use it as the authoritative answer token. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_list_payments

ChatGPT
List Xero payment records, optionally filtered by invoice or reference. Most-recent first. Each payment object links to one invoice — use as a secondary lookup AFTER xero_list_invoices has identified the invoice, e.g. "how was INV-1234 paid?" or "which payments came in this week?". By default returns only AUTHORISED (live) payments — excludes DELETED so payment-status answers are not polluted by reversed payment entries. Pass status: 'all' to include DELETED for audit queries. PAYMENT-STATUS ANSWER POLICY (read before answering any 'has X paid / did X pay / has the invoice been paid?' question): Xero shows ONLY reconciled bank activity, so an invoice that is AUTHORISED or has no payments recorded is NOT evidence of non-payment — a payment may have landed in the bank and simply not been matched yet. There are only TWO valid answers to a payment-status question: (1) PAID — when the invoice status is PAID or a reconciled payment exists; or (2) UNKNOWN — when Xero shows AUTHORISED / unpaid / no payments recorded. You MUST NOT answer 'No', 'not paid', 'still unpaid', 'no payment received', or otherwise state the invoice is unpaid — Xero cannot distinguish 'unpaid' from 'paid-but-not-yet-reconciled'. Do NOT lead with 'No'. Instead lead with the UNKNOWN framing, e.g.: "I can't confirm from Xero — the invoice shows AUTHORISED (Xero only sees reconciled payments), so a payment may have arrived but not been matched yet. Check the bank or chase the customer to be sure." Recent payments (last 1-3 days especially) are the common unreconciled case. Each invoice row carries an explicit paymentStatus field (paid or unknown) — use it as the authoritative answer token. PAGINATION ANSWER POLICY (read before answering): this tool paginates the row array. The structural carriers above the row array (where present) are computed SERVER-SIDE across ALL pages — they carry the complete answer to aggregate questions about totals, counts, and per-contact rollups. The row array contains ONLY this page's slice. The pagination envelope at the end of the response carries { page, pageSize, pageCount, itemCount, hasMore } so you can detect when more pages exist. Answer aggregate questions (who, how much, how many) directly from the carrier on page 1; only walk pagination (page: N+1) when the user explicitly asks for per-row detail beyond page 1.

xero_organisation_details

ChatGPT
The connected Xero organisation: legal name, country, base currency, financial-year-end.

xero_organisation_details

ChatGPT
The connected Xero organisation: legal name, country, base currency, financial-year-end.

xero_trial_balance

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool to answer cash questions): this tool is the question-shaped surface for cash-position questions — "How much cash do I have?", "What's our cash position?", "How much is in the bank?", "Are we cash-positive right now?". The structural cashPosition carrier (described below) pre-computes the answer; you should pick THIS tool first for any cash-position question and read the carrier rather than walking the chart of accounts yourself. Trial balance report as at a specific date. For 'how much cash do we have right now' questions, use the structural `cashPosition` carrier — DO NOT infer the sign from Xero's `Debit`/`Credit` column labels. The carrier shape is cashPosition: { accounts: [{accountId, name, signedAmount, currency}], totals: [{currency, signedAmount}] }. signedAmount uses the customer's perspective: positive = money the customer HAS in the bank, negative = overdraft / amount owed to the bank. Read cashPosition.totals directly to answer the cash-position question (one entry per currency for multi-currency organisations). The raw trial-balance report continues to be returned alongside for general-purpose questions, but the credit/debit column orientation in that raw report is NOT a reliable signal for cash position — cashPosition.totals is the authoritative answer token. EMPTY-OR-ZERO CARRIER POLICY (read before answering any cash-position question): when cashPosition.totals is an empty array (no bank accounts found on the chart of accounts), the answer MUST say "no bank accounts are connected on the chart of accounts — open the Xero dashboard or ask your finance team to confirm the bank feed is connected" — DO NOT fabricate a dollar figure. When cashPosition.totals carries one or more entries but every entry's signedAmount === 0 AND every account in cashPosition.accounts has signedAmount === 0, the answer MUST say "all bank accounts on the chart of accounts have a zero balance as at this date — open the Xero dashboard to confirm the trial-balance report ran for the right date" — again, DO NOT fabricate a dollar figure. You MUST NOT invent, estimate, or approximate any cash amount when the carrier is empty or all-zero; the only valid responses are the two phrasings above. A non-zero signedAmount on any account is the only signal that licenses a numeric cash answer.

xero_trial_balance

ChatGPT
QUESTION-DRIVEN ANSWER POLICY (read before picking a tool to answer cash questions): this tool is the question-shaped surface for cash-position questions — "How much cash do I have?", "What's our cash position?", "How much is in the bank?", "Are we cash-positive right now?". The structural cashPosition carrier (described below) pre-computes the answer; you should pick THIS tool first for any cash-position question and read the carrier rather than walking the chart of accounts yourself. Trial balance report as at a specific date. For 'how much cash do we have right now' questions, use the structural `cashPosition` carrier — DO NOT infer the sign from Xero's `Debit`/`Credit` column labels. The carrier shape is cashPosition: { accounts: [{accountId, name, signedAmount, currency}], totals: [{currency, signedAmount}] }. signedAmount uses the customer's perspective: positive = money the customer HAS in the bank, negative = overdraft / amount owed to the bank. Read cashPosition.totals directly to answer the cash-position question (one entry per currency for multi-currency organisations). The raw trial-balance report continues to be returned alongside for general-purpose questions, but the credit/debit column orientation in that raw report is NOT a reliable signal for cash position — cashPosition.totals is the authoritative answer token. EMPTY-OR-ZERO CARRIER POLICY (read before answering any cash-position question): when cashPosition.totals is an empty array (no bank accounts found on the chart of accounts), the answer MUST say "no bank accounts are connected on the chart of accounts — open the Xero dashboard or ask your finance team to confirm the bank feed is connected" — DO NOT fabricate a dollar figure. When cashPosition.totals carries one or more entries but every entry's signedAmount === 0 AND every account in cashPosition.accounts has signedAmount === 0, the answer MUST say "all bank accounts on the chart of accounts have a zero balance as at this date — open the Xero dashboard to confirm the trial-balance report ran for the right date" — again, DO NOT fabricate a dollar figure. You MUST NOT invent, estimate, or approximate any cash amount when the carrier is empty or all-zero; the only valid responses are the two phrasings above. A non-zero signedAmount on any account is the only signal that licenses a numeric cash answer.

Capabilities

Writes

App Stats

26

Tools

ChatGPT

Platforms

Works with

ChatGPT

Data refreshed daily