| name | accounting-automation |
| description | Automate accounting workflows using QuickBooks and Xero APIs. Covers invoicing, expense tracking, bank reconciliation, financial reporting, and AI-powered bookkeeping automation. |
| license | Apache 2.0 |
| tags | ["accounting","quickbooks","xero","invoicing","bookkeeping","fintech","automation"] |
| difficulty | intermediate |
| time_to_master | 8-12 weeks |
| version | 1.0.0 |
Accounting Automation
Overview
QuickBooks (Intuit) and Xero dominate small-to-mid-market accounting with 10M+ combined customers. Their APIs enable AI agents to create invoices, categorize expenses, reconcile bank transactions, and generate financial reports — eliminating hours of manual bookkeeping. This skill covers both platforms' APIs and common automation patterns.
When to Use This Skill
- Building MCP servers for automated bookkeeping
- Creating invoice generation and payment tracking workflows
- Automating expense categorization with AI
- Implementing bank reconciliation automation
- Generating financial reports (P&L, balance sheet, cash flow)
- Syncing accounting data with CRM or ERP systems
Core Concepts
Platform Comparison
| Feature | QuickBooks Online | Xero |
|---|
| Market | US-dominant (80% SMB) | Strong in UK, AU, NZ |
| API Style | REST | REST |
| Auth | OAuth 2.0 | OAuth 2.0 |
| Webhooks | Yes | Yes |
| Sandbox | Yes (free) | Demo Company |
| Rate Limit | 500 req/min | 60 req/min |
Core Accounting Objects
Chart of Accounts
├── Assets (bank accounts, receivables)
├── Liabilities (payables, loans)
├── Income (revenue accounts)
├── Expenses (cost categories)
└── Equity (owner's equity)
Transactions
├── Invoices (money owed to you)
├── Bills (money you owe)
├── Payments (money received)
├── Expenses (money spent)
├── Journal Entries (manual adjustments)
└── Bank Transactions (imported from bank)
Implementation Guide
QuickBooks Online API
import OAuthClient from "intuit-oauth";
const oauthClient = new OAuthClient({
clientId: process.env.QBO_CLIENT_ID,
clientSecret: process.env.QBO_CLIENT_SECRET,
environment: "production",
redirectUri: process.env.QBO_REDIRECT_URI,
});
async function createInvoice(customerId, lineItems) {
const invoice = {
CustomerRef: { value: customerId },
Line: lineItems.map(item => ({
DetailType: "SalesItemLineDetail",
Amount: item.amount,
SalesItemLineDetail: {
ItemRef: { value: item.itemId },
Qty: item.quantity,
UnitPrice: item.unitPrice,
},
})),
DueDate: new Date(Date.now() + 30 * ).().()[],
};
response = qboClient.({
: ,
: ,
: .(invoice),
});
response..;
}
() {
query = ;
response = qboClient.({
: ,
});
response...;
}
Xero API
import { XeroClient } from "xero-node";
const xero = new XeroClient({
clientId: process.env.XERO_CLIENT_ID,
clientSecret: process.env.XERO_CLIENT_SECRET,
scopes: ["openid", "profile", "email", "accounting.transactions", "accounting.reports.read"],
});
async function createXeroInvoice(contactId, items) {
const invoice = {
type: "ACCREC",
contact: { contactID: contactId },
lineItems: items.map(item => ({
description: item.description,
quantity: item.quantity,
unitAmount: item.unitPrice,
accountCode: "200",
taxType: "OUTPUT2",
})),
date: new Date().toISOString().split("T")[],
: (.() + * ).().()[],
: ,
};
response = xero..(tenantId, { : [invoice] });
response..[];
}
() {
report = xero..(
tenantId, fromDate, toDate
);
report..[];
}
Accounting MCP Server
server.tool(
"get_financial_summary",
"Get a financial summary including revenue, expenses, and profit for a period",
{
period: z.enum(["this_month", "last_month", "this_quarter", "this_year"]),
platform: z.enum(["quickbooks", "xero"]),
},
async ({ period, platform }) => {
const { startDate, endDate } = resolvePeriod(period);
const pnl = await getProfitAndLoss(platform, startDate, endDate);
return {
content: [{
type: "text",
text: `Financial Summary (${period}):\n` +
`Revenue: $${pnl.totalIncome.toLocaleString()}\n` +
`COGS: $${pnl.costOfSales.toLocaleString()}\n` +
`Gross Profit: $${pnl.grossProfit.toLocaleString()} (${pnl.grossMargin.toFixed(1)}%)\n` +
`Operating Expenses: $${pnl.totalExpenses.toLocaleString()}\n` +
`Net Profit: $${pnl.netProfit.toLocaleString()} (${pnl.netMargin.toFixed(1)}%)\n`,
}],
};
}
);
server.tool(
"categorize_expenses",
"Auto-categorize uncategorized bank transactions using AI",
{
limit: z.().(),
},
({ limit }) => {
uncategorized = (limit);
categorized = uncategorized.( ({
...txn,
: (txn., txn.),
: (txn),
}));
{
: [{
: ,
: +
categorized.(
).(),
}],
};
}
);
Best Practices
- Use OAuth 2.0 with refresh tokens — never store user passwords
- Sandbox first — test all operations in sandbox before production
- Idempotent invoice creation — use external IDs to prevent duplicates
- Respect rate limits — QuickBooks: 500/min; Xero: 60/min
- Bank reconciliation should be human-approved — AI suggests, human confirms
- Audit trail everything — log every financial transaction modification
- Multi-currency handling — always store and convert amounts explicitly
Resources
Changelog
| Version | Date | Changes |
|---|
| 1.0.0 | 2026-03-31 | Initial documentation |