Status
Ready for OAuth
Environmentsandbox
API base URLhttps://sandbox-quickbooks.api.intuit.com
Current realm9341455204820813
Stored connections1
Token store path/app/data/qbo-tokens.json
This small Next.js service handles QuickBooks Online OAuth, stores the latest tokens in a local JSON file, exposes a health endpoint, and now provides a native-first bookkeeping v1: standard QuickBooks objects for vendors, expenses, and reports, with journal entries reserved for exception handling only.
Ready for OAuth
QBO_CLIENT_IDQBO_CLIENT_SECRETQBO_ENVQBO_REDIRECT_URIQBO_SCOPESQBO_BASE_URL.env.local./api/qbo/callback./api/qbo/connect and authorize a sandbox company./api/qbo/company-info to verify the stored token works.GET /api/qbo/connect GET /api/qbo/callback GET /api/qbo/health GET /api/qbo/company-info GET /api/qbo/customers?limit=25&query=Acme GET /api/qbo/invoices?limit=25 GET /api/qbo/accounts?limit=25 GET /api/qbo/accounts/resolve?limit=5&query=Office&classification=Expense GET /api/qbo/items?limit=25&query=Widget GET /api/qbo/mappings GET /api/qbo/payments?limit=25 GET /api/qbo/payment-accounts/resolve?limit=5&query=Amex GET /api/qbo/vendors?limit=25&query=Acme GET /api/qbo/vendors/resolve?limit=5&query=Staples GET /api/qbo/reports/profit-and-loss?startDate=2026-01-01&endDate=2026-03-31 GET /api/qbo/reports/balance-sheet?endDate=2026-03-31 GET /api/qbo/reports/transaction-list?startDate=2026-03-01&endDate=2026-03-31 POST /api/qbo/categorize/dry-run
Policy: prefer native QuickBooks objects for normal bookkeeping. Use vendors and expenses first. Journal entries are available only for exceptions and adjustments.
POST /api/qbo/vendors requires allowWrite=true.POST /api/qbo/expenses creates native QuickBooks Purchase transactions with vendor, payment account, txn date, memo, and expense lines, either from explicit line items or from a reviewed categorization result.GET /api/qbo/accounts/resolve returns compact account candidates ranked by name and fully qualified name for posting-account selection.GET /api/qbo/payment-accounts/resolve narrows account lookup to likely payment accounts for paymentAccountId.POST /api/qbo/journal-entries requires both allowWrite=true and allowJournalEntry=true.GET /api/qbo/mappings exposes the current local mapping config from config/qbo-mappings.json.POST /api/qbo/categorize/dry-run evaluates disconnected account transactions against those rules and returns a proposed treatment without writing anything to QuickBooks.POST /api/qbo/expenses call with allowWrite=true; dry-run alone never posts.GET /api/qbo/vendors/resolve returns compact vendor matches for explicit operator selection before retrying a mapping-driven expense create.paymentAccountName without paymentAccountId, the route returns a structured payment-account-resolution response with candidate payment accounts. It never auto-selects or auto-writes.Keep categorization rules in config/qbo-mappings.json. The format is plain JSON so operators can review and edit it without touching route code.
vendorId is missing but vendorName is present, the expense route returns a structured vendor-resolution response with a search query plus top candidate vendors. It never auto-selects or auto-creates.paymentAccountId is missing but paymentAccountName is present in mapping-driven mode, the expense route returns a structured payment-account-resolution response with a search query plus top candidate payment accounts. It never auto-selects.POST /api/qbo/categorize/dry-run
{
"sourceAccount": { "key": "amex-blue", "name": "Amex Blue Business Card" },
"date": "2026-04-15",
"amount": 72.45,
"direction": "expense",
"description": "Staples store purchase",
"payee": "Staples",
"memo": "office supplies order"
}POST /api/qbo/expenses
{
"allowWrite": true,
"paymentAccountName": "Amex Blue Business Card",
"transaction": {
"sourceAccount": { "key": "amex-blue", "name": "Amex Blue Business Card" },
"date": "2026-04-15",
"amount": 72.45,
"direction": "expense",
"description": "Staples store purchase",
"payee": "Staples",
"memo": "office supplies order"
},
"categorization": {
"proposedTreatment": "expense",
"proposedQboAccountId": "84",
"proposedVendorHint": "staples",
"proposedClassId": "200",
"proposedLocationId": "10"
},
"vendorName": "Staples"
}GET /api/qbo/payment-accounts/resolve?query=Amex&limit=5
{
"ok": true,
"paymentAccounts": [
{
"id": "35",
"name": "Amex Blue Business Card",
"fullyQualifiedName": "Credit Cards:Amex Blue Business Card",
"accountType": "Credit Card",
"accountSubType": "CreditCard",
"classification": "Asset",
"active": true
}
]
}GET /api/qbo/vendors/resolve?query=Staples&limit=5
{
"ok": true,
"vendors": [
{
"id": "58",
"displayName": "Staples",
"companyName": "Staples Inc.",
"primaryEmail": "ap@staples.test",
"active": true
}
]
}POST /api/qbo/vendors
{
"allowWrite": true,
"displayName": "Staples",
"companyName": "Staples Inc.",
"primaryEmail": "ap@staples.test"
}