Node.js
Node.js connects to Syntra through the bundled Syntra ODBC driver using the odbc package — the standard async ODBC client for Node. No extra configuration beyond installing the package: the Syntra installer already registers the driver and a default DSN system-wide.
Prerequisites
Section titled “Prerequisites”- Syntra ODBC installed and running on
localhost:5433(the default). - Node.js 16 or later.
- A C/C++ toolchain if
npm installneeds to compile the native binding. On Windows thewindows-build-toolspackage (or Visual Studio Build Tools) is enough.
Install
Section titled “Install”npm install odbcBasic connection
Section titled “Basic connection”The default System DSN the installer creates is named Syntra QuickBooks:
const odbc = require('odbc');
async function main() { const conn = await odbc.connect('DSN=Syntra QuickBooks');
const rows = await conn.query(` SELECT full_name, balance, phone, email FROM customers WHERE balance > 0 ORDER BY balance DESC `);
console.table(rows); await conn.close();}
main().catch(console.error);If you prefer driver-direct (no DSN), specify every parameter inline:
const conn = await odbc.connect( "Driver={Syntra ODBC - QuickBooks ODBC};" + "Server=127.0.0.1;Port=5433;Database=qbconnect;" + "Uid=qbconnect;Pwd=changeme;");Uid and Pwd come from the [auth] section of config.toml. Installer defaults are qbconnect / changeme — change them in production.
Connection pooling
Section titled “Connection pooling”For any app that serves more than one request at a time, use a pool. The odbc package has a built-in pool:
const odbc = require('odbc');
const pool = await odbc.pool({ connectionString: 'DSN=Syntra QuickBooks', initialSize: 2, maxSize: 10, incrementSize: 1,});
async function getOpenInvoices() { const rows = await pool.query(` SELECT ref_number, customer_ref_full_name, txn_date, balance_remaining FROM invoices WHERE is_paid = false ORDER BY txn_date DESC LIMIT 100 `); return rows;}Parameterized queries
Section titled “Parameterized queries”Always parameterise. The odbc package uses ? placeholders:
const rows = await pool.query( 'SELECT list_id, full_name FROM customers WHERE balance > ? AND is_active = true', [1000]);Forcing a live query (bypass cache)
Section titled “Forcing a live query (bypass cache)”The local cache answers most SELECTs. To pull a fresh read straight from QuickBooks, set QB_MAX_STALENESS on the session before running the query:
await conn.query('SET QB_MAX_STALENESS = 0');const rows = await conn.query('SELECT * FROM customers WHERE list_id = ?', ['80000001-1234567890']);The setting applies for the lifetime of that connection (or pool member).
Writing data
Section titled “Writing data”Write operations are included on Standard and Pro. INSERT / UPDATE / DELETE go straight to QuickBooks:
await conn.query( `INSERT INTO customers (name, phone, email) VALUES (?, ?, ?)`,);Multi-line transactions (one invoice with N lines) use the grouped multi-row VALUES pattern. See INSERT / UPDATE / DELETE for full coverage including shared-line parents (bills with item vs expense lines), journal entries, and LinkToTxn for bill-from-sales-order flows.
Using with Express
Section titled “Using with Express”const express = require('express');const odbc = require('odbc');
const app = express();let pool;
(async () => { pool = await odbc.pool({ connectionString: 'DSN=Syntra QuickBooks', maxSize: 10, });})();
app.get('/api/customers', async (req, res) => { try { const rows = await pool.query( 'SELECT full_name, balance, phone, email FROM customers ORDER BY full_name' ); res.json(rows); } catch (err) { console.error(err); res.status(500).json({ error: 'Database query failed' }); }});
app.listen(3000, () => console.log('Server running on port 3000'));- Always pool. Opening a fresh ODBC connection per request adds hundreds of milliseconds.
- Streaming large results.
conn.querybuffers the whole result set. For million-row scans useconn.createStatement()+statement.executeand process rows incrementally. - TypeScript. The
odbcpackage ships its own types;import odbc from 'odbc'gets youodbc.Pool,odbc.Connection, etc. - Timeouts. Append
;Timeout=10to fail fast on connection. Per-query timeouts aren’t on the connection string — use the statement-levelStatementAttributesAPI. - Custom fields surface as
custom_*columns. See Custom Fields.